Laravel - EloquentORM - Relationships

# Introduction

學習一個框架, Ray 的想法是, 在深入理解底層實作的原理之前, 應該先知道這個框架的 使用方法; 先學習怎麼使用這個前人造的輪子, 再學習怎麼樣一個輪子。
所以本篇文章重點在於細讀官方文件, 並將內容理解後以 Q&A 的方式記錄下來, 加速學習以及查詢。




# Defining Relationships

# One To One

在 Laravel relationship 當中, 如何建立一個 one to one relation?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
/**
* Get the phone record associated with the user.
*/
public function phone()
{
return $this->hasOne('App\Phone');
}
}


Laravel hasOne relationship 當中, 預設 foreign key 的條件是什麼?

model name

Laravel hasOne relationship 當中, 如果我要自定義 foreign key, 我可以怎麼做?
<?php
return $this->hasOne('App\Phone', 'foreign_key');
Laravel hasOne relationship 當中, 預設 foreign key 的值需要對應 parent table 上的哪一個 column 的值?

id

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
  • Answer:
    自定義要使用哪個 owner table 與 foreign table 上的 key 來做連結, local_key 代表在 owner table, 即 $this, 上的 column name, foreign_key 代表在 ‘App\Phone’ table 上的 column


# Defining The Inverse Of The Relationship

Laravel one to one relationship 中, 如何定義反向的存取?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model
{
/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('App\User');
}
}
Laravel one to one relationship 中, 預設定義 belongsTo 的 foreign key 的規則是?

根據 belongsTo method 的名稱, 在 method 名稱後加上 _id

Laravel one to one relationship 中, 如何自訂義 foreign key?
<?php
/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('App\User', 'foreign_key');
}
Laravel one to one relationship 當中, 在 belongsTo method 當中, 如果我的 parent table 不是使用 id 作為 primary key, 而我想要自定義, 我可以怎麼做?
<?php
/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}


# One To Many

Laravel one to many relationship 中, 如果我要建立一個 one to many 的 relation, 我可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
/**
* Get the comments for the blog post.
*/
public function comments()
{
return $this->hasMany('App\Comment');
}
}
以下的 relation 中, foreign key 預設是什麼?
  • Example:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Post extends Model
    {
    public function comments()
    {
    return $this->hasMany('App\Comment');
    }
    }
  • Answer:
    post_id, 預設, Laravel 會在擁有者 model 使用 “snake_case”, 並在最後加上 _id

Laravel one to many relationship 中, 如何取得 relation?
<?php
$comments = App\Post::find(1)->comments;

foreach ($comments as $comment) {
//
}
Laravel one to many relationship 中, 如何取得 relation 的 query builder?
<?php
$comment = App\Post::find(1)->comments()->where('title', 'foo')->first();
Laravel one to many relationship 中, 如何自定義 foreign key 以及 local key?
<?php
return $this->hasMany('App\Comment', 'foreign_key');

return $this->hasMany('App\Comment', 'foreign_key', 'local_key');


# One To Many (Inverse)

Laravel one to many relation 中, 如何定義一個反向的 relation?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo('App\Post');
}
}
Laravel one to many relationship 中, 如何自訂義 foreign key 以及 primary key?
<?php
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo('App\Post', 'foreign_key', 'other_key');
}


# Many To Many

Laravel Relationship 中, 當我要建立一個 many to many 的中間表格, 表格的命名是什麼規格?

alphabetical

Laravel Relationship 中, 當我要建立一個 users, roles 的 many to many 的中間表格, 中間表格必須至少有什麼 column?

user_id, role_id

Laravel Relationship 中, 當我要建立一個 users, roles 的 many to many 的 relationship, 在 User 的 model 中, 我可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
/**
* The roles that belong to the user.
*/
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
承上面 Laravel 程式碼, 在 Laravel Relationship 中, 如果我已經在 User 跟 Role model 之間建立了 many to many relationship, 當我想要從 user model 取 roles, 我可以怎麼做?
<?php
$user = App\User::find(1);

foreach ($user->roles as $role) {
//
}
承上面 Laravel 程式碼, 在 Laravel Relationship 中, 如果我已經在 User 跟 Role model 之間建立了 many to many relationship, 當我想要取 roles 並 chain query 時, 我可以怎麼做?
<?php
$roles = App\User::find(1)->roles()->orderBy('name')->get();
以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model
    {
    public function roles()
    {
    return $this->belongsToMany('App\Role', 'table_name');
    }
    }
  • Answer:
    定義 User belongsTo Role relation, 並指定 pivot table 為 ‘table_name’

在 Laravel many to many relationship 中, 如果我想要自定義中間表格中 column 的名稱, 我可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
/**
* The roles that belong to the user.
*/
public function roles()
{
return $this->belongsToMany('App\Role', 'role_user', 'currentModel', 'joiningToModel');
}
}


# Retrieving Intermediate Table Columns

在 Laravel many to many relationship 中, 如果我想要取得中間表格的資料, 我可以怎麼做?
<?php
$user = App\User::find(1);

foreach ($user->roles as $role) {
echo $role->pivot->created_at;
}

會哦

model key

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
/**
* The roles that belong to the user.
*/
public function roles()
{
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
}
}
以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model
    {
    public function roles()
    {
    return $this->belongsToMany('App\Role')->withTimestamps();
    }
    }
  • Answer:
    使用 withTimestamps method, Model User 與 Model Role 的 many to many relationship 的 pivot table 上的 created_at 以及 updated_at 會被自動維護


