源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

laravel学习教程之关联模型

  • 时间:2022-03-21 05:39 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:laravel学习教程之关联模型
[b]Eloquent: 关联模型[/b] [b]简介[/b] 数据库中的表经常性的关联其它的表。比如,一个博客文章可以有很多的评论,或者一个订单会关联一个用户。Eloquent 使管理和协作这些关系变的非常的容易,并且支持多种不同类型的关联: [b]    一对一 [/b] [b]    一对多[/b] [b]    多对多[/b] [b]    远程一对多 [/b] [b]    多态关联[/b] [b]    多态多对多关联[/b] [b]定义关联[/b] Eloquent 关联可以像定义方法一样在 Eloquent 模型类中进行定义。同时,它就像 Eloquent 模型自身一样也提供了强大的查询生成器。这允许关联模型可以链式的执行查询能力。比如:
$user->posts()->where('active', 1)->get();
但是,在更深入的使用关联之前,让我们先来学习一下如何定义各种类型的关联。 [b]一对一[/b] 一对一的关联是最基础的关联。比如,一个 [code]User [/code]模型可能关联一个 [code]Phone[/code]。我们需要在 [code]User [/code]模型上放置一个 [code]phone [/code]方法来定义这种关联。[code]phone [/code]方法应该返回一个基类 Eloquent 模型上 [code]hasOne [/code]方法的结果:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class User extends Model
{
 /**
  * Get the phone record associated with the user.
  */
 public function phone()
 {
  return $this->hasOne('AppPhone');
 }
}
传递到 [code]hasOne [/code]方法的第一个参数应该是关联模型的名称。一旦关联被定义完成,我们可以使用 Eloquent 的动态属性来访问关联模型的记录。动态属性允许你访问关联函数,就像是它们是定义在模型中的属性一样:
$phone = User::find(1)->phone;
Eloquent 假定所关联的外键是基于模型的名称的。在这个前提下,[code]Phone [/code]模型会自动的假定其拥有一个 [code]user_id [/code]外键。如果你希望修改这个惯例,你可以传递第二个参数到 [code]hasOne [/code]方法中:
return $this->hasOne('AppPhone', 'foreign_key');
另外,Eloquent 也会假定外键应该在其上层模型上拥有一个匹配的 [code]id[/code](或者自定义的 [code]$primaryKey[/code])值。换句话说,Eloquent 会查询 [code]Phone [/code]记录中的 [code]user_id[/code] 列所对应的用户的 [code]id [/code]列的记录。如果你希望关联使用 [code]id [/code]以外的值,你可以传递第三个参数到 [code]hasOne [/code]方法来指定自定义的键:
return $this->hasOne('AppPhone', 'foreign_key', 'local_key');
[b]定义相对的关联[/b] 那么,我们可以从我们的 [code]User [/code]中访问 [code]Phone [/code]模型。现在,让我们在 [code]Phone [/code]模型上定义一个关联,让我们可以从 [code]Phone [/code]模型中访问其所属的 [code]User[/code]。我们使用 [code]belongsTo [/code]方法来定义 [code]hasOne [/code]相对的关联:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Phone extends Model
{
 /**
  * Get the user that owns the phone.
  */
 public function user()
 {
  return $this->belongsTo('AppUser');
 }
}
在上面的例子中,Eloquent 将会尝试从 [code]Phone [/code]模型中的 [code]user_id [/code]字段中匹配查找 [code]id [/code]相同的 [code]User[/code]。[code]Eloquent [/code]会依据所关联的模型的蛇形命名和 [code]_id[/code] 来假定默认的外键名。事实上,如果在 [code]Phone [/code]模型上的外键不是 [code]user_id[/code],那么你可以传递自定义的外键名到 [code]belongsTo [/code]方法的第二个参数:
/**
 * Get the user that owns the phone.
 */
public function user()
{
 return $this->belongsTo('AppUser', 'foreign_key');
}
如果你的上级模型并没有使用 [code]id [/code]作为主键名,或者你希望下级模型关联一个不同的列。你可以传递第三个参数到 [code]belongsTo [/code]方法来指定上级模型表中的自定义键:
/**
 * Get the user that owns the phone.
 */
