Eloquentのリレーション活用方法【関連の取得】

Eloquentのリレーションメソッドを活用して、紐付くモデルを取得する方法について解説します。
リレーションメソッドを活用することで、少ない処理で目的のデータを取得できるようになります。

実際に実行されるSQLを載せています。どういった動作が行われるのか理解するのに役立つと思います。

なお、Eloquentのリレーションについて以下3回に渡って解説しています。他の記事も参考にしてください。

動作確認に利用したリポジトリです。
https://github.com/raku-raku/laravel_eloquent_practice

「関連モデル」を取得

動的プロパティで取得

動的プロパティで「関連モデル」を取得できます。

動的プロパティは __getマジックメソッド で実装されています。 Illuminate\Database\Eloquent\Model__getマジックメソッド 経由で各リレーションクラスの getResultsメソッド が呼ばれます。

>>> User::find(1)->phone
=> App\Models\Phone {#2939
     id: 1,
     user_id: 1,
     tel: "072-038-7531",
     created_at: "2018-11-15 06:38:14",
     updated_at: "2018-11-15 06:38:14",
   }

リレーションメソッドで取得

関連モデルを絞り込んで取得したい場合、メソッドとしてアクセスします。
メソッドとしてアクセスすると、条件絞り込みのメソッドを繋げることができます。

>>> User::find(1)->posts()->where('title', 'LIKE', '%この%')->toSql()
=> "select * 
    from `posts` 
    where `posts`.`user_id` = ? 
    and `posts`.`user_id` is not null 
    and `title` LIKE ?"
>>>
>>> User::find(1)->posts()->where('title', 'LIKE', '%この%')->get();
=> Illuminate\Database\Eloquent\Collection {#2963
     all: [
       App\Models\Post {#2926
         id: 6,
         user_id: 1,
         title: "手の方で、このそこですからだ。",
         body: "やの中はもう一つの方たいくほんとうの鼠ねずみいろの霧きりして誰だれから一生けん命めいめんの柱はしの前に女たちの流ながら答えましく立派りっぱいにあかり天の川の中でのでしたりしているだろう。こいつも窓まどかってるんです。その大きな橋はしばらく、船に乗",
         created_at: "2018-11-15 06:38:14",
         updated_at: "2018-11-15 06:38:14",
       },
     ],
   }

中間テーブルのカラム取得

中間テーブルのカラムは pivot 経由でアクセスできます。

>>> User::find(1)->roles()->first()
=> App\Models\Role {#2928
     id: 1,
     role: "管理者",
     created_at: "2018-11-15 06:38:14",
     updated_at: "2018-11-15 06:38:14",
     pivot: Illuminate\Database\Eloquent\Relations\Pivot {#2976
       user_id: 1,
       role_id: 1,
       column1: "King. 'It began with the Gryphon. 'Then, you.",
       column2: "So she swallowed one of the trees upon her knee.",
       created_at: "2018-11-15 06:38:14",
       updated_at: "2018-11-15 06:38:14",
     },
   }
>>> 
>>> User::find(1)->roles()->first()->pivot->column1
=> "King. 'It began with the Gryphon. 'Then, you."

「自モデル」を取得

関連が存在する自モデル

hasメソッド を利用すると、「関連モデル」が存在する「自モデル」を取得できます。
doesntHaveメソッド を利用すると、「関連モデル」が存在しない「自モデル」を取得できます。

>>> User::has('posts')->toSql()
=> "select * 
    from `users` 
    where exists (select * 
                  from `posts` 
                  where `users`.`id` = `posts`.`user_id`)"
>>> 
>>> User::doesntHave('posts')->toSql()
=> "select * 
    from `users` 
    where not exists (select * 
                      from `posts` 
                      where `users`.`id` = `posts`.`user_id`)"
>>> 
>>> User::has('posts')->pluck('name')
=> Illuminate\Support\Collection {#2967
     all: [
       "山岸 くみ子",
       "山本 直人",
       "山口 里佳",
     ],
   }

関連が特定条件で存在する自モデル

追加条件をつけたい場合、 whereHasメソッド whereDoesntHaveメソッド を利用します。

