参考文章
 
以下所用到的实例,包含在https://github.com/archer-wong/laravel-orm-relationships工程中,方便使用。
 
你可在 Eloquent 模型类内将 Eloquent 关联定义为函数。因为关联像 Eloquent 模型一样也可以作为强大的查询语句构造器,定义关联为函数提供了强而有力的链式调用及查找功能。
 

1 一对一关系

1.1 表A和表B的记录一一对应,比如一个用户对应一个社交账号
 
1.2 定义模型User(位于app/Models文件夹下),并在其中定义与UserAccount的一对一对应关系:
public function getAccount() { return $this->hasOne('App\Models\UserAccounts'); }
注意:hasOne()方法的3种不同的使用情况: Eloquent 默认关联关系的外键基于模型名称。默认是:UserAccount模型的主键是id,关联的外键是user_id  
1> hasOne('App\Models\UserAccounts') - 默认情况  
2> hasOne('App\Models\UserAccounts', 'foreign_key') -UserAccount模型的主键是id,但是外键不是 user_id  
3> hasOne('App\Models\UserAccounts', 'foreign_key', 'local_key') - UserAccount模型的主键不是id,外键也不是user_id  
第一个参数是关联模型的类名称,
第二个参数,Eloquent 会假设对应关联的外键名称是基于模型名称的,会取用自身模型的「蛇形命名」后的名称,并在后方加上 _id,所以定义模型时候要注意,模型的名称加上'_id'的组合作为外键,我们这里外键=>'user'+'_id',也就是$foreign_key = 'user_id'
第三个参数,Eloquent 的默认外键在上层模型的 id 字段会有个对应值。
 
1.3 我们也可以在UserAccount模型中定义与User的一对一关系:
public function user() { return $this->belongsTo('App\Models\User'); }
注意:belongsTo()方法的3种不同的使用情况: Eloquent 默认关联关系的外键基于关联方法名称。默认是:UserAccount模型的主键是id,关联的外键是user_id  
1> belongsTo('App\Models\User') - 默认情况  
2> belongsTo('App\Models\User', 'foreign_key') -UserAccount模型的主键是id,但是外键不是 user_id  
3> belongsTo('App\Models\User', 'foreign_key', 'local_key') - UserAccount模型的主键不是id,外键也不是user_id  
默认情况下,Eloquent将调用belongsTo的关联方法名user作为关联关系$relation的值,并将$relation.'_id'作为默认外键名对应users表的id,如果表中没有相应列,又没有在定义关联关系的时候指定具体的外键,就会报错。
 
1.4 控制器中的调用
public function oneToOne(){
$user_account = User::find(1)->getAccount;
$user = UserAccount::find(1)->user;
dd($user_account, $user);
}
调用:  
关联关系被定义后,可以使用 Eloquent 的 '动态属性' 来获取关联关系!  
注意:  
动态属性:允许我们访问关联函数,就像它们是定义在模型上的属性一样!         
理解 '动态属性' 的概念:按理说,我们定义了 getAccount() 方法,应该调用的是一个方法,而这里将其作为了一个 '属性' 来调用!  
 
1.5 总结:不管是User模型类,还是UserAccount模型类,2者都是以 'User' 模型为主。UserAccount模型还是附属于User模型。UserAccount模型具有外键 'user_id' ,但是要注意hasOne()方法的外键基于模型名称,belongsTo()方法的外键基于关联方法名称的。
调用结果:

2 一对多关系

2,1 表A的某条记录对应表B的多条记录,反之表B的某条记录归属于表A的某条记录,比如一个用户发表多篇文章
2.2 我们在用户模型User中定义与文章模型Post的一对多关系如下:
public function getPosts() { return $this->hasMany('App\Models\Post'); }
当然,因为所有的关联也都提供了查询语句构造器的功能,因此你可以对获取到的评论进一步增加条件,通过调用 posts()方法然后在该方法后面链式调用查询条件:
$posts = User::find(1)->getPosts()->where('title','vitae')->get(); dd($posts);
需要注意的是这里我们调用的是getPosts()方法,而不是动态属性getPosts,当然使用getPosts动态属性也可以支持链式调用。
 
