以下のレコード、コードで実行します。
+----+--------+
| id | name |
+----+--------+
| 1 | admin |
| 2 | user01 |
+----+--------+
email、email_verified_at、password、remember_token、created_at、updated_atカラムは省略します。
+----+--------+-------+---------------------+---------------------+---------+
| 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 |
+----+--------+-------+---------------------+---------------------+---------+
<?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();
}
}
<?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->postsはuser_id = 1のデータを入れた、Postオブジェクトを入れた、
Illuminate\Database\Eloquent\Collectionオブジェクトを返します。
Userオブジェクトはpostsプロパティを持っていないので__get()メソッドが呼ばれます。
/**
* 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->attributesにpostsはありません。
selfはModelクラスなので、postsは定義されていません。
よって、$this->getRelationValue('posts')を返します。
/**
* 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);
}
}
/**
* 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を返します。