public function user()
{
 return $this->belongsTo('AppUser', 'foreign_key', 'other_key');
}
[b]一对多[/b] 一个一对多的关联常常用来定义一个模型拥有其他任意数目的模型。比如,一个博客文章可以拥有很多条评论。就像其他的 Eloquent 关联一样,一对多关联在 Eloquent 模型中通过方法来进行定义:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Post extends Model
{
 /**
  * Get the comments for the blog post.
  */
 public function comments()
 {
  return $this->hasMany('AppComment');
 }
}
记住,Eloquent 会自动的根据 [code]Comment [/code]模型来判断合适的外键。依据惯例,[code]Eloquent [/code]会使用自身模型的蛇形命名和[code] _id [/code]来作为外键。所以,在这个例子中,[code]Eloquent [/code]会假定 [code]Comment [/code]模型的外键是 [code]post_id[/code]。 一旦关联定义完成之后,我们可以通过 [code]comments [/code]属性来访问所有关联的评论的集合。记住,由于 [code]Eloquent [/code]提供了动态属性,我们可以对关联函数进行访问,就像他们是在模型中定义的属性一样:
$comments = AppPost::find(1)->comments;

foreach ($comments as $comment) {
 //
}
当然,由于所有的关联都提供了查询生成器的功能,所以你可以在调用 [code]comments [/code]方法时继续的添加一些限制条件,你可以通过链式的调用进行查询条件的添加:
$comments = AppPost::find(1)->comments()->where('title', 'foo')->first();
就像 [code]hasOne [/code]方法,你可以通过添加额外的参数到 [code]hasMany [/code]方法中来重置外键和主键:
return $this->hasMany('AppComment', 'foreign_key');

return $this->hasMany('AppComment', 'foreign_key', 'local_key');
[b]定义相对的关联[/b] 现在我们可以访问文章中所有的评论了,让我们为评论定义一个关联使其可以访问它的上层文章模型。为了定义一个 [code]hasMany [/code]相对的关联,你需要在下层模型中定义一个关联方法并调用 [code]belongsTo [/code]方法:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Comment extends Model
{
 /**
  * Get the post that owns the comment.
  */
 public function post()
 {
  return $this->belongsTo('AppPost');
 }
}
一旦关联被定义完成,我们就可以通过 [code]Comment [/code]模型的 [code]post [/code]动态属性来检索到其对应的 [code]Post [/code]模型:
$comment = AppComment::find(1);

echo $comment->post->title;
在上面的例子中,[code]Eloquent [/code]会尝试从 [code]Comment [/code]模型中的 [code]post_id [/code]字段检索与其相对应 [code]id [/code]的 [code]Post [/code]模型。[code]Eloquent [/code]会使用关联模型的蛇形命名和[code] _id[/code] 来作为默认的外键。如果 [code]Comment [/code]模型的外键不是 [code]post_id[/code],你可以传递一个自定义的键名到 [code]belongsTo [/code]方法的第二个参数:
/**
 * Get the post that owns the comment.
 */
public function post()
{
 return $this->belongsTo('AppPost', 'foreign_key');
}
如果上层模型并没有使用 id 作为主键,或者你想在下层模型中关联其他的列,你可以传递第三个参数到 belongsTo 方法中:
/**
 * Get the post that owns the comment.
 */
public function post()
{
 return $this->belongsTo('AppPost', 'foreign_key', 'other_key');
}
[b]多对多 [/b] 多对多的关联比 [code]hasOne [/code]和 [code]hasMany [/code]关联要稍微复杂一些。假如一个用户拥有多个角色,而角色又可以被其他的用户所共享。比如,多个用户可以拥有管理员的角色。如果定义这种关联,我们需要定义三个数据库表:[code]users[/code],[code]roles[/code],和 [code]role_user[/code]。[code]role_user[/code] 表的命名是以相关联的两个模型数据表来依照字母顺序命名,并且表中包含了 [code]user_id [/code]和 [code]role_id [/code]列。 多对多关联需要编写一个方法调用基础 [code]Eloquent [/code]类 [code]belongsToMany [/code]方法。比如,让我们在 [code]User [/code]模型中定义一个 [code]roles [/code]方法:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class User extends Model
{
 /**
  * The roles that belong to the user.
  */
 public function roles()
 {
  return $this->belongsToMany('AppRole');
 }
}
一旦关联被定义,你可以通过 [code]roles [/code]动态属性来访问用户的角色:
$user = AppUser::find(1);