# Customizing The pivot Attribute Name

在 Laravel many to many 的 relation 中, 中間表格的預設 model 都叫做 pivot, 如果我想要自定義它的名稱, 我可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
/**
* The roles that belong to the user.
*/
public function roles()
{
return $this->belongsToMany('App\Podcast')
->as('subscription')
->withTimestamps();
}
}
呈上, 如何存取這個 subscription 中間表格?
<?php
$users = User::with('podcasts')->get();

foreach ($users->flatMap->podcasts as $podcast) {
echo $podcast->subscription->created_at;
}


# Filtering Relationships Via Intermediate Table Columns

Laravel many to many relation 中, 如何在定義 relation 的時候, 使用中間表格的特定 attribute 條件來定義?
<?php
return $this->belongsToMany('App\Role')->wherePivot('approved', 1);

return $this->belongsToMany('App\Role')->wherePivotIn('priority', [1, 2]);

return $this->belongsToMany('App\Role')->wherePivotNotIn('priority', [1, 2]);




# Defining Custom Intermediate Table Models

以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Role extends Model
    {
    public function users()
    {
    return $this->belongsToMany('App\User')->using('App\RoleUser');
    }
    }
  • Answer:
    在定義 many to many relation 的同時, 指定 pivot Model

以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Role extends Model
    {
    public function users()
    {
    return $this->belongsToMany('App\User')
    ->using('App\RoleUser')
    ->withPivot([
    'created_by',
    'updated_by',
    ]);
    }
    }
  • Answer:
    在定義 Role belongsToMany User 的 relation 的同時, 指定 pivot table, 且指定 pivot table 上預設載入 ‘created_by’, 以及 ‘updated_by’ column

Laravel many to many relation 中, pivot model 可以使用 SoftDeletes trait 嗎?

不行哦


# Custom Pivot Models And Incrementing IDs

Laravel many to many relation 中, 為了讓 table 中的 primary key 運作正常, pivot model 中需要加什麼屬性?
<?php
/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = true;


# Has One Through

以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Supplier extends Model
    {
    public function userHistory()
    {
    return $this->hasOneThrough('App\History', 'App\User');
    }
    }
  • Answer:
    Supplier hasOne User, 而 User hasOne History, 第一個參數為 目標 model, 第二個參數為 中間 model, 定義好後可從 Supplier 直接取得 History model

Laravel hasOneThrough 中, 如果我要自定義 foreign key 跟 local key, 那我可以怎麼做?
<?php
Supplier extends Model
{
/**
* Get the user's history.
*/
public function userHistory()
{
return $this->hasOneThrough(
'App\History',
'App\User',
'supplier_id', // Foreign key on users table...
'user_id', // Foreign key on history table...
'id', // Local key on suppliers table...
'id' // Local key on users table...
);
}
}


# Has Many Through

以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Country extends Model
    {
    public function posts()
    {
    return $this->hasManyThrough('App\Post', 'App\User');
    }
    }
  • Answer:
    Country hasOne User, 而 User hasOne Post, 第一個參數為 目標 model, 第二個參數為 中間 model, 定義好後可從 Country 直接取得 Post model

在 Laravel one to many through method 中, 如果我要自定義 foreign key 以及 local key, 我可以怎麼做?
<?php
class Country extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}




# Polymorphic Relationships

# One To One (Polymorphic)

# Table Structure

在 Laravel 中, 如果說我有一個 image model, 而 user model 跟 post model 都跟 image 有 one to one 的關係, 那我可以使用什麼樣的 relation?

One To One (Polymorphic)

Laravel 中, 假設我的 Post model 有一個 Image model, 而 User model 也有一個 Image model, 現在我要定義 one to one (polymorphic) relation, 若要在 Post model 中定義與 Image model 的關係, 可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
/**
* Get the post's image.
*/
public function image()
{
return $this->morphOne('App\Image', 'imageable');
}
}
以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class User extends Model
    {
    public function image()
    {
    return $this->morphOne('App\Image', 'imageable');
    }
    }
  • Answer:
    User hasOne Image, 而其他 model 也有 hasOne Image relationship, 這樣就可以使用 morph relation, 可以共用一個 images table, Image model 的不同 relation 會在 ‘imageable_type’ 做區分, 例如 ‘App\User’ 或是 ‘App\Post’

Laravel 中, 假設我的 Post model 有一個 Image model, 而 User model 也有一個 Image model, 現在我要定義 one to one (polymorphic) relation, 若要在 Image model 中定義與 User model 以及 Post model 的關係, 可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Image extends Model
{
/**
* Get the owning imageable model.
*/
public function imageable()
{
return $this->morphTo();
}
}
以下的 Laravel one to one (Polymorphic) relation table structure 當中, imageable_id 跟 imageable_type 分別代表什麼?
  • Example:

    posts
    id - integer
    name - string

    users
    id - integer
    name - string

    images
    id - integer
    url - string
    imageable_id - integer
    imageable_type - string
  • Answer:
    imageable_id: user_id 或 post_id
    imageable_type: user model name 或 post model name


# Retrieving The Relationship

在 Laravel one to one (Polymorphic) relation 當中, 假設以下為我的 relation 定義, 如果我要從 parent model 拿到 child model, 那我可以怎麼做?
  • Relation 定義:

    <?php
    class Post extends Model
    {
    public function image()
    {
    return $this->morphOne('App\Image', 'imageable');
    }
    }
  • 取得 relation:

    <?php
    $post = App\Post::find(1);

    $image = $post->image;
