0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Laravel】1対多リレーションのコードリーディング

0
Posted at

以下のレコード、コードで実行します。

userテーブル
+----+--------+
| id | name   |
+----+--------+
|  1 | admin  |
|  2 | user01 |
+----+--------+

email、email_verified_at、password、remember_token、created_at、updated_atカラムは省略します。

postsテーブル
+----+--------+-------+---------------------+---------------------+---------+
| id | title  | body  | created_at          | updated_at          | user_id |
+----+--------+-------+---------------------+---------------------+---------+
|  1 | title1 | body1 | 2019-04-19 03:33:35 | 2019-04-20 02:10:58 |       1 |
|  2 | title2 | body2 | 2019-04-19 03:33:35 | 2019-04-20 02:10:58 |       1 |
|  3 | title3 | body3 | 2019-04-19 03:33:35 | 2019-04-20 02:10:58 |       1 |
|  4 | title4 | body4 | 2019-04-19 03:33:35 | 2019-04-19 03:33:35 |       2 |
|  5 | title5 | body5 | 2019-04-19 03:33:35 | 2019-04-19 03:33:35 |       2 |
+----+--------+-------+---------------------+---------------------+---------+
app/User.php
<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function posts()
    {
        /**
         * @return \Illuminate\Database\Eloquent\Relations\HasMany
         */
        return $this->hasMany('App\Post')->latest();
    }
}
app/Post.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}
<?php
use App\User;

$admin_user = User::find(1);

foreach($admin_user->posts as $post) {
    echo "title: $post->title\n";
    echo "body: $post->body\n";
}

/*
title: title1
body: body1
title: title2
body: body2
title: title3
body: body3
*/

User::find(1)はusersテーブルのid = 1のデータを入れた、Userオブジェクトを返します。

$admin_user->postsuser_id = 1のデータを入れた、Postオブジェクトを入れた、
Illuminate\Database\Eloquent\Collectionオブジェクトを返します。

Userオブジェクトはpostsプロパティを持っていないので__get()メソッドが呼ばれます。

Illuminate/Database/Eloquent/Model.php
/**
 * Dynamically retrieve attributes on the model.
 *
 * @param  string  $key
 * @return mixed
 */
public function __get($key)
{
    return $this->getAttribute($key);
}
/**
 * Get an attribute from the model.
 *
 * @param  string  $key
 * @return mixed
 */
public function getAttribute($key)
{
    if (! $key) {
        return;
    }

    // If the attribute exists in the attribute array or has a "get" mutator we will
    // get the attribute's value. Otherwise, we will proceed as if the developers
    // are asking for a relationship's value. This covers both types of values.
    if (array_key_exists($key, $this->attributes) ||
        $this->hasGetMutator($key)) {
        return $this->getAttributeValue($key);
    }

    // Here we will determine if the model base class itself contains this given key
    // since we don't want to treat any of those methods as relationships because
    // they are all intended as helper methods and none of these are relations.
    if (method_exists(self::class, $key)) {
        return;
    }

    return $this->getRelationValue($key);
}

$this->attributespostsはありません。
selfはModelクラスなので、postsは定義されていません。
よって、$this->getRelationValue('posts')を返します。

Illuminate/Database/Eloquent/Concerns/HasAttributes.php
/**
 * Get a relationship.
 *
 * @param  string  $key
 * @return mixed
 */
public function getRelationValue($key)
{
    // If the key already exists in the relationships array, it just means the
    // relationship has already been loaded, so we'll just return it out of
    // here because there is no need to query within the relations twice.
    if ($this->relationLoaded($key)) {
        return $this->relations[$key];
    }

    // If the "attribute" exists as a method on the model, we will just assume
    // it is a relationship and will load and return results from the query
    // and hydrate the relationship's value on the "relationships" array.
    if (method_exists($this, $key)) {
        return $this->getRelationshipFromMethod($key);
    }
}
Illuminate/Database/Eloquent/Concerns/HasRelationships.php
/**
 * Determine if the given relation is loaded.
 *
 * @param  string  $key
 * @return bool
 */
public function relationLoaded($key)
{
    return array_key_exists($key, $this->relations);
}

$this->relationsに'posts'キーがあるので$this->relations['post']を返します。

var_dump($admin_user);

/*
object(App\User)#365 (27) {

(中略)

["relations":protected]=>
  array(1) {
    ["posts"]=>
    object(Illuminate\Database\Eloquent\Collection)#398 (1) {
      ["items":protected]=>
      array(3) {
        [0]=>
        object(App\Post)#399 (26) {
          ["connection":protected]=>
          string(5) "mysql"
          ["table":protected]=>
          string(5) "posts"
          ["primaryKey":protected]=>
          string(2) "id"
          ["keyType":protected]=>
          string(3) "int"
          ["incrementing"]=>
          bool(true)
          ["with":protected]=>
          array(0) {
          }
          ["withCount":protected]=>
          array(0) {
          }
          ["perPage":protected]=>
          int(15)
          ["exists"]=>
          bool(true)
          ["wasRecentlyCreated"]=>
          bool(false)
          ["attributes":protected]=>
          array(6) {
            ["id"]=>
            int(1)
            ["title"]=>
            string(6) "title1"
            ["body"]=>
            string(5) "body1"
            ["created_at"]=>
            string(19) "2019-04-19 03:33:35"
            ["updated_at"]=>
            string(19) "2019-04-20 02:10:58"
            ["user_id"]=>
            int(1)
          }
          ["original":protected]=>
          array(6) {
            ["id"]=>
            int(1)
            ["title"]=>
            string(6) "title1"
            ["body"]=>
            string(5) "body1"
            ["created_at"]=>
            string(19) "2019-04-19 03:33:35"
            ["updated_at"]=>
            string(19) "2019-04-20 02:10:58"
            ["user_id"]=>
            int(1)
          }
          (中略)
        }
        [1]=>
        object(App\Post)#400 (26) {
            (中略)
        }
        [2]=>
        object(App\Post)#401 (26) {
            (中略)
        }
      }
    }
  }
  (中略)
}
*/

Postオブジェクトの$this->attributesにはtitleキー、bodyキーが存在するのでgetAttributeメソッドは$this->getAttributeValue($key)を返します。

あとは長くなるので省略しますが、getAttributeValue($key)$this->attributes$keyが存在すれば、$keyと同じ名前のカラムからデータを取得し、なれればNULLを返します。

0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?