2.3 同样,我们可以在文章模型Post中定义文章所属用户模型User的对应关系:
//1> 最基本写法
public function user() { return $this->belongsTo('App\Models\User'); }
//2> 当定义的方法名不是user的时候,传入了额外参数,意为posts表中的user_id对应users表中的id
public function author() { return $this->belongsTo('App\Models\User', 'user_id', 'id'); }
2.4 控制器中调用
public function oneToMany(){
$post = User::find(1)->getPosts;
//如果我们想增加更多的附加条件,可以使用posts()方法,这样仍然支持链式。
$post2 = User::find(1)->getPosts()->where('title','vitae')->get();
//区分user和user2的区别
$user = Post::find(1)->user;
$user2 = Post::find(1)->user();
//注意author方法的话,需要增加键的限制
$author = Post::find(1)->author;
dd($post, $post2, $user, $user2, $author);
}
2.4 总结
写法和一对一关系中非常相像。

3 多对多关系

3.1 表A的某条记录通过中间表C与表B的多条记录关联,反之亦然。比如一个用户有多种角色,反之一个角色对应多个用户。
 
提示:定义中间表的时候没有在结尾加s并且命名规则是按照字母表顺序,将role放在前面,user放在后面,并且用_分隔,在定义多对多关联的时候如果没有指定中间表,Eloquent默认的中间表使用这种规则拼接出来,比如模型1 user,模型2 role 那么表名就是role_user,Eloquent默认的中间表使用这种规则拼接出来。
 
3.2 我们在模型User中定义多对多关联如下:
public function getRoles() { return $this->belongsToMany('App\Models\Role'); }
注意:
完整写法:
return $this->belongsToMany('App\Models\Role', 'user_roles', 'user_id', 'role_id');
Eloquent 会合并两个关联模型的名称并依照字母顺序命名。当然你也可以随意重写这个约定。可通过传递第二个参数至 belongsToMany 方法来实现:
return $this->belongsToMany('App\Models\Role', 'user_roles');
除了自定义合并数据表的名称,你也可以通过传递额外参数至 belongsToMany 方法来自定义数据表里的键的字段名称。第三个参数是你定义在关联中的模型外键名称,而第四个参数则是你要合并的模型外键名称:
 
3.3 相对的我们也可以在模型Role中定义获取对应User模型的方法:
public function getUsers() { return $this->belongsToMany('App\Models\Users'); }
 
3.4 此外我们还可以通过动态属性pivot获取中间表字段:
$roles = Users::find(1)->roles; foreach ($roles as $role) { echo $role->pivot->role_id.'<br>'; }
注意:我们取出的每个 Role 模型对象,都会被自动赋予 pivot 属性。此属性代表中间表的模型,它可以像其它的 Eloquent 模型一样被使用。
默认情况下,pivot 对象只提供模型的键。
如果你的 pivot 数据表包含了其它的属性,则可以在定义关联方法时指定那些字段:
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
如果你想要中间表自动维护 created_at 和 updated_at 时间戳,可在定义关联方法时加上 withTimestamps 方法:
return $this->belongsToMany('App\Role')->withTimestamps();
 
3.5 控制器中调用:
public function manyToMany(){
$roles = User::find(1)->getRoles;
$users = Role::find(1)->getUsers;
//通过动态属性pivot获取中间表字段
foreach ($roles as $role) {
$pivot = $role->pivot->role_id;
echo $pivot . '<br>';
}
dd($roles, $users);
}
 

4 远层一对多