在 Laravel one to one (Polymorphic) relation 當中, 假設以下為我的 relation 定義, 如果我要從 child model 取得 parent model, 我可以怎麼做?
  • Relation 定義:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Image extends Model
    {
    /**
    * Get the owning imageable model.
    */
    public function imageable()
    {
    return $this->morphTo();
    }
    }
  • 取得 relation

    <?php
    $image = App\Image::find(1);

    $imageable = $image->imageable;

# One To Many (Polymorphic)

# Table Structure

Laravel 當中, 如果說在我的應用中的 user 可以同時在 video 以及 post 中留下 comments, 那我可以使用怎麼樣的 relation?

one to many (Polymorphic)

Laravel one to many (Polymorphic) 當中, 以下的 table structure 中的 commentable_id 以及 commentable_type 代表什麼?
posts
id - integer
title - string
body - text

videos
id - integer
title - string
url - string

comments
id - integer
body - text
commentable_id - integer
commentable_type - string
  • commentable_id: 代表 foreign key
  • commentable_type: 代表 relation 的 model name


# Model Structure

Laravel 當中, 假設每一個 Video model 以及 Post model 都有多個 Comment model, 現在我要定義一個 one to many (polymorphic) relation, 若要從 Video model 中定義與 Comment model 的 relation, 可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Video extends Model
{
/**
* Get all of the video's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
Laravel 當中, 假設每一個 Video model 以及 Post model 都有多個 Comment model, 現在我要定義一個 one to many (polymorphic) relation, 若要從 Post model 中定義與 Comment model 的 relation, 可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
/**
* Get all of the post's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
Laravel 當中, 假設每一個 Video model 以及 Post model 都有多個 Comment model, 現在我要定義一個 one to many (polymorphic) relation, 若要從 Comment model 中定義與 Post 以及 Video model 的 relation, 可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
/**
* Get the owning commentable model.
*/
public function commentable()
{
return $this->morphTo();
}
}


# Retrieving The Relationship

Laravel one to many (Polymorphic) relation 當中, 如果我要從 parent model 取得 child model, 我可以怎麼做? 假設以下為我的 relation 定義
  • Relation 定義:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Comment extends Model
    {
    /**
    * Get the owning commentable model.
    */
    public function commentable()
    {
    return $this->morphTo();
    }
    }

    class Post extends Model
    {
    /**
    * Get all of the post's comments.
    */
    public function comments()
    {
    return $this->morphMany('App\Comment', 'commentable');
    }
    }

    class Video extends Model
    {
    /**
    * Get all of the video's comments.
    */
    public function comments()
    {
    return $this->morphMany('App\Comment', 'commentable');
    }
    }
  • 取得 relation

    <?php
    $post = App\Post::find(1);

    foreach ($post->comments as $comment) {
    //
    }
在 Laravel one to many (Polymorphic) relation 當中, 假設以下為我的 relation 定義, 現在我要從 child model 取得 parent model, 那我可以怎麼做?
  • relation 定義:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Comment extends Model
    {
    /**
    * Get the owning commentable model.
    */
    public function commentable()
    {
    return $this->morphTo();
    }
    }

    class Post extends Model
    {
    /**
    * Get all of the post's comments.
    */
    public function comments()
    {
    return $this->morphMany('App\Comment', 'commentable');
    }
    }

    class Video extends Model
    {
    /**
    * Get all of the video's comments.
    */
    public function comments()
    {
    return $this->morphMany('App\Comment', 'commentable');
    }
    }
  • 取得 relation

    <?php
    $comment = App\Comment::find(1);

    $commentable = $comment->commentable;


# Many To Many (Polymorphic)

# Table Structure

在 Laravel many to many (Polymorphic) relation 當中, 假如說我有 video 跟 post model, 而兩者都跟 tag model 有 many to many 的關係, 那我可以怎樣定義我的 table?
posts
id - integer
name - string

videos
id - integer
name - string

tags
id - integer
name - string

taggables
tag_id - integer
taggable_id - integer
taggable_type - string


# Model Structure

在 Laravel many to many polymorphic relation 當中, 假如我有 Post 跟 Video model, 而兩者都與 Tag model 有 many to many 的 relationship, 現在我要在 Post 定義 many to many polymorphic relation, 我可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
/**
* Get all of the tags for the post.
*/
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable');
}
}


# Defining The Inverse Of The Relationship

在 Laravel many to many polymorphic relation 當中, 假如我有 Post 跟 Video model, 而兩者都與 Tag model 有 many to many 的 relationship, 現在我要在 Tag 定義 many to many polymorphic relation, 我可以怎麼做?
<?php
class Tag extends Model
{
/**
* Get all of the posts that are assigned this tag.
*/
public function posts()
{
return $this->morphedByMany('App\Post', 'taggable');
}

/**
* Get all of the videos that are assigned this tag.
*/
public function videos()
{
return $this->morphedByMany('App\Video', 'taggable');
}
}


# Retrieving The Relationship

Laravel many to many polymorphic relationship 當中, 如果我的 relation 定義如下, 現在我要從 Post model 取得 Tag relation, 我該怎麼做?
  • Relation 定義:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Post extends Model
    {
    /**
    * Get all of the tags for the post.
    */
    public function tags()
    {
    return $this->morphToMany('App\Tag', 'taggable');
    }
    }
  • Answer:

    <?php
    $post = App\Post::find(1);

    foreach ($post->tags as $tag) {
    //
    }


