模型关联

Eloquent关联在模型中以方法的形式呈现,提供了强大的链式调用和查询功能。可以分为一对一、一对多、多对多、远程一对多、多态一对一、多态一对多、多态多对多、自定义几种。


一对一

用户 User 和手机 Phone 是关联模型,用户拥有手机,手机属于用户。

关联

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model
{//获取用户关联的手机public function phone(){return $this->hasOne('App\Phone');}
}

一旦定义了关联,就可以使用Eloquent的动态属性获取相关的记录,如下:

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

Eloquent会基于模型决定外键名称,会自动假设 Phone 模型有一个 user_id 字段,如果想要覆盖这个决定,可以传递 hasOne 第二个参数,如下:

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

如果Eloquent外键值与父级id不匹配,可以传递 hasOne 第三个参数,如下:

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

反向关联

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Phone extends Model
{//获得拥有此手机的用户public function user(){return $this->belongsTo('App\User');}
}

一对多

文章 Post 和评论 Comment 是关联模型,对一篇文章可以发表很多评论。

关联

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Post extends Model
{//获取文章的评论public function comments(){return $this->hasMany('App\Comment');}
}

访问 Post 文章的 comments 的属性获取评论的集合,如下:

 $comments = App\Comment::find(1)->comments();foreach ( $comments as $comment) {//}

还可以添加过滤,如下:

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

反向关联

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Comment extends Model
{//获取评论所属文章public function post(){return $this->belongsTo('App\Post');}
}

定义好之后,可以通过 Comment 模型的 post 动态属性来访问,如下:

$comment = App\Comment::find(1);
echo $comment->post->title;

多对多

用户 User ,角色 Role (中间模型为 UserRole )模型可以认为是多对多关联,用户可以有多个角色,每个角色可以为多个用户所有。对应的数据分别为 usersrolesrole_user 。其中 role_user 是按两个模型字母排序,包含 user_idrole_id 两个字段。

关联

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model
{//用户的角色public funciton 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();

如果关联表名不符合默认规则,可以传递 belongsToMany 第二个参数,如下:

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

如果关联表两个字段不符合默认规则,可以传递 belongsToMany 第三个、第四个参数,如下:

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

定义反向关联

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Role extends Model
{//拥有此角色的用户public function users(){return $this->belongsToMany('App\User');}
}

取中间表字段

在获取关联对象后,可以使用模型的 pivot 访问中间表数据,如下:

$user = App\User::find(1);
foreach ( $user->roles as $role ) {echo $role->pivot->created_at;
}

默认情况下,pivot 只包含了两个模型的主键,如果中间表还有其它的字段,需要在关联时明确指出,如下:

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

如果想自动维护中间表的 created_atupdated_at 时间戳,需在关联时附加 withTimestamps 方法:

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

自定义中间表模型

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Role extends Model
{public function users(){return $this->belongsToMany('App\User')->using('App\UserRole');}
}

自定义时 UserRole 模型,如下:

<?phpnamespace App;use Illuminate\Database\Eloquent\Relations/Pivot;class UserRole extends Pivot
{//...
}

远程一对多

国家 Country 有很多用户 User , 用户有很多博客 Post,对应的数据表结构如下:

countriesid:主键idname:国家名称...
usersid:主键idcountry_id:国家idname:姓名...
postsid:主键iduser_id:用户idtitle:博客题目...

代码实现:

<?phpnamespace App;use Illuminate\Database\Eloquent\Modell;class Country extends Model
{//获取一个国家下所有的博客public function posts(){return $this->hasManyThrough('App\Post', ‘App\User');}
}

当之后的参数不符合默认规则时,需要传递对应的参数,如下:

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

多态一对一

一对一的多态关联类似于简单的一对一关联,但目标模型在当个关联上属于多个其它模型。博客 Post ,用户 User 共享与图像 Image 模型的多态一对一关联。

数据表结构

postsid:主键title:标题body:文章内容...
usersid:主键title:姓名url:头像...
imagesid:主键body:图片imageable_id:关联主键imageable_type:关联模型...

imagesimageable_id 存储博客或用户id,imageable_type 存储所属模型的类名。imageable_type 来决定我们访问关联模型时,要返回的父模型的类型。

模型结构

<?phpuse Illuminate\Database\Eloquent\Model;class Image extends Model
{//获取此图像所属的模型public function imageable(){return $this->morphTo();}
}class Post extends Model
{//获取此博客的图像public function image(){return $this->morphOne('App\Image', 'imageable');}
}class User extends Model
{//获取此用户的图像public function image(){return $this->morphOne('App\Image', 'imageable');}
}

获取多态关联

$posts = App\Post::find(1);
$image = $posts->image;$image = App\Image::find(1);
$imageable = $image->imageable;

多态一对多

一对多的多态关联类似于简单的一对多关联,但目标在单个模型上可以属于多个其它模型。文章 Post 和视频 video 的评论 comment 可以看作是一个一对多的多态关联。

数据表结构

postsid:主键...
videosid:主键...
commentsid:主键commentable_idcommentable_type...

comments 数据表 commentable_id 字段存储文章或视频的主键,commentable_type 存储所属模型的类名。commentable_type 来决定我们访问关联模型时,返回父模型的类型。

模型结构

<?phpuse Illuminate\Database\Eloquent\Model;class Comment extends Model
{//获取拥有此评论的模型public function commentable(){return $this->morphTo();}
}class Post extends Model
{//获取此文章的所有评论public function comments(){return $this->morphMany('App\Comment', 'commentable');}
}class Video extends Model
{//获取此视频的评论public function comments(){return $this->morphMany('App\Comment', 'commentable');}
}

获取多态关联

$posts = App\Post::find(1);
foreach ($posts->comments as $comment)
{//
}$comment = App\Comment::find(1);
$commentable = $comment->commentable;

多态多对多

文章 Post 和视频 Video 共享标签 Tag 模型。

数据表结构

postsid:主键...
videosid:主键...
tagsid:主键...
taggablestag_id:标签IDtaggable_id:关联模型IDtaggable_type:关联模型类名...

模型结构

<?phpuse Illuminate\Database\Eloquent\Model;class Post extends Model
{//获取文章标签public function tags(){return $this->morphToMany('App\Tag', ''taggable);}
}class Video extends Model
{//获取视频标签public function tags(){return $this->morphToMany('App\Tag', 'taggable');}
}class Tag extends Model
{//获取拥有此标签的文章public function posts(){return $this->morphedByMany('App\Post', 'taggable');}//获取拥有此标签的视频public function videos(){return $this->morphedByMany('App\Video', 'taggable');}
}

获取关联

$post = App\Post::find(1);
foreach ($post->tags as $tag)
{//
}$tag = App\Tag::find(1);
foreach($tag->videos as $video)
{//
}

查询关联关系是否存在

//获取至少有一条评论的文章
$posts = App\Post::has('comments')->get();//获取至少有三条评论的文章
$posts = App\Post::has('comments', '>=', 3)->get();//获取有一条评论的文章,并加载评论的投票信息
$posts = App\Post::has('comments.votes')->get();//获取至少有一条评论的文章,并且以foo开头
$posts = App\Post::whereHas(function ($query) {$query->where('content', 'like', 'foo%');
})->get();

关联计数

$posts = App\Post::withCount('comments')->get();
foreach ($posts as $post)
{echo $post->comments_count;
}$posts = App\Post::withCount('votes', 'comments' => function ($query) {$query->where('content', 'like', 'foo%');
})->get();
echo $posts[0]->votes_count;
echo $posts[0]->comments_count;$posts = App\Post::withCount(['comments','comments as pending_comments_count'  => function ($query) {$query->where('approved', false);})])->get();
echo $posts[0]->comments_count;
echo $posts[0]->pending_comments_count;$posts = App\Post::select(['title','body'])->withCount('comments')->get();
echo $posts[0]->title;
echo $posts[0]->body;
echo $posts[0]->comments_count;

插入更新关联模型

保存方法

添加一个 Comment 到博客 *** Post*** 模型,可以不用在 Comment 中设置 post_id 属性,使用关联模型的 save 方法将 Comment 直接插入,如下:

$comment = new App\Comment(['message' => 'a message comment’]);
$post = App\Post::find(1);
$post->comments->save($comment);

如需要保存多个关联模型,可以使用 saveMany 方法,如下:

$post = App\Post::find(1);
$post->comments()->saveMany([new App\Comment(['message' => 'a comment']),new App\Comment(['message' => 'b comment'])
});

新增方法

create 方法接收普通的php数组,如下:

$post = App\Post::find(1);
$comment = $post->comments->create(['message' => 'a new comment'
});

createMany 可以创建多个关联模型:

$post = App\Post::find(1);
$post->comments->createMany([['message' => 'a new comment'],['message' => 'a new comment']
]);

更新belongsTo关联

当更新 belongsTo 关联时,可以使用 associate 方法。此方法将会在子模型中设置外键。

$account = App\Account(1);
$user->account->associate($account);
$user->save();

当移除 belongsTo 关联时,可以使用 dissociate 方法。此方法会将关联外键设置为 null

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

默认模型

belongsTo 关系允许指定默认模型,当给定关系为 null 时,将会返回默认模型。

//获取博客的作者
public function user()
{return $this->belongsTo('App\User')->withDefault();
}

如果需要在默认模型里添加属性,可以传递数组或回调方法到 withDefault 方法中,如下:

//获取博客的作者
public function user()
{return $this->belongsTo('App\User')->withDefault(['name' => 'Guest Author']);
}public function user()
{return $this->belongsTo('App\User')->withDefault(function ($user) {$user->name = 'Guest Author';});
}

多对多关联

附加/分离

给某个用户添加一个角色是通过向中间表插入一条记录实现的,可以使用 attach 方法,如下:

$user = App\User::find(1);
$user->roles()->attach($roleId);

在将关系附加到模型时,还可以传递一组要插入中间表的附加数据,如下:

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

移除用户的角色,使用 detach 移除多对多关联记录,如下:

//移除用户的一个角色
$user->roles()->detach($roleId);//移除用户的所有角色
$user->roles()->detach();

为了方便,attachdetach 允许传递一个id数组,如下:

$user = App\User::find(1);
$user->roles()->detach([1,2,3]);
$user->roles()->attach([1 => ['expires' => $expires],2 => ['expires' => $expires]
]);

同步关联

sync 接收id数组以替换中间表的记录,所有未在id数组中的记录都会被移除,如下:

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

可以传递额外的附加数据到中间表,如下:

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

如果不想移除现有的id,可以使用 syncWithoutDetaching 方法,如下:

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

Laravel Eloquent 关联相关推荐

  1. Laravel Eloquent关联模型查询设置查询条件与指定字段

    我的个人博客:逐步前行STEP 1.直接获取关联模型: 1)在get中指定字段: $user->posts()->where('created_at','>',date('Y-m-d ...

  2. 深入理解 Laravel Eloquent(三)——模型间关系(关联)

    Eloquent是什么 Eloquent 是一个 ORM,全称为 Object Relational Mapping,翻译为 "对象关系映射"(如果只把它当成 Database A ...

  3. Laravel Eloquent 小技巧

    1. 获取原始属性 当修改一条Eloquent 模型记录的时候你可以通过调用getOriginal()方法获取记录的原始属性 $user = App\User::first(); $user-> ...

  4. Laravel 5.1 文档攻略——Laravel Eloquent ORM最强大也是最难理解的部分:数据关系...

    简介 其实大家都知道,数据表之间都是可以关联的,Eloquent ORM是数据模型操作代替表操作,那么表的关联查询,在Eloquent这里也就是模型间的关联查询,这就是本章的主要内容: Eloquen ...

  5. Laravel Eloquent ORM 实例教程 —— 模型删除及软删除相关实现

    1.删除模型 1.1 使用delete删除模型 删除模型很简单,先获取要删除的模型实例,然后调用delete方法即可: $post = Post::find(5); if($post->dele ...

  6. 20 个 Laravel Eloquent 必备的实用技巧

    Eloquent ORM 看起来是一个简单的机制,但是在底层,有很多半隐藏的函数和鲜为人知的方式来实现更多功能.在这篇文章中,我将演示几个小技巧. 1. 递增和递减 要代替以下实现: $article ...

  7. PHP 项目中单独使用 Laravel Eloquent 查询语句来避免 SQL 注入

    OWASP (Open Web Application Security Project) 是一个记录当前 web 应用所受威胁情况的项目.我一直都在关注他们的网站,从 2010,2013 和 201 ...

  8. 使用Laravel Eloquent ORM 时如何查询表中指定的字段

    我们在使用Laravel ORM的Model方法find, get, first方法获取数据对象时返回的数据对象的attributes属性数组里会包含数据表中所有的字段对应的键值关系, 那么如何在OR ...

  9. laravel mysql注入_PHP 项目中单独使用 Laravel Eloquent 查询语句来避免 SQL 注入

    OWASP (Open Web Application Security Project) 是一个记录当前 web 应用所受威胁情况的项目.我一直都在关注他们的网站,从 2010,2013 和 201 ...

  10. 使用Laravel Eloquent ORM 时如何查询表中指定的字段 1

    我们在使用Laravel ORM的Model方法find, get, first方法获取数据对象时返回的数据对象的attributes属性数组里会包含数据表中所有的字段对应的键值关系, 那么如何在OR ...

最新文章

  1. IOS开发知识(七)
  2. SAP中国招聘内部顾问,工作职责是做客户项目,ABAP开发
  3. java开发13寸_Java 从入门到进阶之路(二十九)
  4. [BZOJ3566][SHOI2014]概率充电器
  5. 英特尔商用攻略升级:企业如何趟平信息化建设这条路?
  6. 了解和使用DotNetCore和Blazor中的异步编程
  7. [原创]JSLint-Toolkit v1.2 - Update with qooxdoo1.3
  8. brew 一直等待_等待高高时,可以做的小事...
  9. QThread Class
  10. Vue的三个点es6知识,扩展运算符表达含义
  11. 给FCKeditor添加自定义按钮的方法
  12. 怎样做小游戏挖金子(VC,源码3)
  13. delphi pi怎么得到?
  14. python爬取淘宝数据魔方_淘宝数据魔方技术架构解析读后感
  15. 海外 Android 三方应用市场
  16. c语言嵌入式系统修炼之道
  17. python3 x完全兼容_中国大学MOOC: Python 3.x 系列版本代码完全兼容 Python 2.x系列的既有语法。...
  18. C语言 —— 多维数组
  19. java用正则表达式判断字符串中是否仅包含英文字母、数字和汉字
  20. TiKV源码分析(一)RaftKV层

热门文章

  1. WhereDidMyTimeGo - 一款帮你记录每天的时间分配的MacOS app
  2. 控制台安装selenium运行浏览器报错TypeError: ‘module‘ object is not callable
  3. 关于日期插件在chrome中出现被遮挡的问题
  4. android7.1索尼,Xperia 1
  5. 使用谷歌(Google)TTS服务 – Java版开源gTTS及Python gTTS
  6. Milton 1.5.1发布,开源服务器端类库
  7. Cannot find name ‘console‘. Do you need to change your target library?ging the ‘lib‘ compiler option
  8. 马克飞象(markdown)的快捷键
  9. rxjava背压_关于RxJava背压
  10. first season tenth episode,Joey kissed Chandler!!!