laravel 基础教程 —— 关联模型

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 相同的 User。Eloquent
会根据所关联的模子的蛇形命名和 _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
字段寻找与其相对应 idPost 模型。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');
}

多对多

多对多的关系比 hasOnehasMany
关联要有些复杂一些。要是一个用户所有三个角色,而角色又有啥不可被此外的用户所共享。比如,五个用户可以享有管理员的角色。若是定义那种关系,大家需求定义多个数据库表:usersroles,和
role_userrole_user
表的命名是以相关联的五个模型数据表来依据字母逐一命名,并且表中带有了
user_idrole_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_atupdated_at
时间戳,你可以在概念关联时利用 withTimestamps 方法:

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

经过中间表字段过滤关系

您可以因此在概念关联时利用 wherePrivotwherePivotIn
方法来在回去的结果中开展过滤:

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
会通过中间表 userscountry_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

多态多对多涉及

表结构

除却传统的多态关联,你也可以定义多对多的多态关联。比如,一个博客的
PostVideo 模型应该可以共享一个多态关联的 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

模型结构

随着,大家来定义模型中的关联。PostVideo 模型将都会包蕴调用基础
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
关联查询时添加额外的封锁,你可以简不难单的像它的品质一样进行走访。比如,大家继续行使
UserPost 示例模型。我们得以像这么来走访用户的享有小说:

$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();

假如您须要更高的主宰,你可以动用 whereHasorWhereHas 方法来在
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');
}

一旦你必要对预加载做一些询问约束,你能够传递 Closureload 方法:

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

陈设关系模型

Save 方法

Eloquent 提供了方便的措施来为模型加上一个关联。比如,也许你需要为 Post
模型新增一个 Comment。除了手动的设置 Commentpost_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 方法

除了 savesaveMany 方法之外,你也可以运用 create
方法,它可以吸纳属性组成的数组,创制一个模子并且将其储存到数据库。那四回,save
create 方法的分别是 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();

相关文章