foreach ($user->roles as $role) {
 //
}
当然,就像其他类型的关联,你可以调用 [code]roles [/code]方法并且链式调用查询条件:
$roles = AppUser::find(1)->roles()->orderBy('name')->get();
就如先前所提到的,Eloquent 会合并两个关联模型并依照字母顺序进行命名。当然你也可以随意的重写这个约定,你可以传递第二个参数到 [code]belongsToMany [/code]方法:
return $this->belongsToMany('AppRole', 'role_user');
除了自定义合并数据表的名称之外,你也可以通过往 [code]belongsToMany [/code]方法传传递额外参数来自定义数据表里的键的字段名称。第三个参数是你定义在关联中模型外键的名称。第四个参数则是你要合并的模型外键的名称:
return $this->belongsToMany('AppRole', 'role_user', 'user_id', 'role_id');
[b]定义相对关联[/b] 你只需要在相对应的关联模型里放置其他的方法来调用 [code]belongsToMany [/code]方法就可以定义相对关联。继续我们上面的用户角色示例,让我们在 [code]Role [/code]模型中定义一个 [code]users [/code]方法:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Role extends Model
{
 /**
  * The users that belongs to the role.
  */
 public function users()
 {
  return $this->belongsToMany('AppUser');
 }
}
就如你所看到的,这个关联的定义与用户的关联定义完全相同。因为我们重复的使用了 [code]belongsToMany [/code]方法,当定义相对于多对多的关联时,所有常用的自定义数据表和键的选项都是可用的。 [b]检索中间表字段[/b] 正如你已经了解到的。定义多对多的关联需要引入一个中间表。Eloquent 提供了几种非常有帮助的方式来与这个表进行交互。比如,让我们假定我们的 [code]User [/code]对象关联到了很多 [code]Role [/code]对象。在访问这些关联对象时,我们可以通过在模型上使用 [code]pivot [/code]属性来访问中间表:
$user = AppUser::find(1);

foreach ($user->roles as $role) {
 echo $role->pivot->created_at;
}
注意我们取出的每个 [code]Role [/code]对象,都会被自动的分配 [code]pivot [/code]属性。这个属性包含了一个代表中间表的模型,并且可以像其他 Eloquent 模型一样被使用。 默认的,只有模型的键会被 [code]pivot [/code]对象提供,如果你的中间表包含了额外的属性,你必须在定义关联时指定它们:
return $this->belongsToMany('AppRole')->withPivot('column1', 'column2');
如果你想要中间表自动维护 [code]created_at [/code]和 [code]updated_at [/code]时间戳,你可以在定义关联时使用 [code]withTimestamps [/code]方法:
return $this->belongsToMany('AppRole')->withTimestamps();
[b]通过中间表字段过滤关系[/b] 你可以通过在定义关联时使用 [code]wherePrivot [/code]和 [code]wherePivotIn [/code]方法来在返回的结果中进行过滤:
return $this->belongsToMany('AppRole')->wherePivot('approved', 1);

return $this->belongsToMany('AppRole')->wherePivotIn('approved', [1, 2]);
[b]远程一对多[/b] 远程一对多关联提供了简短便捷的方法通过中间关联件来访问远端的关联。比如,一个 [code]Country [/code]模型应该通过 [code]User [/code]模型可以拥有很多的 [code]Post [/code]模型。在这个例子中,你可以非常容易的就检索出一个国家中的所有的文章。让我们来看一下定义这些关联所需要的表:
countries
 id - integer
 name - string

users
 id - integer
 country_id - integer
 name - string

posts
 id - integer
 user_id - integer
 title - string
