本節將使用用戶建立博文來學習數據模型關聯的有關知識。php
若是用Laravel原生的表單提示錯誤信息,則是英文的,若是須要中文,則須要修改resources/lang/en
的英文,這樣比較麻煩,不過,咱們可使用github開源的漢化包,而後引入該文件夾,在config/app.php
配置文件裏邊修改語言包引入便可使用。laravel
<span class="timestamp"> {{ $status->created_at->diffForHumans() }} </span>
該方法的做用是將日期進行友好化處理,咱們可使用 tinker 來查看該方法的具體輸出狀況。git
$ php artisan tinker
在 tinker 中輸出第一位用戶的建立時間以下。github
>>> $created_at = App\Models\User::first()->created_at => Carbon\Carbon {#704 +"date": "1998-12-06 03:15:31.000000", +"timezone_type": 3, +"timezone": "UTC", }
在 tinker 中調用 diffForHumans 方法來輸出,結果以下。數據庫
>>> $created_at->diffForHumans() => "17 years ago"
咱們發現 diffForHumans 爲咱們生成的時間是英文的,若是要使用中文時間,則須要對 Carbon 進行本地化設置。Carbon 是 PHP DateTime 的一個簡單擴展,Laravel 將其默認集成到了框架中。app
數據表之間常常會互相進行關聯。例如,一篇博客文章可能會有多條評論,或是一張訂單可能對應一個下單客戶。Eloquent
讓管理和處理這些關聯變得很容易,同時也支持多種類型的關聯。框架
你可在 Eloquent 模型類內將 Eloquent 關聯定義爲函數。由於關聯像 Eloquent 模型同樣也能夠做爲強大的 查詢語句構造器
(數據庫:查詢構造器),定義關聯爲函數提供了強而有力的鏈式調用及查找功能。例如:函數
$user->posts()->where('active', 1)->get();
不過,在深刻了解使用關聯以前,先讓咱們來學習如何定義每一個類型:post
一對一關聯是很基本的關聯。例如一個 User 模型也許會對應一個 Phone。要定義這種關聯,咱們必須將 phone 方法放置於 User 模型上。phone 方法應該要返回基類 Eloquent 上的 hasOne
方法的結果:學習
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * 獲取與指定用戶互相關聯的電話紀錄。 */ 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 字段會有個對應值。換句話說,Eloquent 會尋找用戶的 id
字段與 Phone
模型的 user_id
字段的值相同的紀錄。若是你想讓關聯使用 id 之外的值,則能夠傳遞第三個參數至 hasOne 方法來指定你自定義的鍵:
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
因此,咱們能夠從 User 訪問到 Phone 模型。如今,讓咱們在 Phone 模型上定義一個關聯,此關聯可以讓咱們訪問擁有此電話的 User。咱們能夠定義與 hasOne
關聯相對應的 belongsTo
方法:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Phone extends Model { /** * 獲取擁有此電話的用戶。 */ public function user() { return $this->belongsTo('App\User'); } }
一個「一對多」關聯使用於定義單個模型擁有任意數量的其它關聯模型。例如,一篇博客文章可能會有無限多個評論。就像其它的 Eloquent 關聯同樣,能夠經過放置一個函數到 Eloquent 模型上來定義一對多關聯:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { /** * 獲取博客文章的評論。 */ 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) { // }
如今咱們已經能訪問到全部文章的評論,讓咱們來接着定義一個經過評論訪問上層文章的關聯。若要定義相對於 hasMany
的關聯,可在下層模型定義一個叫作 belongsTo
方法的關聯函數:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Comment extends Model { /** * 獲取擁有此評論的文章。 */ public function post() { return $this->belongsTo('App\Post'); } }
多對多關聯要稍微比 hasOne
及 hasMany
關聯複雜。如一個用戶可能擁有多種身份,而一種身份能同時被多個用戶擁有。舉例來講,不少用戶都擁有「管理者」的身份。要定義這種關聯,須要使用三個數據表:users
、roles
和 role_user
。role_user 表命名是以相關聯的兩個模型數據表來依照字母順序命名,幷包含了 user_id 和 role_id 字段。
多對多關聯經過編寫一個在自身 Eloquent 類調用的 belongsToMany
的方法來定義。舉個例子,讓咱們在 User 模型定義 roles 方法:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * 屬於該用戶的身份。 */ public function roles() { return $this->belongsToMany('App\Role'); } }
要定義相對於多對多的關聯,只需簡單的放置另外一個名爲 belongsToMany
的方法到你關聯的模型上。讓咱們接着以用戶身份爲例,在 Role 模型中定義 users 方法:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Role extends Model { /** * 屬於該身份的用戶。 */ public function users() { return $this->belongsToMany('App\User'); } }
如你所見,此定義除了簡單的參考 AppUser 模型外,與 User 的對應徹底相同。由於咱們重複使用了 belongsToMany
方法,當定義相對於多對多的關聯時,全部經常使用的自定義數據表與鍵的選項都是可用的。
$this->hasOne('App\Phone'); $this->belongsTo('App\User');
hasOne
關聯相對應的 belongsTo
方法
$this->hasMany('App\Comment'); $this->belongsTo('App\Post');
hasMany
關聯相對應的 belongsTo
方法
$this->belongsToMany('App\Role'); $this->belongsToMany('App\User');
belongsToMany
關聯相對應的 belongsToMany
方法
你能夠查找 posts 關聯並增長額外的條件相當聯,像這樣:
$user = App\User::find(1); $user->posts()->where('active', 1)->get();
關聯方法與動態屬性
若是你不須要增長額外的條件至 Eloquent 的關聯查找,則能夠簡單的像訪問屬性同樣來訪問關聯。例如咱們剛剛的 User 及 Post 模型示例,咱們能夠像這樣來訪問全部用戶的文章:
$user = App\User::find(1); foreach ($user->posts as $post) { // }
當經過屬性訪問 Eloquent 關聯時,該關聯數據會被「延遲加載」。意味着該關聯數據只有在你使用屬性訪問它時纔會被加載。不過,Eloquent 能夠在你查找上層模型時「預加載」關聯數據。預加載避免了 N + 1 查找的問題。要說明 N + 1 查找的問題,可試想一個關聯到 Author 的 Book 模型,以下所示:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Book extends Model { /** * 獲取編寫該書的做者。 */ 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, ...)