この記事ではLaravelのリレーションメソッドと動的プロパティの違いを整理してみようと思います。
自分が初めの頃全く理解ができなかったので初学者の方の参考になれば幸いです。
具体的には「$user->posts」と「$user->posts()」の違いにどんなものがあるか紹介していきます。
この記事を読むメリット
- 「$user->posts」と「$user->posts()」の違いが理解できる
- リレーションの扱いで困ることが減る
「$user->posts」と「$user->posts()」で返り値が異なる
まずはこの2つの返り値の違いを整理したいと思います。
$userと$postの関係は1対多の関係です。
User.phpの中で以下のようなリレーション関係を定義しています。
// Postモデルとのリレーション
public function posts()
{
return $this->hasMany(Post::class);
}
1つのユーザーが多くの投稿を持つことができる状態です。
この時に1ユーザーが持っている複数の投稿を取得する際に上記の2つの選択肢があります。
それぞれどのような違いがあるか確認してみます。
$user->postsの返り値:()なしの場合(動的プロパティ)
まずは動的プロパティである$user->postsの返り値がどんなものか確認してみます。
public function getPosts()
{
$user = User::find(1);
dd($user->posts);
}
IDが1のユーザーが持っている投稿を取得しています。
dd($user->posts)で確認します。
中身は以下のようになります。
Illuminate\Database\Eloquent\Collection {#1297 ▼
#items: array:3 [▼
0 => App\Models\Post {#1300 ▶}
1 => App\Models\Post {#1301 ▶}
2 => App\Models\Post {#1302 ▶}
]
#escapeWhenCastingToString: false
}
返り値は「Illuminate\Database\Eloquent\Collection」になっています。
その中に各投稿のPostモデルオブジェクトが格納されています。
$user->postsの返り値はCollectionクラスであることがわかりました。
エンジニアにおすすめ書籍
エンジニアになりたて、これから勉強を深めていきたいという方におすすめの書籍はこちら!
$user->posts()の返り値:()ありの場合(リレーションメソッド)
ではリレーションメソッドと呼ばれる$user->posts()はどうでしょうか。
getPosts()の内容を少し変更して確認してみます。
public function getPosts()
{
$user = User::find(1);
dd($user->posts());
}
中身は以下のようになります。
Illuminate\Database\Eloquent\Relations\HasMany {#1081 ▼
#query: Illuminate\Database\Eloquent\Builder {#328 ▶}
#parent: App\Models\User {#672 ▶}
#related: App\Models\Post {#321 ▶}
#foreignKey: "posts.user_id"
#localKey: "id"
}
先ほどとは異なり「Illuminate\Database\Eloquent\Relations\HasMany」になっていることがわかります。
$user->posts()の返り値はHasManyオブジェクトになります。
つまり、Eloquentのリレーションオブジェクトの1つということになります。
$user->posts()はクエリビルダとしても機能する
$user->posts()の返り値であるリレーションオブジェクトの特徴として、クエリビルダとしても機能することが挙げられます。
例えば以下のようにすることができます。
public function getPosts()
{
$user = User::find(1);
dd($user->posts()->where('id', 1));
}
「->where(‘id’, 1)」として投稿にも制約を追加することができます。
「$user->posts」に同じようにwhere句をつけるとエラーが出ます。
返り値がリレーションオブジェクトである「$user->posts()」がクエリビルダとして制約を加えることができます。
リレーションメソッドと動的プロパティを適切に使い分ける
これまでのことをまとめると以下のようになります。
- ()なしの動的プロパティの返り値はコレクションクラス
- ()ありのリレーションメソッドの返り値はHasManyオブジェクト
- リレーションメソッドの場合はwhere句などで追加制約が可能
この2つのデータ取得の使い分けは、取得時の要件によるかなと思います。
リレーション先の全てのデータを取得したい場合は()なしの動的プロパティが適切になります。
取得後も何か制約を加える可能性がある場合は()ありのリレーションメソッドを使用した方が良いです。
適切な方を選択できるように整理しておくと良いかと思います。