4.1 所谓的“远层一对多”指的是通过一个中间关联对象访问远层的关联关系,比如国家与用户之间存在一对多关系,用户与文章之间也存在一对多关系,那么通过用户可以建立国家与文章的之间的一对多关联关系,我们称之为“远层一对多”。
4.2 我们创建一个模型Country,并在其中定义国家与文章的远层一对多关系如下:
public function getPostsThroughUser() { return $this->hasManyThrough('App\Models\Post','App\Models\User'); }
其中第一个参数是关联对象类名,第二个参数是中间对象类名。
当运行关联查找时,通常会使用 Eloquent 的外键约定。如果你想要自定义关联的键,则可以将它们传递至 hasManyThrough 方法的第三与第四个参数。第三个参数为中间模型的外键名称,而第四个参数为最终模型的外键名称.
$this->hasManyThrough('App\Models\Post','App\Models\User',$country_id,$user_id);
4.3 接下来我们在控制器中定义测试代码如下:
public function hasManyThrough(){
$country = Country::find(1);
$posts = $country->getPostsThroughUser;
echo 'Country#'.$country->name.'下的文章:<br>';
foreach($posts as $post){
echo '&lt;&lt;'.$post->title.'&gt;&gt;<br>';
}
}
 
页面会输出:该国家下对应的所有文章
Country#China下的文章:
<<vitae>>
<<officiis>>
<<hic>>
<<quam>>
<<veritatis>>
 

5 多态关联

5.1 多态关联允许一个模型在单个关联下属于多个不同父模型。比方,某一条评论可能归属于某篇文章,也可能归属于某个视频。我们可以在评论表中添加一个item_id字段表示其归属节点ID,同时定义一个item_type字段表示其归属节点类型。
 
5.2 分别定义三个模型
在Post和Video模型类中定义关联评论:
public function comments() { return $this->morphMany('App\Models\Comment','item'); }
 
同样也可以在Comment模型中定义相对的关联关系获取其所属节点:
public function item() { return $this->morphTo(); }
//扩展,当不使用item作为方法名,可以传入自定义参数
public function getItem()
{
return $this->morphTo('item', 'item_type', 'item_id');
}
 
完整写法:
1> $this->morphMany('App\Models\Comment',$item,$item_type,$item_id,$id);
其中第一个参数是关联模型类名,第二个参数是关联名称,即$item_id和$item_type中的$item部分,最后一个参数是posts/videos表的主键。
2> $this->morphTo($item,$item_type,$item_id); 如果$item部分不等于item可以自定义传入参数到morphTo:
 
5.3 控制器中调用:
public function polymorphicRelations(){
$video = Video::find(1);
$videoComments = $video->comments;
$comment = Comment::find(1);
$item = $comment->item;
dd($videoComments, $item);
}
 
输出结果如下
 
 

6 多态多对多关联

6.1 最常见的应用场景就是标签,比如一篇文章对应多个标签,一个视频也对应多个标签,同时一个标签可能对应多篇文章或多个视频,
 
6.2 定义模型方法
在Post/Video中定义关联关系如下:
public function tags() { return $this->morphToMany('App\Models\Tag','taggable'); }
在Tag中定义相对的关联关系如下:
public function posts() { return $this->morphedByMany('App\Models\Post','taggable'); } public function videos() { return $this->morphedByMany('App\Models\Video','taggable'); }
完整写法:
1> $this->morphToMany('App\Models\Tag','taggable','taggable','taggable_id','tag_id',false);
其中第一个参数是关联模型类名,第二个参数是关联关系名称,其中第三个参数是对应关系表名,最后一个值若为true,则查询的是关联对象本身,若为false,查询的是关联对象与父模型的对应关系。
2> $this->morphedByMany('App\Models\Video','taggable','taggable','tag_id','taggable_id');
其中第一个参数是关联对象类名,第二个参数是关联关系名称,其中第三个参数是对应关系表名。
 
6.3 控制器中调用
public function manyToManyPolymorphicRelations(){
$post = Post::find(1);
$tags = $post->tags;
$tag = Tag::find(1);
$posts = $tag->posts;
dd($tags, $posts);
}
结果:
 
 
 
 
 
 
 
 
 

