一对一关联
表:用户表和资料表
- 用户表:user。主要字段:id, …
- 资料:profile。主要字段:id, user_id, …
hasOne (一对一关联)
// 用户模型
class User extends Model
{
public function profile()
{
// hasOne('关联模型类名', '外键', '主键');
// 关联模型(必须):关联模型类名
// 外键:默认的外键规则是当前模型名(不含命名空间,下同)+_id ,例如user_id
// 主键:当前模型主键,默认会自动获取也可以指定传入
return $this->hasOne(Profile::class, 'user_id', 'id');
}
}
belongsTo(相对关联)
// 资料模型
class Profile extends Model
{
public function user()
{
// belongsTo('关联模型','外键', '关联主键');
// 关联模型(必须):关联模型类名
// 外键:当前模型外键,默认的外键名规则是关联模型名+_id
// 关联主键:关联模型主键,一般会自动获取也可以指定传入
return $this->belongsTo(User::class, 'user_id', 'id');
}
}
一对多关联
表:文章和评论。
- 文章表:article。字段:id,…
- 评论表:comment。字段:id,article_id,…
// 文章模型
class Article extends Model
{
public function comments()
{
// hasMany('关联模型','外键','主键');
// 关联模型(必须):关联模型类名
// 外键:关联模型外键,默认的外键名规则是当前模型名+_id
// 主键:当前模型主键,一般会自动获取也可以指定传入
return $this->hasMany(Comment::class, 'article_id', 'id');
// 为关联加条件 comment.is_cancelled=0
// return $this->hasMany(Comment::class, 'article_id', 'id')->where('is_cancelled', Consts::NO);
}
}
反之,查评论所属的文章,就要使用belongsTo()这个一对一的方法。
远程关联
用远程一对多关联的前提
如果模型 A 想远程一对多关联模型 C,前提是中间模型 B 对应的数据库表必须有模型 A 对应的数据表的外键,模型 C 对应的数据库表必须有模型 B 对应数据库表的外键。(套娃)
参考:[ThinkPHP 远程一对多关联](https://blog.csdn.net/weixin_44161401/article/details/131685949)
表:商品表,订单商品表,订单商品评论表
- 商品表:goods。字段:id,…
- 订单商品记录表(中间表):order_goods。字段:id,goods_id,…
- 订单商品评论表(关联表):order_goods_comment。字段:id,order_goods_id,…
远程一对多
class Goods extends Model
{
// 远程一对多关联获取商品的所有评论
public function comments()
{
// hasManyThrough('关联模型', '中间模型', '中间表关联主键', '关联表关联主键','当前模型主键','中间模型主键');
// 1.关联表模型(必须):关联模型类名
// 2.中间表模型(必须):中间模型类名
// 3.中间表关联主键:当前模型在中间模型的外键,默认的外键名规则是当前模型名+_id(OrderGoods.goods_id)
// 4.关联表关联主键:中间模型在关联模型的外键,默认的外键名规则是中间模型名+_id(OrderGoodsComment.order_goods_id)
// 5.当前模型主键:当前模型主键,一般会自动获取也可以指定传入(Goods.id)
// 6.中间模型主键:一般会自动获取也可以指定传入(OrderGoods.id)
return $this->hasManyThrough(OrderGoodsComment::class, OrderGoods::class, 'goods_id', 'order_goods_id', 'id', 'id');
}
}
执行的SQL:
SELECT * FROM `goods` WHERE `id` = 1 LIMIT 1
SELECT * FROM `order_goods` WHERE `goods_id` = 1
SELECT * FROM `order_goods_comment` WHERE `order_goods_id` = 1
远程一对一
class Goods extends Model
{
public function comment()
{
// hasOneThrough('关联模型', '中间模型', '中间表关联主键', '关联表关联主键','当前模型主键','中间模型主键');
// 1.关联表模型(必须):关联模型类名
// 2.中间表模型(必须):中间模型类名
// 3.中间表关联主键:当前模型在中间模型的外键,默认的外键名规则是当前模型名+_id(OrderGoods.goods_id)
// 4.关联表关联主键:中间模型在关联模型的外键,默认的外键名规则是中间模型名+_id(OrderGoodsComment.order_goods_id)
// 5.当前模型主键:当前模型主键,一般会自动获取也可以指定传入(Goods.id)
// 6.中间模型主键:一般会自动获取也可以指定传入(OrderGoods.id)
return $this->hasOneThrough(OrderGoodsComment::class, OrderGoods::class, 'goods_id', 'order_goods_id', 'id', 'id');
}
}
执行的SQL:
SELECT * FROM `goods` WHERE `id` = 1 LIMIT 1
SELECT * FROM `order_goods` WHERE `goods_id` = 1
SELECT * FROM `order_goods_comment` WHERE `order_goods_id` = 1
多对多关联
表:管理员,角色,管理员角色关联表
- 管理员表:admin。字段:id, …
- 角色表:admin_role。字段:id, …
- 关联表(中间表):admin_role_elation。字段:id, onwer_id(管理员ID=admin_id), role_id
** 中间表要继承 Pivot **
class Admin extends Model
{
public function roles()
{
// belongsToMany('关联模型','中间表','外键','关联键');
// 关联模型(必须):关联模型类名
// 中间表:默认规则是当前模型名+_+关联模型名 (可以指定模型名)
// 外键:中间表的当前模型外键,默认的外键名规则是关联模型名+_id
// 关联键:中间表的当前模型关联键名,默认规则是当前模型名+_id
return $this->belongsToMany(AdminRole::class, AdminRoleRelation::class, 'role_id', 'owner_id');
// 为中间表指定条件
// return $this->belongsToMany(AdminRole::class, AdminRoleRelation::class, 'role_id', 'owner_id')->wherePivot('relation_type', 1);
}
}
多态关联
表:文章表,书籍表,评论表。
article(文章表)
id - integer
title - string
content - text
book(书籍表)
id - integer
title - string
comment(评论表)
id - integer
content - text
commentable_id - integer
commentable_type - string
多态一对多关联
class Article extends Model
{
// 多态关联
public function comments()
{
// morphMany('关联模型','多态字段','多态类型');
// 关联模型(必须):关联的模型类名
// 多态字段(可选):支持两种方式定义
// - 如果是字符串:表示多态字段的前缀,多态字段使用 “多态前缀_type”和“多态前缀_id”。
// - 如果是数组:表示使用['多态类型字段名','多态ID字段名']。
// - 默认为当前的关联方法名作为字段前缀。
// 多态类型(可选):当前模型对应的多态类型(字段的值)。默认为当前模型名,可以使用模型名(如Article)或者完整的命名空间模型名(如app\index\model\Article)。
// 1.多太字段为字符串:commentable_type(关联类型,值默认为当前模型名:Model\\Article), commentable_id(关联表ID,值为:Article.id)
// return $this->morphMany(Comment::class, 'commentable');
// 2.多太字段为数组:commentable_type(关联类型,值默认为当前模型名:Model\\Article), commentable_id(关联表ID,值为:Article.id)
// return $this->morphMany(Comment::class, array('commentable_type', 'commentable_id'));
// 3.指定多太类型:明确指定类型值为当前类的命名空间
return $this->morphMany(Comment::class, 'commentable', self::class);
}
}
多态一对一关联
表:文章表,书籍表,评论表。
** 使用以上表结构,假设文章和书籍都只能有一条评论。 **
class Article extends Model
{
public function comment()
{
// morphOne('关联模型','多态字段','多态类型');
// 关联模型(必须):关联的模型类名。
// 多态字段(可选):支持两种方式定义
// - 如果是字符串表示多态字段的前缀,多态字段使用 多态前缀_type和多态前缀_id。
// - 如果是数组,表示使用['多态类型字段名','多态ID字段名']。
// - 默认为当前的关联方法名作为字段前缀。
// 多态类型(可选):当前模型对应的多态类型,默认为当前模型名,可以使用模型名(如Member)或者完整的命名空间模型名(如app\index\model\Member)。
return $this->morphOne(Comment::class, 'commentable');
}
}
获取所有者模型
class Comment extends Model
{
// 获取评论对应的多态模型(返回评论所有者)
public function commentable()
{
// morphTo('多态字段',['多态类型'=>'模型类名', ...]);
// 多态字段(可选):支持两种方式定义
// - 如果是字符串表示多态字段的前缀,多态字段使用 多态前缀_type和多态前缀_id,
// - 如果是数组,表示使用['多态类型字段名','多态ID字段名'],
// - 默认为当前的关联方法名作为字段前缀
// 多态类型别名(可选):数组方式定义,类型对应的模型类名(可以相对或绝对)。如果类型值就是模型名,可以不传这个数组。
return $this->morphTo('commentable', array(
Article::class => 'Article', // 相对命名空间
Book::class => 'Model\Book', // 绝对命名空间
));
}
}
$comment = Comment::find(1);
$article = $comment->commentable; // 文章模型
通过关联查询
hasWhere
has开头的关联方式可用。
$goods = Goods::hasWhere('comments', function ($query) {
$query->where('id', 1);
})->find(1);
执行的SQL:
SELECT `goods`.* FROM `__table_prefix__goods` `goods` INNER JOIN `__table_prefix__order_goods` ON `__table_prefix__order_goods`.`goods_id`=`goods`.`id` JOIN `__table_prefix__order_goods_comment` ON `__table_prefix__order_goods_comment`.`order_goods_id`=`__table_prefix__order_goods`.`id` WHERE `__table_prefix__order_goods_comment`.`id` = '1' AND `goods`.`id` = '1' GROUP BY `__table_prefix__order_goods_comment`.`order_goods_id` LIMIT 1
$goods = Goods::hasWhere('comments', function ($query) {
$query->where('id', 1);
})->select();
SELECT `goods`.* FROM `__table_prefix__goods` `goods` INNER JOIN `__table_prefix__order_goods` ON `__table_prefix__order_goods`.`goods_id`=`goods`.`id` JOIN `__table_prefix__order_goods_comment` ON `__table_prefix__order_goods_comment`.`order_goods_id`=`__table_prefix__order_goods`.`id` WHERE `__table_prefix__order_goods_comment`.`id` = '1' GROUP BY `__table_prefix__order_goods_comment`.`order_goods_id`