Laravelでユーザー認証紐づいたテーブルの取得コードとSQL

#概要
特定のユーザーの情報とともに、そのユーザーに紐づく本の情報を取得する方法を色々試してみました。
フレームワークだとかモデルでのデータベース操作に関してはLaravelが初めてですので、間違っている点があればコメント欄でバンバン指摘待ってます。


#実装
##前提
今回はLaravelの標準で用意されているUserモデルに、追加で実装したBookモデルを関連づけています。
Userモデルのidに、Bookモデルのuser_idが外部キーとして紐づいています。
最終的な出力結果として、ユーザー情報の中に、紐づいている本の情報が内包しているような形を目指しました。

##準備
まずBookテーブルの作成です。

```php:create_book_table.php(一部)

class CreateBookTable extends Migration
{
    public function up()
    {
        Schema::create('book', function (Blueprint $table) {
			$table->increments('id'); // 本ID
			$table->integer('user_id')->unsigned(); // 登録者ID
			$table->foreign('user_id')->references('id')->on('users'); // 紐付け
			$table->string('name'); // 本の名前
			$table->timestamps(); // 登録、更新日時
			$table->softDeletes(); // ソフトデリート
        });
    }
}

```

次にUserモデルとBookモデルに、1対nのリレーションを追加しておきます。

```php:User.php(一部)
class User extends Model implements AuthenticatableContract,
                                    AuthorizableContract,
                                    CanResetPasswordContract
{
    public function book()
    {
        return $this->hasMany('App\Book');
    }
}
```

```php:Book.php(一部)
class Book extends Model
{
    protected $table = 'book';

    public function user()
    {
        return $this->belongsTo('App\User');
    }

}
```
テーブル内のサンプルデータです。

```text:サンプル
usersテーブル
+----+---------------+-------------------+---------------------+---------------------+
| id | name          | email             | created_at          | updated_at          |
+----+---------------+-------------------+---------------------+---------------------+
|  1 | ユーザー1      | user1@example.com | 2015-09-21 22:35:20 | 2015-09-21 22:35:20 |
+----+---------------+-------------------+---------------------+---------------------+

bookテーブル
+----+---------+----------------------+---------------------+---------------------+------------+
| id | user_id | name                 | created_at          | updated_at          | deleted_at |
+----+---------+----------------------+---------------------+---------------------+------------+
|  1 |       1 | ユーザー1の本1         | 2015-09-21 22:35:41 | 2015-09-21 22:35:41 | NULL       |
|  2 |       1 | ユーザー1の本2         | 2015-09-21 22:35:56 | 2015-09-21 22:35:56 | NULL       |
+----+---------+----------------------+---------------------+---------------------+------------+
```


実行したSQLを確認するためのコードの追加と、事前にログインしているユーザーIDを取得しておきます。

```php:事前準備
DB::listen(function ($sql, $bind) {
	var_dump($sql);
	var_dump($bind);
});
$user_id = Auth::id();

// 上記のSQL
string 'select * from `users` where `users`.`id` = ? limit 1' (length=52)
array (size=1)
  0 => int 1
```

##各取得コード、結果
色々な取得の形を試すために下記の5つのコードを用意しました。

```php:各コード
$test1 = User::with('book')
	->find($user_id)
	->toArray();

$test2 = Auth::user()
	->with('book')
	->find($user_id)
	->toArray();

$test3 = User::where('id', $user_id)
	->first()
	->book
	->toArray();

$test4 = User::find($user_id)
	->book
	->toArray();

$test5 = User::find($user_id)
	->book()
	->with('user')
	->join('users', 'users.id', '=', 'book.user_id')
	->get(['users.*', 'book.*'])
	->toArray();

```
それぞれ、コード、発行されるSQL、取得した配列のvar_dumpでの出力結果です。
###テスト1
私がやってみた限り一番これが短く簡単で、ユーザーの情報の中に、関連づいている本の情報が内包する正しい形で取得できています。
SQLも悪くないのではないでしょうか。

