程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> laravel學習教程之關聯模型

laravel學習教程之關聯模型

編輯:PHP綜合

Eloquent: 關聯模型

簡介

數據庫中的表經常性的關聯其它的表。比如,一個博客文章可以有很多的評論,或者一個訂單會關聯一個用戶。Eloquent 使管理和協作這些關系變的非常的容易,並且支持多種不同類型的關聯:

    一對一

    一對多

    多對多

    遠程一對多

    多態關聯

    多態多對多關聯

定義關聯

Eloquent 關聯可以像定義方法一樣在 Eloquent 模型類中進行定義。同時,它就像 Eloquent 模型自身一樣也提供了強大的查詢生成器。這允許關聯模型可以鏈式的執行查詢能力。比如:

$user->posts()->where('active', 1)->get();

但是,在更深入的使用關聯之前,讓我們先來學習一下如何定義各種類型的關聯。

一對一

一對一的關聯是最基礎的關聯。比如,一個 User 模型可能關聯一個 Phone。我們需要在 User 模型上放置一個 phone 方法來定義這種關聯。phone 方法應該返回一個基類 Eloquent 模型上 hasOne 方法的結果:

<?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');
 }
}

傳遞到 hasOne 方法的第一個參數應該是關聯模型的名稱。一旦關聯被定義完成,我們可以使用 Eloquent 的動態屬性來訪問關聯模型的記錄。動態屬性允許你訪問關聯函數,就像是它們是定義在模型中的屬性一樣:

$phone = User::find(1)->phone;

Eloquent 假定所關聯的外鍵是基於模型的名稱的。在這個前提下,Phone 模型會自動的假定其擁有一個 user_id 外鍵。如果你希望修改這個慣例,你可以傳遞第二個參數到 hasOne 方法中:

return $this->hasOne('App\Phone', 'foreign_key');

另外,Eloquent 也會假定外鍵應該在其上層模型上擁有一個匹配的 id(或者自定義的 $primaryKey)值。換句話說,Eloquent 會查詢 Phone 記錄中的 user_id 列所對應的用戶的 id 列的記錄。如果你希望關聯使用 id 以外的值,你可以傳遞第三個參數到 hasOne 方法來指定自定義的鍵:

return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

定義相對的關聯

那麼,我們可以從我們的 User 中訪問 Phone 模型。現在,讓我們在 Phone 模型上定義一個關聯,讓我們可以從 Phone 模型中訪問其所屬的 User。我們使用 belongsTo 方法來定義 hasOne 相對的關聯:

<?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');
 }
}

在上面的例子中,Eloquent 將會嘗試從 Phone 模型中的 user_id 字段中匹配查找 id 相同的 UserEloquent 會依據所關聯的模型的蛇形命名和 _id 來假定默認的外鍵名。事實上,如果在 Phone 模型上的外鍵不是 user_id,那麼你可以傳遞自定義的外鍵名到 belongsTo 方法的第二個參數:

/**
 * Get the user that owns the phone.
 */
public function user()
{
 return $this->belongsTo('App\User', 'foreign_key');
}

如果你的上級模型並沒有使用 id 作為主鍵名,或者你希望下級模型關聯一個不同的列。你可以傳遞第三個參數到 belongsTo 方法來指定上級模型表中的自定義鍵:

/**
 * Get the user that owns the phone.
 */
public function user()
{
 return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}

一對多

一個一對多的關聯常常用來定義一個模型擁有其他任意數目的模型。比如,一個博客文章可以擁有很多條評論。就像其他的 Eloquent 關聯一樣,一對多關聯在 Eloquent 模型中通過方法來進行定義:

<?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');
 }
}

記住,Eloquent 會自動的根據 Comment 模型來判斷合適的外鍵。依據慣例,Eloquent 會使用自身模型的蛇形命名和 _id 來作為外鍵。所以,在這個例子中,Eloquent 會假定 Comment 模型的外鍵是 post_id

一旦關聯定義完成之後,我們可以通過 comments 屬性來訪問所有關聯的評論的集合。記住,由於 Eloquent 提供了動態屬性,我們可以對關聯函數進行訪問,就像他們是在模型中定義的屬性一樣:

$comments = App\Post::find(1)->comments;

foreach ($comments as $comment) {
 //
}

當然,由於所有的關聯都提供了查詢生成器的功能,所以你可以在調用 comments 方法時繼續的添加一些限制條件,你可以通過鏈式的調用進行查詢條件的添加:

$comments = App\Post::find(1)->comments()->where('title', 'foo')->first();

就像 hasOne 方法,你可以通過添加額外的參數到 hasMany 方法中來重置外鍵和主鍵:

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

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

定義相對的關聯

現在我們可以訪問文章中所有的評論了,讓我們為評論定義一個關聯使其可以訪問它的上層文章模型。為了定義一個 hasMany 相對的關聯,你需要在下層模型中定義一個關聯方法並調用 belongsTo 方法:

<?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');
 }
}

一旦關聯被定義完成,我們就可以通過 Comment 模型的 post 動態屬性來檢索到其對應的 Post 模型:

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

echo $comment->post->title;

在上面的例子中,Eloquent 會嘗試從 Comment 模型中的 post_id 字段檢索與其相對應 id Post 模型。Eloquent 會使用關聯模型的蛇形命名和 _id 來作為默認的外鍵。如果 Comment 模型的外鍵不是 post_id,你可以傳遞一個自定義的鍵名到 belongsTo 方法的第二個參數:

/**
 * Get the post that owns the comment.
 */
public function post()
{
 return $this->belongsTo('App\Post', 'foreign_key');
}

如果上層模型並沒有使用 id 作為主鍵,或者你想在下層模型中關聯其他的列,你可以傳遞第三個參數到 belongsTo 方法中:

/**
 * Get the post that owns the comment.
 */
public function post()
{
 return $this->belongsTo('App\Post', 'foreign_key', 'other_key');
}

多對多

多對多的關聯比 hasOne hasMany 關聯要稍微復雜一些。假如一個用戶擁有多個角色,而角色又可以被其他的用戶所共享。比如,多個用戶可以擁有管理員的角色。如果定義這種關聯,我們需要定義三個數據庫表:usersroles,和 role_userrole_user 表的命名是以相關聯的兩個模型數據表來依照字母順序命名,並且表中包含了 user_id role_id 列。

多對多關聯需要編寫一個方法調用基礎 Eloquent belongsToMany 方法。比如,讓我們在 User 模型中定義一個 roles 方法:

<?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');
 }
}

一旦關聯被定義,你可以通過 roles 動態屬性來訪問用戶的角色:

$user = App\User::find(1);

foreach ($user->roles as $role) {
 //
}

當然,就像其他類型的關聯,你可以調用 roles 方法並且鏈式調用查詢條件:

$roles = App\User::find(1)->roles()->orderBy('name')->get();

就如先前所提到的,Eloquent 會合並兩個關聯模型並依照字母順序進行命名。當然你也可以隨意的重寫這個約定,你可以傳遞第二個參數到 belongsToMany 方法:

return $this->belongsToMany('App\Role', 'role_user');

除了自定義合並數據表的名稱之外,你也可以通過往 belongsToMany 方法傳傳遞額外參數來自定義數據表裡的鍵的字段名稱。第三個參數是你定義在關聯中模型外鍵的名稱。第四個參數則是你要合並的模型外鍵的名稱:

return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');

定義相對關聯

你只需要在相對應的關聯模型裡放置其他的方法來調用 belongsToMany 方法就可以定義相對關聯。繼續我們上面的用戶角色示例,讓我們在 Role 模型中定義一個 users 方法:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
 /**
  * The users that belongs to the role.
  */
 public function users()
 {
  return $this->belongsToMany('App\User');
 }
}

就如你所看到的,這個關聯的定義與用戶的關聯定義完全相同。因為我們重復的使用了 belongsToMany 方法,當定義相對於多對多的關聯時,所有常用的自定義數據表和鍵的選項都是可用的。

檢索中間表字段

