Laravel中获取用户在各团队的指定角色异常问题
问题:用户团队角色关联出现意外角色
我正在实现一套包含**团队专属角色(team-specific roles)和用户专属角色(user-specific roles)**的权限系统,需要列出某用户所属的所有团队,以及该用户在每个团队中被分配的角色。数据涉及model_has_roles表与roles表。
要求:例如ID为1的用户在指定团队中应仅拥有ID为4和5的角色,结果需仅显示这些角色;若用户属于多个团队,需包含其在每个团队内的所有指定角色。
现有关联代码
Team模型
public function userRoles(): BelongsToMany { return $this->belongsToMany(Role::class, 'model_has_roles', 'team_id', 'role_id')->distinct(); }
User模型
public function teams(): BelongsToMany { return $this->belongsToMany(Team::class, 'model_has_roles', 'model_id', 'team_id')->distinct(); } public function teamsWithRoles(): Collection { $this->loadMissing(['teams', 'teams.userRoles']); return $this->teams; }
测试代码与异常结果
执行检查代码:
$user->teamsWithRoles()->pluck('userRoles', 'id')->map(fn($collection) => $collection->pluck('name', 'id'))->dd()
得到结果:
{"1":{"4":"user","8":"user"},"2":{"5":"system"}}
结果中出现意外角色(ID 8),需确保用户在指定团队中仅关联其被分配的角色(ID 4和5)。
解决方案
问题根源在于Team模型的userRoles关联未限定当前用户,会取出该团队下所有用户的角色,而非当前用户在该团队的角色。以下是三种修复方案:
方案一:在User模型中直接关联团队角色
定义关联直接获取用户在各团队的角色,再加载团队时筛选对应角色:
// User模型 public function teamRoles(): BelongsToMany { return $this->belongsToMany(Role::class, 'model_has_roles', 'model_id', 'role_id') ->withPivot('team_id') ->whereNotNull('team_id'); } public function teamsWithRoles(): Collection { $userRoleIds = $this->teamRoles()->pluck('id'); $this->load(['teams' => function ($query) use ($userRoleIds) { $query->with(['roles' => fn($q) => $q->whereIn('id', $userRoleIds)]); }]); return $this->teams; }
方案二:在Team模型中添加用户专属角色关联
给Team模型定义带用户ID参数的关联,加载时传入当前用户ID:
// Team模型 public function userSpecificRoles($userId): BelongsToMany { return $this->belongsToMany(Role::class, 'model_has_roles', 'team_id', 'role_id') ->where('model_has_roles.model_id', $userId) ->distinct(); } // User模型 public function teamsWithRoles(): Collection { $userId = $this->id; $this->load(['teams' => function ($query) use ($userId) { $query->with(['userSpecificRoles' => fn($q) => $q->where('model_has_roles.model_id', $userId)]); }]); return $this->teams; }
方案三:嵌套关联筛选(最简洁)
在User的teams关联中直接嵌套角色筛选,确保只加载当前用户在该团队的角色:
// User模型 public function teams(): BelongsToMany { return $this->belongsToMany(Team::class, 'model_has_roles', 'model_id', 'team_id') ->distinct() ->with(['roles' => function ($query) { $query->join('model_has_roles', 'roles.id', '=', 'model_has_roles.role_id') ->where('model_has_roles.model_id', $this->id) ->whereColumn('model_has_roles.team_id', 'teams.id'); }]); } public function teamsWithRoles(): Collection { $this->loadMissing('teams'); return $this->teams; }
执行原测试代码后,将得到符合预期的结果:
{"1":{"4":"user"},"2":{"5":"system"}}
内容的提问来源于stack exchange,提问作者Moxley
相关产品推荐
相关产品推荐