```php:テスト1
$test1 = User::with('book')
	->find($user_id)
	->toArray();

// SQL
string 'select * from `users` where `users`.`id` = ? limit 1' (length=52)
array (size=1)
  0 => int 1
string 'select * from `book` where `book`.`deleted_at` is null and `book`.`user_id` in (?)' (length=82)
array (size=1)
  0 => int 1

// 出力結果
array (size=6)
  'id' => int 1
  'name' => string 'ユーザー1' (length=13)
  'email' => string 'user1@example.com' (length=17)
  'created_at' => string '2015-09-21 22:35:20' (length=19)
  'updated_at' => string '2015-09-21 22:35:20' (length=19)
  'book' => 
    array (size=2)
      0 => 
        array (size=6)
          'id' => int 1
          'user_id' => int 1
          'name' => string 'ユーザー1の本1' (length=20)
          'created_at' => string '2015-09-21 22:35:41' (length=19)
          'updated_at' => string '2015-09-21 22:35:41' (length=19)
          'deleted_at' => null
      1 => 
        array (size=6)
          'id' => int 2
          'user_id' => int 1
          'name' => string 'ユーザー1の本2' (length=20)
          'created_at' => string '2015-09-21 22:35:56' (length=19)
          'updated_at' => string '2015-09-21 22:35:56' (length=19)
          'deleted_at' => null
```
###テスト2
テスト1と最初のUserクラスかAuth::user()で取得するかの違いのみです。

```php:テスト2
$test2 = Auth::user()
	->with('book')
	->find($user_id)
	->toArray();

// SQL
string 'select * from `users` where `users`.`id` = ? limit 1' (length=52)
array (size=1)
  0 => int 1
string 'select * from `book` where `book`.`deleted_at` is null and `book`.`user_id` in (?)' (length=82)
array (size=1)
  0 => int 1

// 出力結果
array (size=6)
  'id' => int 1
  'name' => string 'ユーザー1' (length=13)
  'email' => string 'user1@example.com' (length=17)
  'created_at' => string '2015-09-21 22:35:20' (length=19)
  'updated_at' => string '2015-09-21 22:35:20' (length=19)
  'book' => 
    array (size=2)
      0 => 
        array (size=6)
          'id' => int 1
          'user_id' => int 1
          'name' => string 'ユーザー1の本1' (length=20)
          'created_at' => string '2015-09-21 22:35:41' (length=19)
          'updated_at' => string '2015-09-21 22:35:41' (length=19)
          'deleted_at' => null
      1 => 
        array (size=6)
          'id' => int 2
          'user_id' => int 1
          'name' => string 'ユーザー1の本2' (length=20)
          'created_at' => string '2015-09-21 22:35:56' (length=19)
          'updated_at' => string '2015-09-21 22:35:56' (length=19)
          'deleted_at' => null
```
###テスト3
Userモデルにwhereでログイン中のIDで絞り込んでいます。
関連する本を取得は出来るのですが、このままでは$test3にはユーザー情報が格納されませんね。
一度分割して別の変数に入れたり、配列に両方格納するといった方法ならユーザーと本の情報を保持はできますが、紐付けが面倒になりますね。

```php:テスト3
$test3 = User::where('id', $user_id)
	->first()
	->book
	->toArray();

// SQL
string 'select * from `users` where `id` = ? limit 1' (length=44)
array (size=1)
  0 => int 1
string 'select * from `book` where `book`.`deleted_at` is null and `book`.`user_id` = ? and `book`.`user_id` is not null' (length=112)
array (size=1)
  0 => int 1

// 出力結果
array (size=2)
  0 => 
    array (size=6)
      'id' => int 1
      'user_id' => int 1
      'name' => string 'ユーザー1の本1' (length=20)
      'created_at' => string '2015-09-21 22:35:41' (length=19)
      'updated_at' => string '2015-09-21 22:35:41' (length=19)
      'deleted_at' => null
  1 => 
    array (size=6)
      'id' => int 2
      'user_id' => int 1
      'name' => string 'ユーザー1の本2' (length=20)
      'created_at' => string '2015-09-21 22:35:56' (length=19)
      'updated_at' => string '2015-09-21 22:35:56' (length=19)
      'deleted_at' => null

```
###テスト
これもテスト3と同じような感じですね。