Laravel many to many polymorphic relationship 當中, 如果我的 relation 定義如下, 現在我要從 Tag model 取得 Post relation, 我該怎麼做?
  • Relation 定義:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Tag extends Model
    {
    /**
    * Get all of the posts that are assigned this tag.
    */
    public function posts()
    {
    return $this->morphedByMany('App\Post', 'taggable');
    }

    /**
    * Get all of the videos that are assigned this tag.
    */
    public function videos()
    {
    return $this->morphedByMany('App\Video', 'taggable');
    }
    }
  • Answer:

    <?php
    $tag = App\Tag::find(1);

    foreach ($tag->videos as $video) {
    //
    }


# Custom Polymorphic Types

在 Laravel polymorphic relationship 當中, 預設 commentable_type 的內容會是像什麼樣的?

model 的名稱, 像是 App\Post 或是 App\Video

在 Laravel polymorphic relationship 當中, polymorphic 關係的對應預設是依照 polymorphic type column 中的值來對應的, 格式預設是 App/ModelName, 如果我不想要使用這個預設格式, 我想要變更的話, 我可以在什麼地方變更?

AppServiceProviderboot function 內

在 Laravel polymorphic relationship 當中, 如果我要在 AppServiceProvider 當中自定義 polymorphic table 中的 type column 的值, 我可以怎麼做?
<?php
use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
'posts' => 'App\Post',
'videos' => 'App\Video',
]);
在 Laravel polymorphic relationship 當中, 如果我在 AppServiceProvider 當中自定義 polymorphic table 中的 type column 的值之後, 原本的 App\Post 形式的 model 名稱需要依照自定義的名稱做變更嗎?

需要哦




# Querying Relations

Laravel query 當中, 當我使用 orWhere 時, 如果我要限制 where condition 的範圍, 我可以怎麼做?
<?php
use Illuminate\Database\Eloquent\Builder;

$user->posts()
->where(function (Builder $query) {
return $query->where('active', 1)
->orWhere('votes', '>=', 100);
})
->get();

// select * from posts
// where user_id = ? and (active = 1 or votes >= 100)


# Querying Relationship Existence

在 Laravel relationship 當中, 假如我的 Post model 與 Comment model 關聯, 我只要取得至少有一個 Comment 的 Post, 那我可以怎麼做?
<?php
// Retrieve all posts that have at least one comment...
$posts = App\Post::has('comments')->get();
在 Laravel relationship 當中, 假如我的 Post model 與 Comment model 關聯, 我只要取得有三個以上 Comment 的 Post, 那我可以怎麼做?
<?php
// Retrieve all posts that have three or more comments...
$posts = App\Post::has('comments', '>=', 3)->get();
在 Laravel relationship 當中, 假如我的 Post model 與 Comment model 關聯, 我只要取得有至少一個以上 Comment 的 Post, 且這個 comment 的 content 要含有 ‘foo’, 那我可以怎麼做?
<?php
// Retrieve posts with at least one comment containing words like foo%...
$posts = App\Post::whereHas('comments', function (Builder $query) {
$query->where('content', 'like', 'foo%');
})->get();
在 Laravel relationship 當中, 假如我的 Post model 與 Comment model 關聯, 我只要取得有十個以上 Comment 的 Post, 且 10 個 Comment 的 content 都要含有 ‘foo’, 那我可以怎麼做?
<?php
// Retrieve posts with at least ten comments containing words like foo%...
$posts = App\Post::whereHas('comments', function (Builder $query) {
$query->where('content', 'like', 'foo%');
}, '>=', 10)->get();


# Querying Relationship Absence

在 Laravel relationship 當中, 假如我的 Post model 與 Comment model 關聯, 我要取得沒有任何 comments 的 post, 那我可以怎麼做?
<?php
$posts = App\Post::doesntHave('comments')->get();
在 Laravel relationship 當中, 假如我的 Post model 與 Comment model 關聯, 我要取得沒有某些特定 comment 的 post, 而這些特定的 comment 的 content 會含有 ‘foo’, 那我可以怎麼做?
<?php
use Illuminate\Database\Eloquent\Builder;

$posts = App\Post::whereDoesntHave('comments', function (Builder $query) {
$query->where('content', 'like', 'foo%');
})->get();
在 Laravel relationship 中, 假設我有 post, comment, 以及 author Model, 現在我要取得 comment 的 author 未被 banned 的 post (以 post 的 comment 的 author 為條件 query), 那我可以怎麼做?
<?php
use Illuminate\Database\Eloquent\Builder;

$posts = App\Post::whereDoesntHave('comments.author', function (Builder $query) {
$query->where('banned', 1);
})->get();


# Querying Polymorphic Relationships

在 Laravel polymorphic relationship 當中, 假如 Post 與 Video Model 都有多個 Comment Model, 現在我要取得 comment, 所屬的 video 或 post 的 title 含有 foo%, 那我可以怎麼做?
<?php
use Illuminate\Database\Eloquent\Builder;