远端的 [code]posts [/code]并没有包含 [code]country_id [/code]列,[code]hasManyThrough [/code]关联可以通过 [code]$country->posts [/code]来访问一个国家的文章。为了执行这个查询,[code]Eloquent [/code]会通过中间表 [code]users [/code]的 [code]country_id [/code]来检索 [code]posts [/code]表中用户 ID 相匹配的记录。 现在我们已经明确了关联表的结构,那么让我们来在 Country 模型上定义关联:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Country extends Model
{
 /**
  * Get all of the posts for the country.
  */
 public function posts()
 {
  return $this->hasManyThrough('AppPost', 'AppUser');
 }
}
传递到 [code]hasManyThrough [/code]方法的第一个参数是我们最终想要访问到的模型,而第二个参数则是中间层的模型名称。 当使用关联查询时,通常 Eloquent 会遵循外键约定。如果你希望对关联的键进行自定义,你可以传递第三和第四个参数到 [code]hasManyThrough [/code]方法。第三个参数是中间层模型的外键名称,第四个参数是最终想要获取的模型中的所对应的中间层的外键, 而第五个参数则是当前模型的主键:
class Country extends Model
{
 public function posts()
 {
  return $this->hasManyThrough(
   'AppPost', 'AppUser',
   'country_id', 'user_id', 'id'
  );
 }
}
[b]多态关联[/b] [b]表结构[/b] 多态关联允许一个模型在单个关联中从属一个或多个其它模型。比如,想象一下应用中的用户可以喜欢文章及其评论。如果使用多态关联,那么你就可以使用一个单独的 [code]likes [/code]表来关联这两个场景。首先,让我们确定定义这种关联所需要的表结构:
posts
 id - integer
 title - string
 body - text

comments
 id - integer
 post_id - integer
 body - text

likes
 id - integer
 likeable_id - integer
 likeable_type - string
你需要注意到的两个在 [code]likes [/code]表中重要的字段 [code]likeable_id [/code]和 [code]likeable_type[/code]。[code]likeable_id[/code] 字段会包含文章或者评论的 ID 值,而 [code]likeable_type[/code] 字段会包含其所属的模型的类名。[code]likeable_type[/code] 就是当访问 [code]likeable [/code]关联时 ORM 用来判断所属的模型是哪个类型。 [b]模型结构[/b] 接着,让我们检查一下这个关联所需要的模型定义:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

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('AppLike', 'likeable');
 }
}

class Comment extends Model
{
 /**
  * Get all of the comment's likes.
  */
 public function likes()
 {
  return $this->morphMany('AppLike', 'likeable');
 }
}
[b]获取多态关联[/b] 一旦数据库表和模型都定义完成,你就可以在你的模型中访问这些关联。比如,你可以使用 [code]likes [/code]动态属性来访问文章中所有关联的 [code]likes [/code]模型:
$post = AppPost::find(1);

foreach ($post->likes as $like) {
 //
}
你也可以通过在模型上调用提供 [code]morphTo [/code]的方法来获取多态模型其关系所有者。在上面的例子中,指的就是 [code]Like [/code]模型中的 [code]likeable [/code]方法。所以,我们可以像使用动态属性一样使用方法来进行访问:
$like = AppLike::find(1);

$likeable = $like->likeable;
[code]Like [/code]模型的 [code]likeable [/code]关联将会返回一个 [code]Post [/code]或者 [code]Comment [/code]实例,这取决于其所属者的类型。 [b]自定义多态类型[/b] 默认的,Laravel 会使用包完全限定类名来存储所关联模型的类型。比如,上面的例子中 [code]Like [/code]可以属于 [code]Post [/code]或者 [code]Comment[/code]。默认的 [code]likeable_type[/code] 应该是 [code]AppPost [/code]或者 [code]AppComment[/code]。事实上,你可能希望从你的应用程序的内部结构分离数据库。在这个例子中,你可以定义一个关联的多态映射来指导 Eloquent 使用模型关联的表名称来替代类名:
use IlluminateDatabaseEloquentRelationsRelation;

Relation::morphMap([
 AppPost::class,
 AppComment::class,
]);
或者,你可以指定一个自定的字符串与每个模型进行关联:
use IlluminateDatabaseEloquentRelationsRelation;

