本节将使用用户建立博文来学习数据模型关联的有关知识。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, ...)