laravel框架总结(十二) -- 关联关系
这里我们users表对应的模型类名是users,大家特意注意下和user取名的不同
1.一对一关系
1>表A和表B的记录一一对应,比如一个用户对应一个社交账号
数据表的设计如下:
2>定义模型Users,并在其中定义与UserAccounts的一对一对应关系:
public function account() {
return $this->hasOne('App\Http\Models\UserAccounts');
}
3>最后在控制器中编写测试代码如下:
$account = Users::find(1)->account; dd($account);
浏览器中会输出相对应的UserAccounts模型实例。
注意:上面的$this->hasOne()方法的完整格式是
$this->hasOne('App\Http\Models\UserAccount',$foreign_key,$local_key);
第一个参数是关联模型的类名称,
第二个参数,Eloquent 会假设对应关联的外键名称是基于模型名称的,会取用自身模型的「蛇形命名」后的名称,并在后方加上 _id,所以定义模型时候要注意,模型的名称加上'_id'的组合作为外键,我们这里外键=>'users'+'_id',也就是$foreign_key = 'users_id'
第三个参数,Eloquent 的默认外键在上层模型的 id 字段会有个对应值。换句话说,Eloquent 会寻找用户的 id 字段与 Phone 模型的 user_id 字段的值相同的纪录。如果你想让关联使用 id 以外的值,则可以传递第三个参数至 hasOne 方法来指定你自定义的键.
4>我们也可以在UserAccount模型中定义与User的一对一关系:
public function users() {
return $this->belongsTo('App\Http\Models\Users');
}
相应的测试代码为:
$user = UserAccounts::find(1)->users; dd($user);
上述代码会输出相应的Users模型实例。
分析:
Eloquent将调用belongsTo的关联方法名users作为关联关系$relation的值,并将$relation.'_id'作为默认外键名对应users表的id,如果表中没有相应列,又没有在定义关联关系的时候指定具体的外键,就会报错。
如果user_accounts中关联users的外键是$foreign_key,该外键对应users表中的列是$local_key,那么调用belongsTo方法:
$this->belongsTo('App\Http\Models\User',$foreign_key,$local_key);
此外,belongsTo还接收一个额外参数$relation,用于指定关联关系名称,其默认值为调用belongsTo的方法名,这里是user。
2.一对多关系
2>我们在用户模型Users中定义与文章模型Post的一对多关系如下:
public function posts() {
return $this->hasMany('App\Http\Models\Post');
}
对应的测试代码:
$posts = User::find(1)->posts; dd($posts);
这样就能获取id为1的用户所有发表的文章。
由于关联模型实例本身是一个查询构建器,我们可以添加查询条件到该实例:
$posts = User::find(1)->posts()->where('views','>',100)->get();
dd($posts);
需要注意的是这里我们调用的是posts方法,而不是动态属性posts。
3>同样,我们可以在文章模型Post中定义文章所属用户模型User的对应关系:
public function author() {
return $this->belongsTo('App\Http\Models\User','user_id','id');
}
我们可以使用如下方式获取指定文章对应的用户模型实例:
$author = Post::find(1)->author; dd($author);
结果如下:
注意我们在belongsTo方法中传入了额外参数,意为posts表中的user_id对应users表中的id。如果我们定义的方法名为user,则不需传入这些参数:
public function users() { return $this->belongsTo('App\Http\Models\Users'); }
我们在调用belongsTo方法时如果没有传入第四个参数$relation,则默认使用当前调用belongsTo的方法名为关联关系名称并赋值给$relation
3.多对多关系
1>表A的某条记录通过中间表C与表B的多条记录关联,反之亦然。比如一个用户有多种角色,反之一个角色对应多个用户。
数据表设计如下
提示:在定义多对多关联的时候如果没有指定中间表,Eloquent 会合并两个关联模型的名称并依照字母顺序命名,所有中间表的名字要根据两个模型的名称来写,比如模型1 users,模型2 role 那么表名就是role_users,Eloquent默认的中间表使用这种规则拼接出来。
2>我们在模型Users中定义多对多关联如下:
public function roles() {
return $this->belongsToMany('App\Http\Models\Role');
}
注意:我们这里模型的名称是users和role那么关联表中对应的字段就是users_id和role_id,我们的两个表对应的的模型类名是users 和role ,那么自动拼成的中间表名就是 role_users ,并且该表对应的字段就是role_id和users_id,如果你设计表的时候没有注意到这点,那么需要把中间表名作为第二个参数传入,中间表字段$user_id和$role_id作为第三个和第四个参数传入(这两个顺序不能乱),如果关联方法名不是roles还可以将对应的关联方法名作为第五个参数传入该方法。
3>接下来我们在控制器中编写测试代码:
$user = User::find(1);
$roles = $user->roles; echo 'User#'.$user->name.'所拥有的角色:<br>';
foreach($roles as $role) {
echo $role->name.'<br>';
}
对应输出为:
User#所拥有的角色:
role1
role2
role3
4>相对的我们也可以在模型Role中定义获取对应User模型的方法:
public function users() {
return $this->belongsToMany('App\Http\Models\Users');
}
测试代码如下:
$role = Role::find(4);
$users = $role->users; echo 'Role#'.$role->name.'下面的用户:<br>';
foreach ($users as $user) {
echo $user->mobile.'<br>';
}
对应输出为:
Role#role1下面的用户:
18652005200
18612341234
5>此外我们还可以通过动态属性pivot获取中间表字段:
$roles = Users::find(1)->roles;
foreach ($roles as $role) {
echo $role->pivot->role_id.'<br>';
}
对应输出为:
1
2
3
注意:我们取出的每个 Role 模型对象,都会被自动赋予 pivot 属性。此属性代表中间表的模型,它可以像其它的 Eloquent 模型一样被使用。
默认情况下,pivot 对象只提供模型的键。如果你的 pivot 数据表包含了其它的属性,则可以在定义关联方法时指定那些字段:
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
如果你想要中间表自动维护 created_at 和 updated_at 时间戳,可在定义关联方法时加上 withTimestamps 方法:
return $this->belongsToMany('App\Role')->withTimestamps();
4.远层一对多
1>所谓的“远层一对多”指的是通过一个中间关联对象访问远层的关联关系,比如用户与文章之间存在一对多关系,国家与用户之间也存在一对多关系,那么通过用户可以建立国家与文章的之间的一对多关联关系,我们称之为“远层一对多”。
数据表设计如下
2>我们创建一个模型Country,并在其中定义国家与文章的远层一对多关系如下:
public function posts() {
return $this->hasManyThrough('App\Http\Models\Post','App\Http\Models\Users');
}
其中第一个参数是关联对象类名,第二个参数是中间对象类名。
当运行关联查找时,通常会使用 Eloquent 的外键约定。如果你想要自定义关联的键,则可以将它们传递至 hasManyThrough 方法的第三与第四个参数。第三个参数为中间模型的外键名称,而第四个参数为最终模型的外键名称.
public function posts() {
return $this->hasManyThrough('App\Http\Models\Post','App\Http\Models\Users',$country_id,$user_id);
}
接下来我们在控制器中定义测试代码如下:
$country = Country::find(1);
$posts = $country->posts; echo 'Country#'.$country->name.'下的文章:<br>';
foreach($posts as $post){
echo '<<'.$post->title.'>><br>';
}
页面会输出:该国家下对应的所有文章
Country#china下的文章:
<<test1>>
<<test2>>
<<test4>>
5、多态关联
1>多态关联允许一个模型在单个关联中从属一个以上其它模型。比方说你可为你的工作人员和产品保存一些照片。使用多态关联,你可以对这两种情况使用单个 photos 数据表
数据表设计如下:
2>分别定义三个模型
class Photo extends Model {
/** * 获取所有拥有的 imageable 模型。 */
public function imageable() { return $this->morphTo();
}
}
class Staff extends Model {
/** * 获取所有工作人员的照片。 */
public function photos() {
return $this->morphMany('App\Http\Models\Photo', 'imageable');
}
}
class Product extends Model {
/** * 获取所有产品的照片。 */
public function photos() {
return $this->morphMany('App\Http\Models\Photo', 'imageable');
}
}
其中第一个参数是关联模型类名,第二个参数是关联名称,即$imageable_id和$imageable_type中的$imageable部分。当然也可以传递完整参数到morphMany方法:
$this->morphMany('App\Http\Models\Comment',$imageable,$imageable_type,$imageable_id,$id);
最后一个参数是Staff/Products表的主键。
3>接下来我们在控制器中定义测试代码如下:
$staff = Staff::find(1);
echo $staff->name.'的照片信息:<br />';
foreach ($staff->photos as $photo) {
echo $photo->id.'<br />';
echo $photo->path.'<br />';
}
$product = Product::find(1);
echo '产品编号为'.$product->id.'的照片信息:<br />';
foreach ($product->photos as $photo) {
echo $photo->id.'<br />';
echo $photo->path.'<br /><br />';
}
输出结果如下
tom的照片信息:
1
/test/1
2
/test/2
产品编号为1的照片信息:
4
/test/4
6.多态多对多
1>博客的 Post 和 Video 模型可以共用多态关联至 Tag 模型。使用多对多的多态关联能够让你的博客文章及图片共用独立标签的单个列表
数据表设计如下
2>Post 及 Video 模型都会拥有 tags 方法,并在该方法内调用自身 Eloquent 类的 morphToMany 方法:
class Post extends Model {
/** * 获取该文章的所有标签。 */
public function tags() {
return $this->morphToMany('App\Http\Models\Post', 'taggable');
}
}
在 Tag 模型上,你必须为每个要关联的模型定义一个方法。因此,在这个例子中,我们需要定义一个 posts 方法及一个 videos 方法:
class Tag extends Model {
/** * 获取所有被赋予该标签的文章。 */
public function posts() {
return $this->morphedByMany('App\Http\Models\Post', 'taggable');
/** * 获取所有被赋予该标签的图片。 */
public function videos() {
return $this->morphedByMany('App\Http\Models\Video', 'taggable');
}\Video', 'taggable');
} }
3>你可以简单的使用 tags 动态属性来访问文章的所有标签:
$post = Post::find(1);
echo $post->title.'下面的标签:<br />';
foreach ($post->tags as $tag) {
echo $tag->name.'<br />';
}
输出结果:
test1下面的标签:
tag1
tag2
tag3
4>你也可以从多态模型的多态关联中,通过访问运行调用 morphedByMany 的方法名称来获取拥有者。在此例子中,就是 Tag 模型的 posts 或 videos 方法。因此,你可以通过访问使用动态属性来访问这个方法:
$tag = Tag::find(1);
echo $tag->name.'下面的视频:<br />';
foreach ($tag->videos as $video) {
echo $video->name.'<br />';
}
输出结果:
tag1下面的视频:
video1
video2
video3
laravel框架总结(十二) -- 关联关系的更多相关文章
- laravel框架总结(十) -- 返回值
以前用CI框架对于返回值没有过多关注,但是发现使用laravel框架的时候出现了一些小问题,特意实践总结了一些常用情形,希望对大家有所帮助 先理解几个概念: 1>StdClass 对象=&g ...
- 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十二 || 三种跨域方式比较,DTOs(数据传输对象)初探
更新反馈 1.博友@落幕残情童鞋说到了,Nginx反向代理实现跨域,因为我目前还没有使用到,给忽略了,这次记录下,为下次补充.此坑已填 2.提示:跨域的姊妹篇——<三十三║ ⅖ 种方法实现完美跨 ...
- Django框架(十二)-- 中间件、CSRF跨站请求伪造
中间件 一.什么是中间件 请求的时候需要先经过中间件才能到达django后端(urls,views,templates,models) 响应的时候也需要经过中间件才能到达web服务网关接口 djang ...
- Django框架(十二)—— 补充:inclusion_tag、defer、only、choice、事务、创建多对多的第三张表
目录 补充:inclusion_tag.defer.only.choice.事务.创建多对多的第三张表 一.inclusion_tag 1.作用 2.使用 二.defer与only 1.定义 2.使用 ...
- laravel框架总结(十四) -- 数据迁移和数据填充
一.数据迁移 1.创建一个迁移 1>使用artisan命令make:migration来创建一个新的迁移: php artisan make:migration create_sutdents_ ...
- Unity 游戏框架搭建 (十二) 简易AssetBundle打包工具(二)
上篇文章中实现了基本的打包功能,在这篇我们来解决不同平台打AB包的问题. 本篇文章的核心api还是: BuildPipeline.BuildAssetBundles (outPath, 0, Edit ...
- Django框架(十二)-- Djang与Ajax
一.什么是Ajax AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”.即使用Javascript语言与服务器进行异步交互,传 ...
- flask框架(十二):上下文管理***
情况一:单进程单线程 基于全局变量实现. 情况二:单进程多线程 基于threading.local对象. threading.local对象,用于为每个线程开辟一块空间来保存它独有的值. # -*- ...
- 潭州课堂25班:Ph201805201 django框架 第十二课 自定义中间件,上下文处理,admin后台 (课堂笔记)
中间件 在项目主目录下的配置文件 在项目主目录下创建文件 写个自定义异常处理 方法1 要让其生效,要在主目录下,的中间件中进行注册 主目录下.该文件名.类名 在进入视图函数之前进行判断, 给 req ...
随机推荐
- 关于复选框input[type=checkbox]
关于复选框input[type=checkbox],其实在前面的文章中说过一次,当时主要关注点在设置复选框的状态,利用prop实现,今天继续关注一下复选框. 自己在项目中,遇到一个全选/全不选的需求, ...
- Java:对象的强、软、弱、虚引用
转自: http://zhangjunhd.blog.51cto.com/113473/53092 1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无 ...
- OpenStack学习参考
预备知识 Python 调试手段.日志:pdb 开源框架 Django 面向对象:类.继承.多态 编码规范 搭建环境 安装docker,下载openstack镜像,关于docker参考 使用fuel来 ...
- Javascript基础知识总结一
Javascript基础知识总结一 <!DOCTYPE html> <html> <head lang="en"> <meta chars ...
- WebView 一直展示加载中。。。
webview加载html5页面总是一直在加载中,加载很慢或干脆加载不出来, 听浏览器的大牛说可能是 js导致的,尝试在onpause里加入mWebView.pauseTimers(), onResu ...
- centos7 firewalld
1.firewalld简介 firewalld是centos7的一大特性,最大的好处有两个: 1.支持动态更新,不用重启服务: 2.加入了防火墙的"zone"概念 firewa ...
- Android Studio: Failed to sync Gradle project 'xxx' Error:Unable to start the daemon process: could not reserve enough space for object heap.
创建项目的时候报错: Failed to sync Gradle project 'xxx' Error:Unable to start the daemon process: could not r ...
- 跟着思维导图学习javascript
1.javascript 变量 2.javascript 运算符 3.javascript 数组 4.javascript 流程语句 5.javascript字符串函数 6.javascript 函数 ...
- LUA5.3的BNF范式学习笔记
BNF巴科斯范式 {A} 表示 0 或多个 A , [A] 表示一个可选的 A chunk ::= block block ::= {stat} [retstat] stat ::= ‘;’ ...
- [Android Tips] 25. ADB Command Note
copy from https://github.com/operando/Android-Command-Note Android Command Note Logcat adb logcat -v ...