// Retrieve comments associated to posts or videos with a title like foo%...
$comments = App\Comment::whereHasMorph(
'commentable',
['App\Post', 'App\Video'],
function (Builder $query) {
$query->where('title', 'like', 'foo%');
}
)->get();
Laravel 中, 如果今天我的 Comment model 與 video 以及 post 有 polymorphic 的 relation, 那我想要取得 comment, 且該 comment 所屬的 post 的 title 不可含有 foo, 那我可以怎麼做?
<?php
// Retrieve comments associated to posts with a title not like foo%...
$comments = App\Comment::whereDoesntHaveMorph(
'commentable',
'App\Post',
function (Builder $query) {
$query->where('title', 'like', 'foo%');
}
)->get();
Laravel 中, 假如 Post model, Video model 與 Comment model 有 polymorphic 的關係, 現在我想要取得某些 Comment, 條件是 Video 的 title 必須含有 foo, 而 Post 的 title 或 content 必須含有 foo, 那我可以怎麼做?
<?php
use Illuminate\Database\Eloquent\Builder;

$comments = App\Comment::whereHasMorph(
'commentable',
['App\Post', 'App\Video'],
function (Builder $query, $type) {
$query->where('title', 'like', 'foo%');

if ($type === 'App\Post') {
$query->orWhere('content', 'like', 'foo%');
}
}
)->get();
Laravel polymorphic relationship 中, Comment model 與很多其他的 model 都有 morph relation, 如果我要一次性取得所有的 morph model, 不管我有幾個, 並且從這些 relation 當中搜尋任何 title 含有 foo 的 comment, 那我可以怎麼做?
<?php
use Illuminate\Database\Eloquent\Builder;

$comments = App\Comment::whereHasMorph('commentable', '*', function (Builder $query) {
$query->where('title', 'like', 'foo%');
})->get();


# Counting Relate Models

Laravel relationship 中, 假設今天我的 Post model 有很多 Comment model, 我想要拿到每個 Post model 下有幾個 Comment model, 那我可以怎麼做?
<?php
$posts = App\Post::withCount('comments')->get();

foreach ($posts as $post) {
echo $post->comments_count;
}
以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use Illuminate\Database\Eloquent\Builder;

    $posts = App\Post::withCount(['votes', 'comments' => function (Builder $query) {
    $query->where('content', 'like', 'foo%');
    }])->get();

    echo $posts[0]->votes_count;
    echo $posts[0]->comments_count;
  • Answer:
    取出 Post model 的 relation model ‘Votes’, 以及 ‘Comments’ 的數量, 並且, 針對 Comments model 有特別篩選, 條件為 where(‘content, ‘like’, ‘foo%’)
    載入後, 可在每一個 Post model 使用 ‘votes_count’ 以及 ‘comments_count’

Laravel relationship 中, 當我使用了 withCount method, Laravel 會在取得的 model 中加入哪一個欄位?

{relation}_count

Laravel relationship 中, 假設今天我的 Post model 有 comments 的 relationships, 假如現在我要取得每個 Post 有幾個 comment, 以及我要自定義一個 comment 叫做 pending_comments_count, 條件是該 comment 的 approved 必須是 false, 那我可以怎麼做?
<?php
use Illuminate\Database\Eloquent\Builder;

$posts = App\Post::withCount([
'comments',
'comments as pending_comments_count' => function (Builder $query) {
$query->where('approved', false);
},
])->get();

echo $posts[0]->comments_count;

echo $posts[0]->pending_comments_count;
Laravel Query Builder 當中, 如果我要同時使用 select 以及 withCount, 哪一種需排在前面?

select

Laravel 當中, 如果說現在我要同時取得 Post 中的 title 以及 body 欄位, 以及其 relation comments 的數量, 那我可以怎麼做?
<?php
$posts = App\Post::select(['title', 'body'])->withCount('comments')->get();

echo $posts[0]->title;
echo $posts[0]->body;
echo $posts[0]->comments_count;
Laravel 當中, 如果我的 Book model 有很多 genres model relation, 現在我已取得特定的那一個 Book model, 我要再取得所屬的 genres 的數量, 那我可以怎麼做?
<?php
$book = App\Book::first();

$book->loadCount('genres');
Laravel 當中, 如果我的 Book model 有很多 reviews relation, 現在我已取得特定的那一個 Book model, 我要再取得所屬的 reviews 的數量, 但有一個特別的條件, 那就是 reviewsrating 必須要等於 5, 那我可以怎麼做?
<?php
$book->loadCount(['reviews' => function ($query) {
$query->where('rating', 5);
}])




# Eager Loading

以下的 Laravel 程式碼中, author 為 book model 的 relation, 假設 $books 有 25 個 book model, 那以下的程式碼共會 query 幾次?
  • 程式碼:

    <?php
    $books = App\Book::all();

    foreach ($books as $book) {
    echo $book->author->name;
    }
  • answer:
    26 次, 取所有的 book model 共花一次, 取各個 model 的 author relation 再花 25 次

Laravel 中, 假設以下為我的原始程式碼, 我要如何使用 eager loading 將所有的 author relation 一次取出?
  • 原始程式碼

    <?php
    $books = App\Book::all();

    foreach ($books as $book) {
    echo $book->author->name;
    }
  • Answer:

    <?php
    $books = App\Book::with('author')->get();

    foreach ($books as $book) {
    echo $book->author->name;
    }
以下的 Laravel 程式碼中, 實際上下的 MySQL query 是哪兩句?
  • 程式碼

    <?php
    $books = App\Book::with('author')->get();

    foreach ($books as $book) {
    echo $book->author->name;
    }
  • query 語法:

    select * from books
    select * from authors where id in (1, 2, 3, 4, 5, ...)


# Eager Loading Multiple Relationships

