thinkphp-多对多关联查询
多对多
一对一,一个用户对应一个用户档案资料,是一对一关联;
一对多,一篇文章对应多个评论,是一对多关联。
一对多,一篇文章对应多个评论,是一对多关联,那么这种对应关系,就是多对多关系,最经典的应用就是权限控制;
首先,我们来看多对多关系的三张表,具体如下
tp_user:用户表;tp_role:角色表;tp_access:中间表;access 表包含了user 和role 表的关联id,多对多模式;
第一步,创建model/Role.php和model/Access.php两个模型文件(role.php 和access.php 创建一个空模型即可,无须创建任何;)
Role
<?php
namespace app\model;
use think\Model;
class Role extends Model
{
// 空的就行
}
Access.php
<?php
namespace app\model;
// 中间表需要继承一个model下的另一个类(Pivot其实也是继承自model)
use think\model\Pivot;
class Access extends Pivot
{
// 空的就行
}
注意:Role 继承Model 即可,而中间表需要继承Pivot;
第二步,在model/User.php 的模型中,设置多对多关联,方法如下
namespace app\model;
use think\Model;
class User extends Model {
public function roles()
{
return $this->belongsToMany(Role::class, Access::class);
}
}
在roles 方法中,belongsToMany 为多对多关联,具体参数如下:
belongsToMany('关联模型','中间表',['外键','关联键']);
$this->belongsToMany(Role::class, Access::class, 'role_id', 'user_id');
在控制器中,简单调用:
public function many()
{
//得到一个用户:蜡笔小新
$user = UserModel::find(21);
//获取这个用户的所有角色
$roles = $user->roles;
//输出这个角色所具有的权限
return json($roles);
}
最终输出如下:
[
{
"id":2,
"type":"评论审核专员",
"pivot":{
"id":1,
"user_id":19,
"role_id":2,
"details":null
}
},
{
"id":3,
"type":"图片监察员",
"pivot":{
"id":6,
"user_id":19,
"role_id":3,
"details":null
}
},
{
"id":1,
"type":"超级管理员",
"pivot":{
"id":8,
"user_id":19,
"role_id":1,
"details":null
}
}
]
当我们要给一个用户创建一个角色时,用到多对多关联新增;
而关联新增后,不但会给tp_role 新增一条数据,也会给tp_access 新增一条;
$user = UserModel::find(19);
$user->roles()->save([
'type' => '测试管理员'
]);
这样就会给user_id=19的行,给与其相关联的role表添加一行新的属性,同时给access也会自动添加关联
user表
id | username | psd |
---|---|---|
19 | 蜡笔小新 | 123 |
role表
id | type | something |
---|---|---|
16 | 测试管理员 | .. |
1 | 超级管理员 | ... |
5 | 广告发布员 |
access表
id | user_id | role_id | st |
---|---|---|---|
1 | 19 | 1 | .. |
2 | 19 | 16 | .. |
$user->roles()->saveAll([[...],[...]]);
一般来说,上面的这种新增方式,用于初始化角色比较合适;也就是说,各种权限的角色,并不需要再新增了,都是初始制定好的,那么,我们真正需要就是通过用户表新增到中间表关联即可;
一般都是直接在中间表添加一个已经存在的用户,而不需要在role表中重新创建一个新角色
比如给user_id=19的用户添加一个新角色,其对应的role_id=5
$user = UserModel::find(19);
$user->roles()->save(5);
执行之后,中间表access表中
id | user_id | role_id | st |
---|---|---|---|
1 | 19 | 1 | .. |
2 | 19 | 16 | .. |
36 | 19 | 5 | ... |
实现同样效果的:
$user->roles()->save(Role::find(5)); // 本地测试6.1.4会报错
$user->roles()->saveAll([1,2,3]); // 一口气添加多个角色
或:
$user->roles()->attach(1);
$user->roles()->attach(2, ['details'=>'测试详情']);
其中,attach可以为更多的字段添加信息。
$user = UserModel::find(19);
$user->roles()->attach(5, [
'details' => '测试测试'
]);
除了新增,还有直接删除中间表数据的方法:
$user = UserModel::find(19);
$user->roles->detach(5);