Relation::morphMap([
 'posts' => AppPost::class,
 'likes' => AppLike::class,
]);
你可以在你的 [code]AppServiceProvider [/code]或者一个分离的服务提供者的 [code]boot [/code]方法中注册你的 [code]morphMap[/code]。 [b]多态多对多关联[/b] [b]表结构[/b] 除了传统的多态关联,你也可以定义多对多的多态关联。比如,一个博客的 [code]Post [/code]和 [code]Video [/code]模型应该可以共享一个多态关联的 [code]Tag [/code]模型。使用多对多的多态关联可以允许你的博客文章和视频能够共享独特标签的单个列表。首先,让我们来看一下表结构:
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
[b]模型结构[/b] 接着,我们来定义模型中的关联。[code]Post [/code]和 [code]Video [/code]模型将都会包含调用基础 [code]Eloquent [/code]类的 [code]morphToMany [/code]方法的 [code]tags [/code]方法:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Post extends Model
{
 /**
  * Get all of the tags for the post.
  */
 public function tags()
 {
  return $this->morphToMany('AppTag', 'taggable');
 }
}
[b]定义相对的关联[/b] 接着,在 [code]Tag [/code]模型中,你应该为所有关联模型定义相应的方法。所以,在这个例子中,我们将定义 [code]posts [/code]方法和 [code]videos [/code]方法:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

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

 /**
  * Get all of the videos that are assigned this tag.
  */
 public function videos()
 {
  return $this->morphedByMany('AppVideo', 'taggable');
 }
}
[b]获取关联[/b] 当定义完成数据表和模型之后,你就可以通过模型来访问其关联。比如,你可以简单的使用 [code]tags [/code]动态属性来访问文章的所有标签模型:
$post = AppPost::find(1);

foreach ($post->tags as $tag) {
 //
}
你也可以通过访问模型中提供执行 [code]morphedByMany [/code]方法的方法来获取关联模型的所属模型。在上面的例子中,就是 [code]Tag [/code]模型上的 [code]posts [/code]或者 [code]videos [/code]方法。所以,你可以像动态属性一样访问这些方法:
$tab = AppTag::find(1);

foreach ($tag->videos as $video) {
 //
}
[b]关联查询[/b] 由于所有的 Eloquent 关联类型都是通过方法定义的,所以你可以调用这些方法来获取所关联的模型的实例而无需实际的执行关联查询。另外,所有的 Eloquent 关联也都提供了查询生成器服务,这允许你可以继续的链式执行查询操作。 比如,想象一下博客系统中 [code]User [/code]模型拥有很多 [code]Post [/code]关联的模型:
<?ph

namespace App;

use IlluminateDatabaseEloquentModel;

class User extends Model
{
 /**
  * Get all of the posts for the user.
  */
 public function posts()
 {
  return $this->hasMany('AppPost');
 }
}
你可以查询 [code]posts [/code]关联的同时添加一些额外的查询约束:
$user = AppUser::find(1);

$user->posts()->where('active', 1)->get();
你应该注意到了,你可以在关联中使用任何的查询生成器的方法。 [b]关联方法 Vs. 动态属性[/b] 如果你不需要在进行 Eloquent 关联查询时添加额外的约束,你可以简单的像它的属性一样进行访问。比如,我们继续使用 [code]User [/code]和 [code]Post [/code]示例模型。我们可以像这样来访问用户的所有文章:
$user = AppUser::find(1);

foreach ($user->posts as $post) {
 //
}
动态属性是惰性加载的,这意味着在你实际访问他们之前,其关联数据是不会加载的。正因为如此,开发的时候通常使用预加载来进行加载一些即将用到的关联模型。预加载要求必须加载一个模型的关系,这有效的减少了查询的次数。 [b]查询关联是否存在[/b] 当访问一个模型的记录时,你可能会希望基于关联的记录是否存在来对结果进行限制。比如,想象一下你希望获取最少有一条评论的博客文章。你可以传递关联的名称到 [code]has [/code]方法来做这些:
// Retrieve all posts that have at least one comment...
$posts = AppPost::has('comments')->get();
你也可以指定操作符,和数量来进一步定制查询:
// Retrieve all posts that have three or more comments...
$posts = Post::has('comments', '>=', 3)->get();
你也可以使用 . 语法来构造嵌套的 [code]has [/code]语句。比如,你可以获取所有包含至少一条评论和投票的文章:
// Retrieve all posts that hava at least one comment with votes...
$posts = Post::has('comments.votes')->get();
如果你需要更高的控制,你可以使用 [code]whereHas [/code]和 [code]orWhereHas [/code]方法来在 [code]has [/code]查询中插入 [code]where [/code]子句。这些方法允许你为关联进行自定义的约束查询。比如检查评论的内容:
// Retrieve all posts with at least one comment containing words like foo%
$posts = Post::whereHas('comments', function ($query) {
 $query->where('content', 'like', 'foo%'); 
})->get();
[b]统计关联结果[/b] 如果你希望统计关联的结果而不实际的加载它们,你可以使用 [code]withCount [/code]方法,这将在你的结果模型中添加[code] {relation}_count[/code] 列。比如:
$posts = AppPost::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;
[b]预加载[/b] 当通过属性访问 Eloquent 关联时,该关联的数据会被延迟加载。这意味着该关联数据只有在你真实的访问属性时才会进行加载。事实上,Eloquent 可以在上层模型中一次性预加载的。预加载有效避免了 N + 1 的查找问题。要说明 N + 1 查找问题,我们可以来看一个 [code]Author [/code]关联 [code]Book [/code]的示例:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Book extends Model
{
 /**
  * Get the author that wrote the book.
  */
 public function author()
 {
  return $this->belongsTo('AppAuthor');
 }
}
现在,让我们检索所有的书籍和他们的作者:
$books = AppBook::all();