在以下的 Laravel 程式碼中, 我如果想要一次性的 eager load relations authorpublisher, 我可以怎麼做?
  • 程式碼

    <?php
    $books = App\Book::all();
    foreach ($books as $book) {
    echo $book->author->name;
    }
  • Answer:

    <?php
    $books = App\Book::with(['author', 'publisher'])->get();


# Nested Eager Loading

在以下的 Laravel 程式碼中, 如果我要一次性的 eager load book 的 author relation, 以及 author 的 contacts relation, 我可以怎麼做?
  • 程式碼

    <?php
    $books = App\Book::all();
    foreach ($books as $book) {
    echo $book->author->name;
    }
  • Answer:

    <?php
    $books = App\Book::with('author.contacts')->get();


# Nested Eager Loading morphTo Relationships

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    use Illuminate\Database\Eloquent\Relations\MorphTo;

    $activities = ActivityFeed::query()
    ->with(['parentable' => function (MorphTo $morphTo) {
    $morphTo->morphWith([
    Event::class => ['calendar'],
    Photo::class => ['tags'],
    Post::class => ['author'],
    ]);
    }])->get();
  • Answer:
    ActivityFood morphTo Event
    ActivityFood morphTo Photo
    ActivityFood morphTo Post
    Event has relation with calendar
    Photo has relation with tags
    Post has relation with author
    一次性的從 ActivityFeed eager loading 上面的六個 relationships


# Eager Loading Specific Columns

在以下的 Laravel 程式碼中, 如果我只想要 eager load author relation 中的 id 以及 name columns, 我可以怎麼做?
  • 程式碼:

    <?php
    $books = App\Book::all();

    foreach ($books as $book) {
    echo $book->author->name;
    }
  • Answer:

    <?php
    $books = App\Book::with('author:id,name')->get();
在 Laravel 當中, 如果說我今天使用 eager loading 來取得部份的 column, 有哪一個 column 是必須的?

id


# Eager Loading By Default

在以下的 Laravel relation definition 當中, 如果說我想要預設 eager load author 這一個 relation, 那我可以怎麼做?
  • Relation definition:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Book extends Model
    {
    /**
    * Get the author that wrote the book.
    */
    public function author()
    {
    return $this->belongsTo('App\Author');
    }
    }
  • Answer:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Book extends Model
    {
    /**
    * The relationships that should always be loaded.
    *
    * @var array
    */
    protected $with = ['author'];

    /**
    * Get the author that wrote the book.
    */
    public function author()
    {
    return $this->belongsTo('App\Author');
    }
    }
在以下的 Laravel relation definition 當中, 如果說我想要從某次的 query 當中移除 $with 所賦予的 default eager loading 效果, 那我可以怎麼做?
  • Relation definition:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Book extends Model
    {
    /**
    * The relationships that should always be loaded.
    *
    * @var array
    */
    protected $with = ['author'];

    /**
    * Get the author that wrote the book.
    */
    public function author()
    {
    return $this->belongsTo('App\Author');
    }
    }
  • Answer:

    <?php
    $books = App\Book::without('author')->get();


# Constraining Eager Loads

在以下的 Laravel eager loading 範例程式碼中, 如果我想要指定 eager load title 含有 firstposts model, 那我可以怎麼做?
  • 範例程式碼:

    <?php
    $users = App\User::with('posts')->get();
  • Answer:

    <?php
    $users = App\User::with(['posts' => function ($query) {
    $query->where('title', 'like', '%first%');
    }])->get();
在以下的 Laravel 範例程式碼中, 我可以加入額外的 query builder method 嗎?
  • 範例程式碼:

    <?php
    $users = App\User::with(['posts' => function ($query) {
    $query->where('title', 'like', '%first%');
    }])->get();
  • Answer:
    可以

Laravel eager loading constrain 當中, 像是以下的 Laravel 範例程式碼, 有哪些 query builder method 不適用?
  • 範例:

    <?php
    $users = App\User::with(['posts' => function ($query) {
    $query->orderBy('created_at', 'desc');
    }])->get();
  • Answer:
    limittake


# Lazy Eager Loading

假如我的 Book model 有 author 以及 publisher 的 relation, 但我想要在特定的條件下才 eager load relation 如以下的範例程式碼, 那我可以怎麼做?
  • 範例程式碼:

    <?php
    $books = App\Book::all();

    if ($someCondition) {
    // eager load here
    }
  • Answer:

    <?php
    $books = App\Book::all();

    if ($someCondition) {
    $books->load('author', 'publisher');
    }
以下的 Laravel example code 的意思是?
  • Example:

    <?php
    $author->load(['books' => function ($query) {
    $query->orderBy('published_date', 'asc');
    }]);
  • Answer:
    eager load author 的 books relation model, 並且針對 books model 做 orderBy 排序

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    public function format(Book $book)
    {
    $book->loadMissing('author');

    return [
    'name' => $book->name,
    'author' => $book->author->name,
    ];
    }
  • Answer:
    假設我們在一開頭就取出了 User model 的 Author relation model ‘$user = User::with(‘author)’
    然而, $user 後面又新增了 Author relation model ‘$user->authors()->attach($newAuthor)’
    這時 $user 上原本載入的 Author model 就沒有這個新的 $newAuthor, 這時就可以使用 loadMissing()


# Nested Lazy Eager Loading & morphTo