正如你已經了解到的。定義多對多的關聯需要引入一個中間表。Eloquent 提供了幾種非常有幫助的方式來與這個表進行交互。比如,讓我們假定我們的 User 對象關聯到了很多 Role 對象。在訪問這些關聯對象時,我們可以通過在模型上使用 pivot 屬性來訪問中間表:

$user = App\User::find(1);

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

注意我們取出的每個 Role 對象,都會被自動的分配 pivot 屬性。這個屬性包含了一個代表中間表的模型,並且可以像其他 Eloquent 模型一樣被使用。

默認的,只有模型的鍵會被 pivot 對象提供,如果你的中間表包含了額外的屬性,你必須在定義關聯時指定它們:

return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');

如果你想要中間表自動維護 created_at updated_at 時間戳,你可以在定義關聯時使用 withTimestamps 方法:

return $this->belongsToMany('App\Role')->withTimestamps();

通過中間表字段過濾關系

你可以通過在定義關聯時使用 wherePrivot wherePivotIn 方法來在返回的結果中進行過濾:

return $this->belongsToMany('App\Role')->wherePivot('approved', 1);

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

遠程一對多

遠程一對多關聯提供了簡短便捷的方法通過中間關聯件來訪問遠端的關聯。比如,一個 Country 模型應該通過 User 模型可以擁有很多的 Post 模型。在這個例子中,你可以非常容易的就檢索出一個國家中的所有的文章。讓我們來看一下定義這些關聯所需要的表:

countries
 id - integer
 name - string

users
 id - integer
 country_id - integer
 name - string

posts
 id - integer
 user_id - integer
 title - string

遠端的 posts 並沒有包含 country_id 列,hasManyThrough 關聯可以通過 $country->posts 來訪問一個國家的文章。為了執行這個查詢,Eloquent 會通過中間表 users country_id 來檢索 posts 表中用戶 ID 相匹配的記錄。

現在我們已經明確了關聯表的結構,那麼讓我們來在 Country 模型上定義關聯:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Country extends Model
{
 /**
  * Get all of the posts for the country.
  */
 public function posts()
 {
  return $this->hasManyThrough('App\Post', 'App\User');
 }
}

傳遞到 hasManyThrough 方法的第一個參數是我們最終想要訪問到的模型,而第二個參數則是中間層的模型名稱。

當使用關聯查詢時,通常 Eloquent 會遵循外鍵約定。如果你希望對關聯的鍵進行自定義,你可以傳遞第三和第四個參數到 hasManyThrough 方法。第三個參數是中間層模型的外鍵名稱,第四個參數是最終想要獲取的模型中的所對應的中間層的外鍵, 而第五個參數則是當前模型的主鍵:

class Country extends Model
{
 public function posts()
 {
  return $this->hasManyThrough(
   'App\Post', 'App\User',
   'country_id', 'user_id', 'id'
  );
 }
}

多態關聯

表結構

多態關聯允許一個模型在單個關聯中從屬一個或多個其它模型。比如,想象一下應用中的用戶可以喜歡文章及其評論。如果使用多態關聯,那麼你就可以使用一個單獨的 likes 表來關聯這兩個場景。首先,讓我們確定定義這種關聯所需要的表結構:

posts
 id - integer
 title - string
 body - text

comments
 id - integer
 post_id - integer
 body - text

likes
 id - integer
 likeable_id - integer
 likeable_type - string

你需要注意到的兩個在 likes 表中重要的字段 likeable_id likeable_typelikeable_id 字段會包含文章或者評論的 ID 值,而 likeable_type 字段會包含其所屬的模型的類名。likeable_type 就是當訪問 likeable 關聯時 ORM 用來判斷所屬的模型是哪個類型。

模型結構

接著,讓我們檢查一下這個關聯所需要的模型定義:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class like extends Model
{
 /**
  * Get all of the owning likeable models.
  */
 public function likeable()
 {
  return $this->morphTo();
 }
}

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

class Comment extends Model
{
 /**
  * Get all of the comment's likes.
  */
 public function likes()
 {
  return $this->morphMany('App\Like', 'likeable');
 }
}