foreach ($books as $book) {
 echo $book->author->name;
}
这个循环会执行一次查找回所有的书籍,接着每本书会运行一次查找作者的操作。所以,如果我们拥有 25 本书,那么循环将会进行 26 次查询:1 次查询所有的书籍,25 次查询相关书籍的作者。 非常幸运的,我们可以使用预加载来将查询有效的控制在 2 次。当查询时,使用 [code]with [/code]方法来指定关联的预加载:
$books = AppBook::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, ...)
[b]预加载多个关联[/b] 有时候你可能需要在一个操作中预加载多个关联,你只需要传递额外的参数到 [code]with [/code]方法中就可以:
$books = AppBook::with('author', 'publisher')->get();
[b]嵌套的预加载[/b] 你可以使用 . 语法来加载嵌套的关联。比如,让我们在一个 Eloquent 语句中一次加载所有书籍的作者以及作者的死人通讯簿:
$books = AppBook::with('author.contacts')->get();
[b]预加载约束[/b] 有时候你可能希望预加载一些关联,但是也需要对预加载查询指定额外的约束,这里有个示例:
$users = AppUser::with(['posts' => function ($query) {
 $query->where('title', 'like', '%first%');
}])->get();
在这个例子中,[code]Eloquent [/code]会值预加载文章的 [code]title [/code]列包含 [code]first [/code]单词的记录。当然,你也可以调用其他查询生成器可用的方法:
$users = AppUser::with(['posts' => function ($query) {
 $query->orderBy('created_at', 'desc');
}])->get();
[b]延迟预加载[/b] 有时候你可能需要在上层模型被获取后才预加载其关联。当你需要来动态决定是否加载关联模型时尤其有用:
$books = AppBook::all();

if ($someCondition) {
 $books->load('author', 'publisher');
}
如果你需要对预加载做一些查询约束,你可以传递 [code]Closure [/code]到 [code]load [/code]方法:
$books->load(['author' => function ($query) {
 $query->orderBy('published_date', 'asc');
}]);
[b]插入关系模型[/b] [b]Save 方法[/b] [code]Eloquent [/code]提供了方便的方法来为模型添加一个关联。比如,也许你需要为 [code]Post[/code] 模型新增一个 [code]Comment[/code]。除了手动的设置 [code]Comment [/code]的 [code]post_id [/code]属性,你也可以直接在关联模型中调用 [code]save [/code]方法来插入 [code]Comment[/code]:
$comment = new AppComment(['message' => 'A new comment.']);

$post = AppPost::find(1);

$post->comments()->save($comment);
注意上面我们并没有使用关联模型的动态属性的方式来访问 [code]comments[/code],而是使用 [code]comments [/code]方法的形式来获取关联模型的实例。[code]save [/code]方法会自动的添加相应的 [code]post_id [/code]值到新的 [code]Comment [/code]模型上。 如果你需要一次添加多个关联模型,你需要使用 [code]saveMany[/code] 方法:
$post = AppPost::find(1);