Laravel 中, 假設我有一個 ActivityFeed Model, 它跟 Event, Photo, Post Model 有 morphTo 的關係, 如下面範例。 而 Event 又與 Calendar 有關, PhotoTag 有關, 而 PostAuthor 有關。 現在我要先 eager load ActivityFeed 的 morphTo 關係, 再使用 lazy eager loading 取得以上 morphTo 各自的 relationship, 我可以怎麼做?
  • 範例 relation:

    <?php

    use Illuminate\Database\Eloquent\Model;

    class ActivityFeed extends Model
    {
    /**
    * Get the parent of the activity feed record.
    */
    public function parentable()
    {
    return $this->morphTo();
    }
    }
  • Answer:

    <?php
    $activities = ActivityFeed::with('parentable')
    ->get()
    ->loadMorph('parentable', [
    Event::class => ['calendar'],
    Photo::class => ['tags'],
    Post::class => ['author'],
    ]);




# The save method

在 Laravel 當中, 如果說我一個 Post model 有許多 Comment model, 在以下的範例程式碼中, 除了直接對 comment model 做操作之外, 我要如何儲存 comment 與 post 之間的 relation?
  • 範例程式碼:

    <?php
    $comment = new App\Comment(['message' => 'A new comment.']);
    $post = App\Post::find(1);
  • Answer:

    <?php
    $comment = new App\Comment(['message' => 'A new comment.']);
    $post = App\Post::find(1);
    $post->comments()->save($comment);
在 Laravel 當中, 在以下的範例程式碼當中, 我要如何一次儲存複數的 model?
  • 範例程式碼:

    <?php
    $comment = new App\Comment(['message' => 'A new comment.']);

    $post = App\Post::find(1);

    $post->comments()->save($comment);
  • Answer:

    <?php
    $post = App\Post::find(1);

    $post->comments()->saveMany([
    new App\Comment(['message' => 'A new comment.']),
    new App\Comment(['message' => 'Another comment.']),
    ]);


# Recursively Saving Models & Relationships

以下的 Laravel 程式碼代表什麼意思?
  • 程式碼:

    <?php
    $post = App\Post::find(1);

    $post->comments[0]->message = 'Message';
    $post->comments[0]->author->name = 'Author Name';

    $post->push();
  • Answer:
    指定 post 的 comment relation 的第一個 model 的 message 為 ‘Message’
    指定 post 的 comment relation 的第一個 model 的 author relation 的 name 為 ‘Author Name’

Laravel 當中, 如果我的 relation 是 Post->hasMany->comment, 現在我要變更第一個 comment 的 message 欄位為 ‘Message’, 以及 comment 的 author relation 的 name 欄位為 ‘Author Name’, 我可以怎麼做?
<?php
$post = App\Post::find(1);

$post->comments[0]->message = 'Message';
$post->comments[0]->author->name = 'Author Name';

$post->push();


# The create Method

Laravel relationship 當中, save 跟 create method 的差別在於?
  • save 接受的參數為 model
  • create 接受的參數為 array
以下的 Laravel 程式碼代表什麼意思?
  • 程式碼:

    <?php
    $post = App\Post::find(1);

    $comment = $post->comments()->create([
    'message' => 'A new comment.',
    ]);
  • Answer:
    使用 array 內的資料來建立一筆 Post 與 Comment 的關係

Laravel relation 中, 如果我的 relation 是 Post->hasMany->comments, 現在我要帶入 array 來建立新的 relational comment, 我可以怎麼做?
<?php
$post = App\Post::find(1);

$comment = $post->comments()->create([
'message' => 'A new comment.',
]);
以下的 Laravel 程式碼中, 該怎麼儲存 post 與 comment 的 relation?
  • 程式碼:

    <?php
    $post = App\Post::find(1);
    $comment = ['message' => 'A new comment.'];
  • Answer:

    <?php
    $post = App\Post::find(1);
    $comment = ['message' => 'A new comment.'];
    $comment = $post->comments()->create($comment);
以下的 Laravel example code 的意思是?
  • Example:

    <?php
    $post = App\Post::find(1);
    $post->comments()->createMany([$comment1, $comment2]);
  • Answer:
    使用 createMany(), 帶入多個 array 來建立多個 Comments model 並儲存於資料庫, Post model hasMany Comment model

如果我要使用多個 array 來建立 relation, 我可以使用哪一個 method?

createMany


# Belongs To Relationships

以下的 Laravel 程式碼是什麼意思?
  • 程式碼:

    <?php
    $account = App\Account::find(10);

    $user->account()->associate($account);

    $user->save();
  • Answer:
    取得目標 account
    在該 user 的 account relation 中新增上面取得的 account model

以下的 Laravel 程式碼是什麼意思?
  • 程式碼:

    <?php
    $manager = auth()->user();
    $sub_account->manager()->dissociate();
    $sub_account->save();
  • Answer:
    sub_account belongs to manager
    將 sub_account 的 foreign key 設為 null

以下的 Laravel 程式碼是什麼意思?
  • 程式碼:

    <?php
    $manager = auth()->user();
    $sub_account->manager()->associate($manager);
    $sub_account->save();
  • Answer:
    sub_account belongs to manager
    將 sub_account 的 foreign key 設為 $manager

以下的 Laravel 程式碼中, $manager 可以是什麼?
  • 程式碼:

    <?php
    $manager = auth()->user();
    $sub_account->manager()->associate($manager);
    $sub_account->save();
  • Answer:
    Eloquent Model
    也可以是任意字元, 會儲存在 foreign key