>>> Post::whereHas('comments', function ($query) {
...     $query->where('content', 'like', 'foo%');
... })->toSql()
=> "select * 
    from `posts` 
    where exists (select * 
                  from `comments` 
                  where `posts`.`id` = `comments`.`commentable_id` 
                  and `comments`.`commentable_type` = ? 
                  and `content` like ?)"

「関連モデル」の総数を取得

withCountメソッド を利用すると「関連モデル」の総数も取得されます。

>>> User::withCount('posts')->toSql()
=> "select `users`.*, 
           (select count(*) from `posts` where `users`.`id` = `posts`.`user_id`) as `posts_count` 
    from `users`"
>>> 
>>> User::withCount('posts')->first()
=> App\Models\User {#2999
     id: 1,
     name: "山岸 くみ子",
     country_id: 5,
     created_at: "2018-11-15 06:38:14",
     updated_at: "2018-11-15 06:38:14",
     posts_count: 4,
   }

上記例では、 posts_count に総数が設定されています。

「関連モデル」をEagerローディング

N+1クエリ問題 の対策として、Eagerローディングする方法を確認します。

withでEagerロード

User::with('posts')->get();
select * from `users`
select * from `posts` where `posts`.`user_id` in ('1', '2', '3')

loadでEagerロード

$users = User::get();
if ($condition) {
    $users->load('posts');
}
select * from `users`
select * from `posts` where `posts`.`user_id` in ('1', '2', '3')

条件ごとに、Eagerロードするリレーションを変更したいケースなどに有効です。

ネストしたEagerロード

Country::with('users.posts')->get();
select * from `countries`
select * from `users` where `users`.`country_id` in ('1', '2', '3', '4', '5', '6', '7', '8', '9', '10')
select * from `posts` where `posts`.`user_id` in ('1', '2', '3')

複数リレーションをEagerロード

User::with(['posts', 'videos'])->get();
select * from `users`
select * from `posts` where `posts`.`user_id` in ('1', '2', '3')
select * from `videos` where `videos`.`user_id` in ('1', '2', '3')

特定条件をつけてEagerロード

User::with(['posts' => function ($query) {
    $query->where('title', 'like', '%first%');
}])->get();
select * from `users`
select * from `posts` where `posts`.`user_id` in ('1', '2', '3') and `title` like '%first%'
【エンジニア向け】仕事を見つける方法

転職する

転職エージェントを活用する

転職サイトの場合、自身でサイト上から企業を探す必要があります。 一方「レバテックキャリア」 などの転職エージェントの場合、エージェントが企業を紹介してくれます。エージェントが間に入ることにより、日程調整や、条件交渉などもサポートしてくれます。

転職ドラフトを活用する

転職ドラフト」は、 企業がITエンジニアをドラフトという形で指名するサービスです。年収が最初に提示されるなどのメリットがあります。 ただ、初回登録時にレジュメ作成が必要で、すでにエンジニア経験が豊富にあるエンジニア向けのサービスかと思います。 レジュメ作成が手間ですが、自身のキャリアを見直す機会になり、他の仕事探しにも役立つはずです。

エンジニア転職保証のあるスクールを活用する

ある程度、開発経験のあるかたであれば、独学で必要なスキルを身につけることができるはずです。ただ、別業種からエンジニアに転職したい場合など、1から独学で学ぶのはハードルが高いです。そういった方は、スクールの活用を検討しても良いと思います。 「TechAcademy」は、エンジニア転職保証コースを提供しています。給付金制度の対象講座として認定されているため、金銭面の負担も抑えることができます。

フリーランスとして活動する

レバテックフリーランス」「ITプロパートナーズ」「ギークスジョブ」は、フリーランスエージェントサービスです。 エージェントによって、支払いサイトなど細かい違いはありますが、まずは良い案件を見つけることが重要です。 登録自体は無料なので、複数エージェントに登録して、より多くの案件を紹介してもらうのがおすすめです。

logo
わくわくBank.
技術系の記事を中心に、役に立つと思ったこと、整理したい情報などを掲載しています。