#概要
他のテーブルとリレーションを結ぶuser( )などのリレーションメソッド。
user( )と使う場面と単にuserとして使う場面もある。
なんとなくで使っていたがここらでスッキリさせておくために、今回は
この2つの違いについて自分なりにまとめておく。
#リレーションメソッド
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* ユーザーの全ポストの取得
*/
public function posts()
{
return $this->hasMany('App\Post');
}
}
[表題ではuserで書いたが書きにくかったのでpostで書いてます]
これはUserモデルとposts()という1対多のリレーションメソッドですね。
あるユーザーの持つPostを取得したいときは以下のようなコードになるでしょう。
idが1のUserの全Postを取得
$user = App\User::find(1);
$posts = $user->posts;
さてこの$posts
に入っているのはなんでしょうか?
posts()
で定義しているのに$user->posts
と( )がついていません。
この$posts
に入っているのはPostモデルのインスタンスのコレクションです。
posts()の中身はこうでした。
return $this->hasMany('App\Post')
ですので$this->hasMany('App\Post')
を返していることは確実です。
では、この$this->hasMany('App\Post')
がコレクションを返しているのか?
そうではなくてこれはHasMany オブジェクトというものを返しています。
$user->posts
ここで動的プロパティというものを呼び出しているんですね。
#動的プロパティ
プロパティってのは何かの性質、特徴を表すものですから。
それが動的ってことはなんらかの原因によって性質が変わるものってことでしょうか?
調べたところ
インスタンスのプロパティには attributes と呼ばれる各レコードのカラムの値の他に、relations というものもあって、その中身には定義したリレーションメソッド名を key、リレーションメソッドの制約に従って取得したリレーション先のモデルインスタンスのコレクションを value とした連想配列が入っているそうです。
ここのrelations 内の値は定義されたリレーションメソッドやリレーション先のテーブル内容によって動的に変わるので、動的プロパティと呼ばれているということですね!なるほど!
#()がつくと?
先ほどの動的プロパティを使わずに有効な全 Post を取得するコードを書いてみましょう。
$user = App\User::find(1);
$posts = $user->posts()->where('active', 1)->get();
ここではposts()
としてからwhereで一致するものを探してからget()で取得しています。
こちらの$user->posts()の時点では、return $this->hasMany('App\Post')
の結果の
HasMany オブジェクトが返ってきています。
HasMany オブジェクトを考えるために、
HasMany の基底クラスである HasOneOrMany の実装を見てみましょう。
*略
public function create(array $attributes = [])
{
return tap($this->related->newInstance($attributes), function ($instance) {
$this->setForeignAttributesForCreate($instance);
$instance->save();
});
}
$this->related
にPostモデルの仮のインスタンスが入っていて、newInstance($attributes)
で意味のあるモデルインスタンスを生成しています。
そしてsetForeignAttributesForCreate()
で外部キーがセットされてそのままそのモデルをsaveしているんですね。
なので今回の場合は$user->posts() で user_id が埋められた状態になっててそれをwhereで一致したものをget()しているということです。
#2つの違い
だったら記述の少ない動的プロパティだけで良いじゃんってことになりますが、HasMany オブジェクトなどの Eloquent リレーションオブジェクトはクエリビルダとしても動作するという大きな特徴があります。
クエリビルダは Laravel で SQL の記法を書きやすくするもので、where('active', 1)といった記法をメソッドチェーン的に繋げられます。
コレクションが返ってくる動的プロパティではそのまま繋げられないが、Eloquent リレーションオブジェクトであればそのまま繋げて制約を追加することが可能ということですね。
反対に、動的プロパティは「遅延ロード」されるという性質を持っています。
遅延ロードとは、アクセスされたときにだけリレーションのデータをロードするというもので、このため、あらかじめアクセスしておいて EagerLoadができるのです。
#まとめ
1.posts()などの()がつくものはリレーションメソッド postsは動的プロパティである。
**2.動的プロパティpostsでUserモデルのコレクションが返ってきている。
3.リレーションメソッドposts()の時点では結びつけているもの(今回だとuser_id--テーブル書くの省略していますが笑--)が返ってきてそれをクエリビルダでメソッドチェーン的につなげられる!。
ということになるかと思います!
しかしこれ頻出すると思うのですが記事がかなり少ない。。。
慣れたら感覚で使いこなせるのかな?
何かありましたらコメントお願いします!