Laravel relation 當中, 如果我要更新 belongs to 的 relation, subAccount belongs to Manager, 如下面的程式碼中, 我已取得 manager 的 model, 除了直接使用 update method 去更新該 table 之外, 我可以使用哪個 method?
  • 程式碼:

    <?php
    $manager = App\Manager::find(10);
  • Answer:

    <?php
    $manager = App\Manager::find(10);
    $sub_account->manager()->associate($manager);
    $sub_account->save();
以下的 Laravel example code 的意思是?
  • Example:

    <?php
    $sub_account->manager()->dissociate();
    $sub_account->save();
  • Answer:
    從 $sub_account 的 belongsTo relation manager model 中, 移除 foreign key, 即移除彼此的 relation


# Default Models

Laravel 當中, 哪些種類的 relation 可以定義 default model?

belongsTo
hasOne
hasOneThrough
morphOne

Laravel 當中, 如果我的 relation definition 如下, 現在我要定義一個 default model, name 為 guest author 我可以怎麼做?
  • 範例程式碼:

    <?php
    /**
    * Get the author of the post.
    */
    public function user()
    {
    return $this->belongsTo('App\User');
    }
  • Answer 1:

    <?php
    /**
    * Get the author of the post.
    */
    public function user()
    {
    return $this->belongsTo('App\User')->withDefault([
    'name' => 'Guest Author',
    ]);
    }
  • Answer 2:

    <?php
    /**
    * Get the author of the post.
    */
    public function user()
    {
    return $this->belongsTo('App\User')->withDefault(function ($user, $post) {
    $user->name = 'Guest Author';
    });
    }
以下的 Laravel relation definition, 如果該 relation 不存在, 會回傳什麼?
  • 範例 relation definition:

    <?php
    /**
    * Get the author of the post.
    */
    public function user()
    {
    return $this->belongsTo('App\User')->withDefault([
    'name' => 'Guest Author',
    ]);
    }
  • Answer:

    {
    "name": "Guest Author"
    }

# Many To Many Relationships

# Attaching / Detaching

Laravel many to many relation 中, 如果我要單純新增一筆 relation 紀錄, 我可以怎麼做?
<?php
$user = App\User::find(1);

$user->roles()->attach($roleId);
Laravel many to many relation 中, 如果我要單純新增一筆 relation 紀錄, 然後我還要再在額外的欄位寫入資訊, 那我可以怎麼做?
<?php
$user->roles()->attach($roleId, ['expires' => $expires]);
Laravel many to many relation 中, 如果我要單純的移除一筆 relation 紀錄, 我可以怎麼做?
<?php
// Detach a single role from the user...
$user->roles()->detach($roleId);
Laravel many to many relation 中, 如果我要單純的移除多筆筆 relation 紀錄, 我可以怎麼做?
<?php
$user = App\User::find(1);
$user->roles()->detach([1, 2, 3]);
Laravel many to many relation 中, 如果我要移除該 model 下所有的 relation 紀錄, 我可以怎麼做?
<?php
$user->roles()->detach();
Laravel many to many relation 中, 如果我要新增多筆 relation 紀錄, 然後我還要再在額外的欄位寫入資訊, 那我可以怎麼做?
<?php
$user = App\User::find(1);
$user->roles()->attach([
1 => ['expires' => $expires],
2 => ['expires' => $expires],
]);
Laravel many to many relation 中, 帶入一筆或多筆 relation 紀錄, 資料庫內需與帶入的資料完全符合, 沒有的新增, 多的刪除, 那我可以怎麼做?
<?php
$user->roles()->sync([1, 2, 3]);
Laravel many to many relation 中, 帶入一筆或多筆 relation 紀錄, 資料庫內需與帶入的資料完全符合, 沒有的新增, 多的刪除, 我還要再額外的欄位新增資訊, 那我可以怎麼做?
<?php
$user->roles()->sync([1 => ['expires' => true], 2, 3]);
Laravel many to many relation 中, 如果我要帶入一筆或多筆紀錄, 資料庫內若無資料則新增, 若有則保留不刪除, 那我可以怎麼做?
<?php
$user->roles()->syncWithoutDetaching([1, 2, 3]);

# Toggling Associations

Laravel many to many relation 中, 如果我要帶入一組 relation 紀錄, 資料庫裡頭, 若沒有則則新增, 若有的話則移除, 那我可以怎麼做?
<?php
$user->roles()->toggle([1, 2, 3]);


# Saving Additional Data On A Pivot Table

Laravel many to many relation 中, 如果我要新增一筆 relation 紀錄, 同時如果此 relation 的對象不存在的話則建立, 再建立 relation 紀錄, 那我可以怎麼做?
<?php
App\User::find(1)->roles()->save($role, ['expires' => $expires]);


# Updating A Record On A Pivot Table

Laravel many to many relation 中, 如果我要更新目前已經存在, 位於中間表格裡的 relation 紀錄, 那我可以怎麼做?

$attribute 是一個 array

<?php
$user = App\User::find(1);
$user->roles()->updateExistingPivot($roleId, $attributes);




# Touching Parent Timestamps

Laravel many to many relation 中, 如果當我更新了中間表格的 relation timestamps 時, 我也想要一併更新 parent table 的 timestamp, 我可以怎麼做?
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
/**
* All of the relationships to be touched.
*
* @var array
*/
protected $touches = ['post'];

/**
* Get the post that the comment belongs to.
*/
public function post()
{
return $this->belongsTo('App\Post');
}
}
一下子敏感, 一下子不敏感, Git 你搞得我好亂啊 使用 Spinnaker 在 Kubernetes Engine 中實作持續交付管道

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×