laravel model relationship
laravel支持多种模型之间的relation,对应着模型间的one2one, one2many,many2many,hasManyThrough,Polymorphic, many2many polymorphic关系。
心法
1.所有relation都由model class上的方法来定义;
2. relationship和model本身都是以query builder作为基类的,因此对relation的操作也可以使用类似query builder的方法,比如:可以支持级联;
3.Dynamic property of model:这是 model->relation方式引用的结果,这种方式直接返回relation model的value,不支持query builder的级联操作,这是和model->relation()方法调用的本质区别。
也就是说model->relation = model->relation()->get()
关系的种类:
one 2 one(一对一)
例子User hasOne Phone, Phone belongsTo User这种关系。要使得这种关系work,则需要以下前提:
1. User模型
base table: users,
字段预设: id
relation method: phone (){ return $this->hasOne('App\Phone') }
注意:按照laravel的命名规约,laravel会假设phones表中有一个user_id字段作为users表中的id外键,
我们可以通过在user()方法中传入另外的参数来覆盖这种规约,比如$this->hasOne('App\Phone','owner_id')
在这里owner_id就是phones表中外键引用users表的id的字段名称(默认为user_id);
2.Phone模型
base table: phones,
字段预设: user_id
relation method: user(){ return $this->belongsTo('App\User')}
在这里,laravel也会预设parent表(也就是users表)中有一个id字段为primary key,如果你的parent表并不是使用id作为主键,则在上面的hasOne调用中,可以使用第三个参数来指定这个主键,比如
user(){return $this->hasOne('App\User','owner_id','u_id'}. 这里owner_id为phones表中对users表主键(u_id)的外键引用字段名称
One 2 Many(一对多)
例子: Post hasMany Comments, Comment belongsTo Post,这就是典型的一对多关系模型
1. Post模型
base table: posts
字段预设:id标示行主键
relation method: comments(){return $this->hasMany('App\Comment')}
如果需要覆盖默认命名规约,我们需要这样调用:
public function comments(){return $this->hasMany('App\Comment','foreign_owner_postid_key','local_postid_key')}
注意这里:foreign_owner_postid_key就是要在comments表中具有的字段名;
local_postid_key就是posts本表中必须具有的主键字段名
2. Comment模型
base table: comments
字段预设: post_id 作为posts表的外键
relation method: post(){return $this->belongsTo('App\Post')}
如果需要覆盖默认命名规约,同样我们需要这样调用:
public function post(){return $this->belongsTo('App\Post','foreign_owner_postid_key','other_local_postid_key'}
注意:这里foreign_owner_postid_key就是在本comments表中必须具有的引用posts表的外键字段名;
other_local_postid_key就是必须在posts表中具有的主键名称。之所以加local,other就是代表的是本表的还是关联表的。
另外,上面也已经提到由于relationship本身就是query builder因此可以增加约束级联,比如:
Post::find(1)->comments()->where('title','foo')->first()就只取title为foo的第一条post对应的comment
other_local_postid_key就是
注意按照laravel默认命名规约,一对多的关系模型,child model中的owning model
many 2 many(多对多)
例子: User belongsToMany Role, Role belongsToMany User
1. User模型
base table: users
字段预设: id主键
relation method: roles(){return $this->belongsToMany('App\Role')}
其他预设: role_user pivot表(即两个小写关系之间按照字母排序使用 _ 连接起来)
2. Role模型
base table: roles
字段预设: id主键
relation method: users(){return $this->belongsToMany('App\User')}
其他预设: role_user pivot表(即两个小写关系之间按照字母排序使用 _ 连接起来)
上面的两个model中都有预设pivot表,我们可以通过传参来覆盖它(注意这里只需要在一个方向上调用即可,不用像上面one 2 many需要两边都这样调用才能work!):
public function roles(){return $this->belongsToMany('App\Role','user_role','user_pivot_ziduan_name','role_ziduan_name_in_pivot')}
再看一个使用query builder特性的例子:$roles=App\User::find(1)->roles()->orderBy('name')->get()
也可以在访问relation的同时访问pivot表数据:
public function roles(){$this->belongsToMany('App\Role')->withPivot('column1_in_pivot','c2_in_pivot')}
foreach ($user->roles as $role){ echo $role->pivot->column1_in_pivot}
上面代码中获取relation的同时,也返回pivot表格的对应数据,并且可以作为pivot relation来操作数据
has Many through(通过xx一对多)
例子:由于Country hasMany User,同时User hasMany Post,所以Country可以hasMany Post via User(注意同时User belongsTo Countery, Post belongsTo User)
1. Country模型
base table: countries
字段预设: id, name
relation methods:
public function users(){return $this->hasMany('App\User')}
public function posts(){return $this->hasManyThrough('App\Post')}
2.User模型
base table: users
字段预设: id, country_id, username
relation method: country(){return $this->belongsTo('App\Country')}
3.Post模型
base table: posts
字段预设: id, user_id, title,description
relation method: user(){return $this->belongsTo('App\User')}
Polymorphic relation(多态一对多)
例子:Photo可以morphTo Staff, 同时Photo也可以morphTo Product, Product可以morphMany Photo, Staff也可以morphMany Photo,也就是说一个model可以belongsTo多种parentmodel,多种parentmodel都可以hasMany这个model时,非常适合这种polymorphic relation
1. Staff模型:
base table: staffs
字段预设: id, name
relation method: photos(){return $this->morphMany('App\Photo','imagable')} //注意imagable是Photo模型的一个relation method
2.Product模型
base table: products
字段预设: id, name, price
relation method: photos(){return $this->morphMany('App\Photo','imagable')}//注意imagable是Photo模型的一个relation method
3. Photo模型
base table: photos
字段预设: id,path,imageable_id,imageable_type //注意imageable就是本模型中的relation method名称,这里imageable_id和imageable_type非常关键,也是laravel根据photos表找到对应photos属于哪种模型的关键,也就是说一张图片到底是staff的图片还是产品product的图片,就看这个type和id了,由type找到是哪张表,id再找到这张表中第几条数据。默认情况下laravel会使用Model的class全称作为type,但是有时你可能并不希望如此,这时,一个可行的方案是创建一个types表,来指定这种对应关系,同时在AppServiceProvider booted方法中调用
Relation::morphMap($morphMapArray);
来完成这种人性化的映射关系
Many 2 Many Polymorphic Relations
例子: Post可以打上多个Tag标签, Video也可以同样打上多个Tag,也就是说Tag可以同时打在video或者post上。
如何在model中增加一个不存在于base table字段中的字段?
很多时候存在这样的场景:你很难找到一个适合的relation来描述两个表格之间的关系,或者你不需要建立复杂的relation,你只需要在你返回的model中添加一条额外的信息,比如,User model中你可能需要一条额外的字段'isAdmin'来方便判断该用户是否admin用户,这时可以这样操作:(但是好像动态访问不是很好用)
https://laravel.com/docs/5.1/eloquent-serialization#appending-values-to-json
class User extends Model
{
protected $appends = ['is_admin'];
/**
* Get the administrator flag for the user.
*
* @return bool
*/
public function getIsAdminAttribute()
{
return $this->attributes['admin'] == 'yes';
}
}
laravel relation相关简单调试手段
虽然laravel的relation非常强大,只要你稍加熟悉,你就能花非常少的effort构建出非常强大的web后端应用来。但是有时候,一些高级的sql查询,laravel可能并未按照我们的预期工作,这时,我们就希望eloquent最终到底映射成了什么sql,有几种方法获取这方面的信息:
1. get()替换为toSql()直接打印出来;
$results = User::where(function($q) use ($request) {
$q->orWhere('email', 'like', '%john@example.org%');
$q->orWhere('first_name', 'like', '%John%');
$q->orWhere('last_name', 'like', '%Doe%');
})->toSql();
2. listen事件
\DB::listen(function($sql) {
var_dump($sql);
});
https://scotch.io/tutorials/debugging-queries-in-laravel
查询relation时针对relation实现限制条件:(has, doesnotHave)
// Retrieve all posts with at least one comment containing words like foo%
$posts = Post::has('comments.votes')->get(); // 简化版
$posts = Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get(); $posts = App\Post::doesntHave('comments')->get(); // 简化版
$posts = Post::whereDoesntHave('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
hasManyThrough 多对多?
http://laravel.io/forum/03-04-2014-hasmanythrough-with-many-to-many
laravel model relationship的更多相关文章
- Laravel Model 利用 Macroable 为数据模型添加宏能力
什么是ThinkSNS ? ThinkSNS(简称TS),一款全平台综合性社交系统,为国内外大中小企业和创业者提供社会化软件研发及技术解决方案,目前最新版本为ThinkSNS+(简称TS+).Thin ...
- Laravel Model查询结果的3种存储格式内存占用对比
PHP Laravel框架支持Model查询数据后可以有多种方式返回数据,对新手会造成一些困扰,比如数组Model对象.集合.纯数组 今天从内存占用的角度对比一下3种数据返回方式 按数组Model对象 ...
- Laravel Model 的 fillable (白名单)与 guarded (黑名单)
例如 protected $fillable = ['name']; protected $guarded = ['price']; 定义了 name 字段可以写入/修改,而 price 字段不可以. ...
- Laravel Model Factory(模型工厂)的用法以及数据本地化
Model Factory的位置 生成数据方法:make是生成数据,create是生成数据并保存到数据库 本地化方法 这样便生成了中文数据 整理自www.laravist.com视频教程
- Laravel Model updating&updated 事件使用注意事项
1 触发条件 1.1 updating 1.1.1 如果字段无变化,不会触发此事件. 1.1.2 除非更改至少一个字段的值 2 事件逻辑不会覆盖 2.1 Trait 中定义事件如下 /** * The ...
- 保存 laravel model 而不更新 timestamps 的方法
$product = Product::find(1); $product->view_count += 1; $product->timestamps = false; $product ...
- Laravel Relationship Events
Laravel Relationship Events is a package by Viacheslav Ostrovskiy that adds extra model relationship ...
- PHP and laravel知识点小小积累
function () use ($x, &$y){} 自从PHP5.3开始有了closure/匿名函数的概念,在这里的use关键词的作用是允许匿名函数capture到父函数scope 内存在 ...
- Laravel 系列入门教程(一)【最适合中国人的 Laravel 教程】
热烈庆祝 Laravel 5.5 LTS 发布! 实际上 Laravel 上一个 LTS 选择 5.1 是非常不明智的,因为 5.2 增加了许许多多优秀的特性.现在好了,大家都用最新的长期支持版本 5 ...
随机推荐
- 【文档】一、Mysql Binlog概述
Binlog是一系列日志文件,他们包含的内容是Mysql数据内容的改变.如果想开启binlog功能,需要在启动时带上--log-bin参数. binlog是从Mysql3.23.14版本开始的.它包含 ...
- 浅谈js中的垃圾两种回收机制
一.标记清除 标记清除的主要思想是先建立各个对象的关联,然后从根节点出发,使用广度优先搜索依次标记所有对象,那些不能被标记的对象就应该作为垃圾回收. 这种方式的主要缺点就是如果某些对象被清理后,内存是 ...
- 《LeetBook》leetcode题解(6): ZigZag Conversion[E]
我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...
- Python2.7环境下安装pydbg
From:http://blog.csdn.net/cheng_tian/article/details/7652058 最近在看<Python灰帽子:黑客与逆向工程师的Python编程之道&g ...
- Tomcat8-启动脚本分析
1. Tomcat也是一个java程序 最终的入口启动文件:org.apache.catalina.startup.Bootstrap 最后一条命令: start "Tomcat" ...
- STL 排序(转载)
这篇文章关于STL中的排序写的虽不深入,但是还是挺好的. 1.sort sort有两种形式,第一种形式有两个迭代器参数,构成一个前开后闭的区间,按照元素的 less 关系排序:第二种形式多加一个指定排 ...
- rails 中 create, new, build, save 的用法以及误区汇总 (转)
自己很初级,初级的不能再初级,所以初次接触rails的时候,对于里面的create,new,build等方法不是很了解,用的很混乱,导致经常出现不必要的bug,很苦恼,决定,总结一下,结合网上已有资源 ...
- Lineare Algebra
Grundlegendes Wort: 矩阵列:Das Spalte von der Matrix 行列式:Die Determinante 对角矩阵:Die diagonal Matrix 逆矩阵: ...
- pythonchallenge(七)
转眼间又一个月没有逛博客园,明显的感觉到自己的代码能力变弱,前两周搞项目去了,只是形式上面的答辩而已,并没有涉及到代码层面,也就玩了一下验证码,没有识别玩出校器网页的验证码:转眼间又是各种考试,所幸, ...
- MongoDB的基本使用及java对MongoDB的基本增删改查
MongoDB的特点 MongoDB 是文档存储数据库,存储结构灵活 MongoDB 支持复杂查询操作.支持序列 MongoDB 采用C++开发,可以做分布式扩展 MongoDB 采用BSON格式存储 ...