```php:テスト4
$test4 = User::find($user_id)
	->book
	->toArray();

// SQL
string 'select * from `users` where `users`.`id` = ? limit 1' (length=52)
array (size=1)
  0 => int 1
string 'select * from `book` where `book`.`deleted_at` is null and `book`.`user_id` = ? and `book`.`user_id` is not null' (length=112)
array (size=1)
  0 => int 1

// 出力結果
array (size=2)
  0 => 
    array (size=6)
      'id' => int 1
      'user_id' => int 1
      'name' => string 'ユーザー1の本1' (length=20)
      'created_at' => string '2015-09-21 22:35:41' (length=19)
      'updated_at' => string '2015-09-21 22:35:41' (length=19)
      'deleted_at' => null
  1 => 
    array (size=6)
      'id' => int 2
      'user_id' => int 1
      'name' => string 'ユーザー1の本2' (length=20)
      'created_at' => string '2015-09-21 22:35:56' (length=19)
      'updated_at' => string '2015-09-21 22:35:56' (length=19)
      'deleted_at' => null
```
###テスト5
joinを書いています。
本にユーザー情報が関連づいている形になっていますね。
ユーザーと本は1対nになっているのでこれでは逆で何度も同じユーザー情報を本情報に格納する形になってしまい、良くないですね。


```php:テスト5
$test5 = User::find($user_id)
	->book()
	->with('user')
	->join('users', 'users.id', '=', 'book.user_id')
	->get(['users.*', 'book.*'])
	->toArray();

// SQL
string 'select * from `users` where `users`.`id` = ? limit 1' (length=52)
array (size=1)
  0 => int 1
string 'select `users`.*, `book`.* from `book` inner join `users` on `users`.`id` = `book`.`user_id` where `book`.`deleted_at` is null and `book`.`user_id` = ? and `book`.`user_id` is not null' (length=184)
array (size=1)
  0 => int 1
string 'select * from `users` where `users`.`id` in (?)' (length=47)
array (size=1)
  0 => int 1

// 出力結果
array (size=2)
  0 => 
    array (size=10)
      'id' => int 1
      'name' => string 'ユーザー1の本1' (length=20)
      'email' => string 'user1@example.com' (length=17)
      'password' => string '*********' (length=*)
      'remember_token' => null
      'created_at' => string '2015-09-21 22:35:41' (length=19)
      'updated_at' => string '2015-09-21 22:35:41' (length=19)
      'user_id' => int 1
      'deleted_at' => null
      'user' => 
        array (size=5)
          'id' => int 1
          'name' => string 'ユーザー1' (length=13)
          'email' => string 'user1@example.com' (length=17)
          'created_at' => string '2015-09-21 22:35:20' (length=19)
          'updated_at' => string '2015-09-21 22:35:20' (length=19)
  1 => 
    array (size=10)
      'id' => int 2
      'name' => string 'ユーザー1の本2' (length=20)
      'email' => string 'user1@example.com' (length=17)
      'password' => string '*********' (length=*)
      'remember_token' => null
      'created_at' => string '2015-09-21 22:35:56' (length=19)
      'updated_at' => string '2015-09-21 22:35:56' (length=19)
      'user_id' => int 1
      'deleted_at' => null
      'user' => 
        array (size=5)
          'id' => int 1
          'name' => string 'ユーザー1' (length=13)
          'email' => string 'user1@example.com' (length=17)
          'created_at' => string '2015-09-21 22:35:20' (length=19)
          'updated_at' => string '2015-09-21 22:35:20' (length=19)
```

#終えて
まだメソッドチェーンでクエリを作っていくのには抵抗がありますが色んなメソッドがあって面白いです。
今回は出力を分かりやすいようにtoArray()を行っていますが、実コードでは下記のように扱っていくのかなと思います。

```php:テスト1の場合
$test1 = User::with('book')
	->find($user_id);

echo "<p>登録者：" . $test1->name . "</p>";

foreach($test1->book as $book) {
	echo "<p>本の名前：" . $book->name . "</p>";
}
```