Laravel 9.x中如何从User模型正确关联Permission模型?
问题描述
数据库结构
user user_id office office_id project project_id role role_id permission permission_id role_permission role_id permission_id office_user office_user_id office_id user_id role_id project_user project_user_id project_id user_id role_id
对应模型
User, Project, Office, Role, Permission
我想从User模型直接访问Permission模型,但写的代码里,officeUserPermissions()和projectUserPermissions()方法获取的role_id值一直出错,代码如下:
class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; public function projects() { return $this->belongsToMany(Project::class, 'project_user', 'user_id'); } public function offices() { return $this->belongsToMany(Office::class, 'office_user', 'user_id'); } public function officeRole() { return $this->belongsToMany(Role::class, 'office_user'); } public function projectRole() { return $this->belongsToMany(Role::class, 'project_user'); } public function officeUserPermissions() { return $this->belongsToMany(Permission::class, 'role_permission', 'role_id'); } public function projectUserPermissions() { return $this->belongsToMany(Permission::class, 'role_permission', 'role_id'); } }
解决方案
你之前的写法错在直接跳过角色关联,想让User和Permission直接通过role_permission表关联,但role_permission里根本没有user_id字段,自然拿不到正确的role_id。得通过用户关联的角色(办公/项目角色)间接关联权限,以下是正确实现方式:
第一步:完善Role模型的权限关联
先在Role模型里定义好和Permission的多对多关联:
class Role extends Model { public function permissions() { return $this->belongsToMany(Permission::class, 'role_permission'); } }
第二步:在User模型里关联权限
1. 获取办公场景下的权限
有两种实现方式:
- 方式一:嵌套关联(先拿角色,再取角色对应的权限)
public function officePermissions() { return $this->officeRole()->with('permissions'); }
调用时$user->officePermissions会返回所有办公角色及对应的权限集合。
- 方式二:直接关联出所有办公权限(自动去重)
public function officePermissions() { return $this->belongsToMany(Permission::class, 'office_user') ->join('role_permission', 'office_user.role_id', '=', 'role_permission.role_id') ->select('permissions.*') ->distinct(); }
调用时$user->officePermissions直接返回Permission模型的集合,无需嵌套遍历。
2. 获取项目场景下的权限
和办公场景逻辑一致:
- 方式一:嵌套关联
public function projectPermissions() { return $this->projectRole()->with('permissions'); }
- 方式二:直接关联权限
public function projectPermissions() { return $this->belongsToMany(Permission::class, 'project_user') ->join('role_permission', 'project_user.role_id', '=', 'role_permission.role_id') ->select('permissions.*') ->distinct(); }
3. 获取用户的所有权限(办公+项目)
如果需要一次性拿到用户所有权限,用union合并两个查询:
public function allPermissions() { return Permission::query() ->join('role_permission', 'permissions.permission_id', '=', 'role_permission.permission_id') ->join('office_user', 'role_permission.role_id', '=', 'office_user.role_id') ->where('office_user.user_id', $this->user_id) ->union( Permission::query() ->join('role_permission', 'permissions.permission_id', '=', 'role_permission.permission_id') ->join('project_user', 'role_permission.role_id', '=', 'project_user.role_id') ->where('project_user.user_id', $this->user_id) ) ->distinct(); }
内容的提问来源于stack exchange,提问作者Валерий Новожилов
相关产品推荐
相关产品推荐

