LoginSignup
1
0

More than 1 year has passed since last update.

Laravel user()とuserの違い 動的プロパティ リレーションメソッド

Last updated at Posted at 2021-06-07

概要

他のテーブルとリレーションを結ぶuser( )などのリレーションメソッド。
user( )と使う場面と単にuserとして使う場面もある。
なんとなくで使っていたがここらでスッキリさせておくために、今回は
この2つの違いについて自分なりにまとめておく。

リレーションメソッド

User.php
<?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--テーブル書くの省略していますが笑--)が返ってきてそれをクエリビルダでメソッドチェーン的につなげられる!。

ということになるかと思います!

しかしこれ頻出すると思うのですが記事がかなり少ない。。。
慣れたら感覚で使いこなせるのかな?

何かありましたらコメントお願いします!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0