獲取多態關聯

一旦數據庫表和模型都定義完成,你就可以在你的模型中訪問這些關聯。比如,你可以使用 likes 動態屬性來訪問文章中所有關聯的 likes 模型:

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

foreach ($post->likes as $like) {
 //
}

你也可以通過在模型上調用提供 morphTo 的方法來獲取多態模型其關系所有者。在上面的例子中,指的就是 Like 模型中的 likeable 方法。所以,我們可以像使用動態屬性一樣使用方法來進行訪問:

$like = App\Like::find(1);

$likeable = $like->likeable;

Like 模型的 likeable 關聯將會返回一個 Post 或者 Comment 實例,這取決於其所屬者的類型。

自定義多態類型

默認的,Laravel 會使用包完全限定類名來存儲所關聯模型的類型。比如,上面的例子中 Like 可以屬於 Post 或者 Comment。默認的 likeable_type 應該是 App\Post 或者 App\Comment。事實上,你可能希望從你的應用程序的內部結構分離數據庫。在這個例子中,你可以定義一個關聯的多態映射來指導 Eloquent 使用模型關聯的表名稱來替代類名:

use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
 App\Post::class,
 App\Comment::class,
]);

或者,你可以指定一個自定的字符串與每個模型進行關聯:

use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
 'posts' => App\Post::class,
 'likes' => App\Like::class,
]);

你可以在你的 AppServiceProvider 或者一個分離的服務提供者的 boot 方法中注冊你的 morphMap

多態多對多關聯

表結構

除了傳統的多態關聯,你也可以定義多對多的多態關聯。比如,一個博客的 Post Video 模型應該可以共享一個多態關聯的 Tag 模型。使用多對多的多態關聯可以允許你的博客文章和視頻能夠共享獨特標簽的單個列表。首先,讓我們來看一下表結構:

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

模型結構

接著,我們來定義模型中的關聯。Post Video 模型將都會包含調用基礎 Eloquent 類的 morphToMany 方法的 tags 方法:

<?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');
 }
}

定義相對的關聯

接著,在 Tag 模型中,你應該為所有關聯模型定義相應的方法。所以,在這個例子中,我們將定義 posts 方法和 videos 方法:

<?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');
 }
}

獲取關聯

當定義完成數據表和模型之後,你就可以通過模型來訪問其關聯。比如,你可以簡單的使用 tags 動態屬性來訪問文章的所有標簽模型:

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

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

你也可以通過訪問模型中提供執行 morphedByMany 方法的方法來獲取關聯模型的所屬模型。在上面的例子中,就是 Tag 模型上的 posts 或者 videos 方法。所以,你可以像動態屬性一樣訪問這些方法:

$tab = App\Tag::find(1);

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

關聯查詢

由於所有的 Eloquent 關聯類型都是通過方法定義的,所以你可以調用這些方法來獲取所關聯的模型的實例而無需實際的執行關聯查詢。另外,所有的 Eloquent 關聯也都提供了查詢生成器服務,這允許你可以繼續的鏈式執行查詢操作。

比如,想象一下博客系統中 User 模型擁有很多 Post 關聯的模型:

<?ph

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
 /**
  * Get all of the posts for the user.
  */
 public function posts()
 {
  return $this->hasMany('App\Post');
 }
}

你可以查詢 posts 關聯的同時添加一些額外的查詢約束:

$user = App\User::find(1);

$user->posts()->where('active', 1)->get();

你應該注意到了,你可以在關聯中使用任何的查詢生成器的方法。

關聯方法 Vs. 動態屬性

如果你不需要在進行 Eloquent 關聯查詢時添加額外的約束,你可以簡單的像它的屬性一樣進行訪問。比如,我們繼續使用 User Post 示例模型。我們可以像這樣來訪問用戶的所有文章:

$user = App\User::find(1);

foreach ($user->posts as $post) {
 //
}

動態屬性是惰性加載的,這意味著在你實際訪問他們之前,其關聯數據是不會加載的。正因為如此,開發的時候通常使用預加載來進行加載一些即將用到的關聯模型。預加載要求必須加載一個模型的關系,這有效的減少了查詢的次數。

