🔍

【Laravel】リレーション先のリレーション先のデータを取得する2つの方法

2021/12/01に公開

はじめに

一例として、「あるユーザーが投稿した記事のカテゴリーの名前を取得したい」というケースを考えます。

データベース構造

記事用なので簡易的に書きます。

ユーザーテーブル(users)

カラム名 データ内容 FK
id ID
name 名前
email メールアドレス

記事テーブル(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つ先の階層にアクセス記法がいろいろなところで使われています。

https://zenn.dev/shimotaroo/articles/f88bacd13c01da

上記記事のようにセッションデータとか設定内容(configファイル)とか。

クロージャを使う

with()の中でクロージャを使う。

SampleService.php
$user = User::with(['article' => function ($query) {
    $query->with(['category'])
}])->first();

// ユーザーが投稿した記事のカテゴリー名を取得
$user->article->category->name

最後に

クロージャを使った方法はリレーション先で検索することができるみたい(実際に試してない)なので、
単純にリレーション先のリレーション先のデータを取得したい場合は、ドット(.)を使う方法の方がコード量も少なく見た目もスッキリして良いかなと思いました。

Discussion