🔍
【Laravel】リレーション先のリレーション先のデータを取得する2つの方法
はじめに
一例として、「あるユーザーが投稿した記事のカテゴリーの名前を取得したい」というケースを考えます。
データベース構造
記事用なので簡易的に書きます。
ユーザーテーブル(users)
カラム名 | データ内容 | FK |
---|---|---|
id | ID | |
name | 名前 | |
メールアドレス |
記事テーブル(articles)
カラム名 | データ内容 | FK |
---|---|---|
id | ID | |
user_id | 投稿ユーザーID | ◯ |
category_id | カテゴリーID | ◯ |
tile | 記事タイトル | |
body | 記事の内容 |
カテゴリーテーブル(categories)
カラム名 | データ内容 | FK |
---|---|---|
id | ID | |
name | 名前 |
モデルファイル
Laravel8だとapp/Models/◯◯.php
ユーザーモデル
実際には現実的ではないですが、説明を簡略化するためにユーザーは1つの記事しか投稿できない(=ユーザーと記事が1対1の関係)前提とします。
User.php
public function article()
{
return $this->belongsTo(Article::class);
}
記事モデル
Article.php
public function category()
{
return $this->belongsTo(Category::class);
}
リレーション先のリレーション先のデータを取得する2つの方法
ドット(.)で繋ぐ
モデルインスタンスを取得する際にwith()
の中でリレーションメソッドをドット(.
)繋ぎ(=文字列の連結)で記載する。(with()
はN+1問題対策用)
SampleService.php
$user = User::with(['article.category'])->first();
// ユーザーが投稿した記事のカテゴリー名を取得
$user->article->category->name
Laravelではドット繋ぎで1つ先の階層にアクセス記法がいろいろなところで使われています。
上記記事のようにセッションデータとか設定内容(config
ファイル)とか。
クロージャを使う
with()
の中でクロージャを使う。
SampleService.php
$user = User::with(['article' => function ($query) {
$query->with(['category'])
}])->first();
// ユーザーが投稿した記事のカテゴリー名を取得
$user->article->category->name
最後に
クロージャを使った方法はリレーション先で検索することができるみたい(実際に試してない)なので、
単純にリレーション先のリレーション先のデータを取得したい場合は、ドット(.
)を使う方法の方がコード量も少なく見た目もスッキリして良いかなと思いました。
Discussion