laravel5.2总结--关联关系的更多相关文章

  1. laravel5.3统计 withCount()方法的使用

    在laravel5.3之后可以使用withCount()这个方法. 注意:一定要是5.3版本之后,5.2和5.1都会报方法未定义 举个栗子: App\Post::withCount('comments ...

  2. 【laravel5.4 + TP5.0】hasOne和belongsTo的区别

    1.从字面理解:假如A比B大,那么A hasOne B: B belongsTo A: 2.个人总结: 3.从代码角度: 主要是看你是在哪一个model(模型)中编写这个关联关系,父关联对象就是在父关 ...

  3. laravel5.6 ORM 关联模型,一对一和一对多

    Laravel5.6 关联模型的操作,主要是一对一,一对多,多对多等操作.下面示例主要解析前面两个操作用法比较常用.(操作和用法TP5类似)将关联查询使用语法hasOne.hasMany.belong ...

  4. 【原】使用Bmob作为iOS后台开发心得——查询关联关系(BmobRelation)

    本文转载请注明出处 —— polobymulberry-博客园 简介 Bmob中的数据关联分为Pointer和Relation两种(数据关联在我开发app过程中使用还是很频繁的,也算个难点.虽然之前没 ...

  5. Hibernate(6)—— 一对多 和 多对多关联关系映射(xml和注解)总结

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: One to Many 映射关系 多对一单向外键关联(XML/Annotation) 一对多单向外键关联(XM ...

  6. Hibernate(5)—— 联合主键 、一对一关联关系映射(xml和注解) 和 领域驱动设计

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: One to One 映射关系 一对一单向外键(XML/Annotation) 一对一双向外键关联(XML/A ...

  7. laravel5 安装笔记

    1.环境更新 apt-get update apt-get install php5-cli apt-get install curl 2. Composer安装 curl -sS https://g ...

  8. Laravel5路由/home页面无法访问

    报错信息: Not Found The requested URL /laravel5/public/home was not found on this server. 解决方法: 1.编辑apac ...

  9. Laravel5.0学习--03 Artisan命令

    本文以laravel5.0.22为例. 简介 Artisan 是 Laravel 内置的命令行接口.它提供了一些有用的命令协助您开发,它是由强大的 Symfony Console 组件所驱动.利用它, ...

随机推荐

  1. Error和Exception的区别?

    Error和Exception都继承自Throwable类 二者不同之处在于: Exception: 1.可以是可控制的(checked)或是不可控制的(unchecked) 2.表示一个有程序员编写 ...

  2. 零基础逆向工程24_C++_01_类_this指针_继承本质_多层继承

    1 类内的成员函数和普通函数的对比 1.1 主要是从参数传递.压栈顺序.堆栈平衡来总结. 1.参数传递:成员函数多传一个this指针 2.压栈顺序:成员函数会将this指针压栈,在函数调用取出 3.堆 ...

  3. 小div在大div里面 垂直居中

    方法1: .parent { width:800px; height:500px; border:2px solid #000; position:relative; } .child { width ...

  4. python基础-数据运算

             *按位取反运算规则(按位取反再加1)   详解http://blog.csdn.net/wenxinwukui234/article/details/42119265  详细内容ht ...

  5. C++ 关于运算符重载

    转载来源:http://c.biancheng.net/cpp/biancheng/view/216.html 重载运算符的函数一般格式如下:    函数类型 operator 运算符名称 (形参表列 ...

  6. pat甲级1013

    1013 Battle Over Cities (25)(25 分) It is vitally important to have all the cities connected by highw ...

  7. java Vamei快速教程19 嵌套类

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 到现在为止,我们都是在Java文件中直接定义类.这样的类出现在包(package) ...

  8. 关于ffmpeg(libav)解码视频最后丢帧的问题

    其实最初不是为了解决这个问题而来的,是Peter兄给我的提示解决另一个问题却让我误打误撞解决了另外一个问题之后也把这个隐藏了很久的bug找到(之前总是有一些特别短的视频产生不知所措还以为是视频素材本身 ...

  9. Object.keys 函数 (JavaScript)

    Object.keys 函数 (JavaScript) 返回对象的可枚举属性和方法的名称. 在实际开发中,我们有时需要知道对象的所有属性,原生js给我们提供了一个很好的方法:Object.keys() ...

  10. fflush - 刷新一个流

    SYNOPSIS 总览 #include <stdio.h> int fflush(FILE *stream); DESCRIPTION 描述 函数 fflush 强制在所给的输出流或更新 ...