查詢關聯是否存在

當訪問一個模型的記錄時,你可能會希望基於關聯的記錄是否存在來對結果進行限制。比如,想象一下你希望獲取最少有一條評論的博客文章。你可以傳遞關聯的名稱到 has 方法來做這些:

// Retrieve all posts that have at least one comment...
$posts = App\Post::has('comments')->get();

你也可以指定操作符,和數量來進一步定制查詢:

// Retrieve all posts that have three or more comments...
$posts = Post::has('comments', '>=', 3)->get();

你也可以使用 . 語法來構造嵌套的 has 語句。比如,你可以獲取所有包含至少一條評論和投票的文章:

// Retrieve all posts that hava at least one comment with votes...
$posts = Post::has('comments.votes')->get();

如果你需要更高的控制,你可以使用 whereHas orWhereHas 方法來在 has 查詢中插入 where 子句。這些方法允許你為關聯進行自定義的約束查詢。比如檢查評論的內容:

// Retrieve all posts with at least one comment containing words like foo%
$posts = Post::whereHas('comments', function ($query) {
 $query->where('content', 'like', 'foo%'); 
})->get();

統計關聯結果

如果你希望統計關聯的結果而不實際的加載它們,你可以使用 withCount 方法,這將在你的結果模型中添加 {relation}_count 列。比如:

$posts = App\Post::withCount('comments')->get();

foreach ($posts as $post) {
 echo $post->comments_count;
}

你也可以同時檢索多個關聯的統計,以及添加查詢約束:

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

echo $posts[0]->votes_count;
echo $posts[0]->comments_count;

預加載

當通過屬性訪問 Eloquent 關聯時,該關聯的數據會被延遲加載。這意味著該關聯數據只有在你真實的訪問屬性時才會進行加載。事實上,Eloquent 可以在上層模型中一次性預加載的。預加載有效避免了 N + 1 的查找問題。要說明 N + 1 查找問題,我們可以來看一個 Author 關聯 Book 的示例:

<?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');
 }
}

現在,讓我們檢索所有的書籍和他們的作者:

$books = App\Book::all();

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

這個循環會執行一次查找回所有的書籍,接著每本書會運行一次查找作者的操作。所以,如果我們擁有 25 本書,那麼循環將會進行 26 次查詢:1 次查詢所有的書籍,25 次查詢相關書籍的作者。

非常幸運的,我們可以使用預加載來將查詢有效的控制在 2 次。當查詢時,使用 with 方法來指定關聯的預加載:

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

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

對於這個操作,只會執行兩個查詢:

select * from books

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

預加載多個關聯

有時候你可能需要在一個操作中預加載多個關聯,你只需要傳遞額外的參數到 with 方法中就可以:

$books = App\Book::with('author', 'publisher')->get();

嵌套的預加載

你可以使用 . 語法來加載嵌套的關聯。比如,讓我們在一個 Eloquent 語句中一次加載所有書籍的作者以及作者的死人通訊簿:

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

預加載約束

有時候你可能希望預加載一些關聯,但是也需要對預加載查詢指定額外的約束,這裡有個示例:

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

在這個例子中,Eloquent 會值預加載文章的 title 列包含 first 單詞的記錄。當然,你也可以調用其他查詢生成器可用的方法:

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

延遲預加載

有時候你可能需要在上層模型被獲取後才預加載其關聯。當你需要來動態決定是否加載關聯模型時尤其有用:

$books = App\Book::all();

if ($someCondition) {
 $books->load('author', 'publisher');
}

如果你需要對預加載做一些查詢約束,你可以傳遞 Closure load 方法:

$books->load(['author' => function ($query) {
 $query->orderBy('published_date', 'asc');
}]);

插入關系模型

Save 方法

Eloquent 提供了方便的方法來為模型添加一個關聯。比如,也許你需要為 Post 模型新增一個 Comment。除了手動的設置 Comment post_id 屬性,你也可以直接在關聯模型中調用 save 方法來插入 Comment:

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

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