$post->comments()->saveMany([
 new AppComment(['message' => 'A new comment.']),
 new AppComment(['message' => 'Another comment.']),
]);
[b]Save & 多对多关联[/b] 当与多对多关联互动时,[code]save[/code] 方法接收一个中间层表属性的额外参数数组作为第二个参数:
AppUser::find(1)->roles()->save($role, ['expires' => $expires]);
[b]Create 方法[/b] 除了 [code]save [/code]和 [code]saveMany[/code] 方法之外,你也可以使用 [code]create[/code] 方法,它可以接收属性组成的数组,创建一个模型并且将其存储到数据库。这一次,[code]save[/code] 和 [code]create[/code] 方法的区别是 [code]save [/code]接收一个完整的 [code]Eloquent[/code] 模型实例,而 [code]create [/code]接收的是一个原生的 PHP [code]array[/code]:
$post = AppPost::find(1);

$comment = $post->comments()->create([
 'message' => 'A new comment.',
]);
在使用 [code]create [/code]方法之前,你应该确保已经阅读了属性的 批量赋值文档。 [b]更新从属关联模型[/b] 当更新一个 [code]belongsTo[/code] 关联时,你应该使用 [code]associate [/code]方法。这个方法会在下层模型中设置外键:
$account = AppAccount::find(10);

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

$user->save();
当删除 [code]belongsTo[/code] 关联时,你应该使用 [code]dissociate [/code]方法,该方法会重置下层模型所关联的外键:
$user->account()->dissociate();

$user->save();
[b]多对多关联[/b] [b]附加 / 抽离[/b] 当使用多对多关联时,Eloquent 提供了一些额外的帮助方法来更方便的管理关联模型。比如,让我们想象一下用户可以有很多角色并且角色可以有很多用户。你可以使用 [code]attach [/code]方法来附加一个角色到用户并且在中间表中加入这条记录:
$user = AppUser::find(1);

$user->roles()->attach($roleId);
当附加关联到模型时,你也可以传递一个含有额外数据的数组来将其添加到中间表中:
$user->roles()->attach($roleId, ['expires' => $expires]);
当然,有时候你可能需要从用户中删除一个角色。你可以使用 [code]detach[/code] 方法来删除多对多关联的记录。[code]datech[/code] 方法将从中间表中删除相应的记录。但是,除了中间表,其它两个模型的记录都还会被保留:
// Detach a single role from the user...
$user->roles()->detach($roleId);

// Detach all roles from the user...
$user->roles()->detach();
为了更加的便捷,[code]attach[/code] 和 [code]detach[/code] 也可以接收 IDs 所组成的数组作为输入:
$user = AppUser::find(1);

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

$user->roles()->attach([1 => ['expires' => $expires], 2, 3]);
[b]更新中间表的记录[/b] 如果你需要更新中间表中存在的行,你可以使用 [code]updateExistingPivot [/code]方法:
$user = AppUser::find(1);

$user->roles()->updateExistingPivot($roleId, $attributes);
[b]便利的同步[/b] 你也可以使用 [code]sync [/code]方法来构建多对多的关联。[code]sync[/code] 方法接收放置中间表 IDs 所组成的数组。任意 IDs 如果没有在所给定的数组中,那么其将会从中间表中进行删除。所以,在操作完成之后,只有存在于给定数组里的 IDs 才会存在于中间表中:
$user->roles()->sync([1, 2, 3]);
你也可以同时传递额外的中间表的键值对:
$user->roles()->sync([1 => ['expires' => true], 2, 3]);
[b]联动上层模型时间戳[/b] 当一个模型 [code]belongsTo[/code] 或者[code] belongsToMany [/code]另外一个模型时,比如[code] Comment [/code]从属于[code] Post[/code],这对下层模型更新时同时要求更新上层模型的时间戳时很有帮助。比如,当 [code]Comment [/code]模型更新了,你想要自动的更新其所属的 [code]Post[/code] 模型的 [code]updated_at [/code]时间戳。[code]Eloquent [/code]使之变的非常容易。你只需要在下层模型中添加一个 [code]touches[/code] 属性来包含关联的名称就可以了:
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

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('AppPost');
 }
}
现在,当你更新[code] Comment [/code]时,其所属的 [code]Post [/code]将会同时更新[code] updated_at [/code]列:
$comment = AppComment::find(1);

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

$comment->save();
以上就是laravel学习教程之关联模型的全部内容,希望对大家学习php有所帮助。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部