$post->comments()->save($comment);

注意上面我們並沒有使用關聯模型的動態屬性的方式來訪問 comments,而是使用 comments 方法的形式來獲取關聯模型的實例。save 方法會自動的添加相應的 post_id 值到新的 Comment 模型上。

如果你需要一次添加多個關聯模型,你需要使用 saveMany 方法:

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

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

Save & 多對多關聯

當與多對多關聯互動時,save 方法接收一個中間層表屬性的額外參數數組作為第二個參數:

App\User::find(1)->roles()->save($role, ['expires' => $expires]);

Create 方法

除了 save saveMany 方法之外,你也可以使用 create 方法,它可以接收屬性組成的數組,創建一個模型並且將其存儲到數據庫。這一次,savecreate 方法的區別是 save 接收一個完整的 Eloquent 模型實例,而 create 接收的是一個原生的 PHP array:

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

$comment = $post->comments()->create([
 'message' => 'A new comment.',
]);

在使用 create 方法之前,你應該確保已經閱讀了屬性的 批量賦值文檔。

更新從屬關聯模型

當更新一個 belongsTo 關聯時,你應該使用 associate 方法。這個方法會在下層模型中設置外鍵:

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

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

$user->save();

當刪除 belongsTo 關聯時,你應該使用 dissociate 方法,該方法會重置下層模型所關聯的外鍵:

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

$user->save();

多對多關聯

附加 / 抽離

當使用多對多關聯時,Eloquent 提供了一些額外的幫助方法來更方便的管理關聯模型。比如,讓我們想象一下用戶可以有很多角色並且角色可以有很多用戶。你可以使用 attach 方法來附加一個角色到用戶並且在中間表中加入這條記錄:

$user = App\User::find(1);

$user->roles()->attach($roleId);


當附加關聯到模型時,你也可以傳遞一個含有額外數據的數組來將其添加到中間表中:

$user->roles()->attach($roleId, ['expires' => $expires]);

當然,有時候你可能需要從用戶中刪除一個角色。你可以使用 detach 方法來刪除多對多關聯的記錄。datech 方法將從中間表中刪除相應的記錄。但是,除了中間表,其它兩個模型的記錄都還會被保留:

// Detach a single role from the user...
$user->roles()->detach($roleId);

// Detach all roles from the user...
$user->roles()->detach();

為了更加的便捷,attachdetach 也可以接收 IDs 所組成的數組作為輸入:

$user = App\User::find(1);

$user->roles()->detach([1, 2, 3]);

$user->roles()->attach([1 => ['expires' => $expires], 2, 3]);

更新中間表的記錄

如果你需要更新中間表中存在的行,你可以使用 updateExistingPivot 方法:

$user = App\User::find(1);

$user->roles()->updateExistingPivot($roleId, $attributes);

便利的同步

你也可以使用 sync 方法來構建多對多的關聯。sync 方法接收放置中間表 IDs 所組成的數組。任意 IDs 如果沒有在所給定的數組中,那麼其將會從中間表中進行刪除。所以,在操作完成之後,只有存在於給定數組裡的 IDs 才會存在於中間表中:

$user->roles()->sync([1, 2, 3]);

你也可以同時傳遞額外的中間表的鍵值對:

$user->roles()->sync([1 => ['expires' => true], 2, 3]);

聯動上層模型時間戳

當一個模型 belongsTo 或者 belongsToMany 另外一個模型時,比如 Comment 從屬於 Post,這對下層模型更新時同時要求更新上層模型的時間戳時很有幫助。比如,當 Comment 模型更新了,你想要自動的更新其所屬的 Post 模型的 updated_at 時間戳。Eloquent 使之變的非常容易。你只需要在下層模型中添加一個 touches 屬性來包含關聯的名稱就可以了:

<?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');
 }
}

現在,當你更新 Comment 時,其所屬的 Post 將會同時更新 updated_at 列:

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

$comment->text = 'Edit to this comment!';

$comment->save();

以上就是laravel學習教程之關聯模型的全部內容,希望對大家學習php有所幫助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved