Laravel-Backpack中合并hasMany与hasManyThrough实现实例列表权限过滤
实现方案
问题根因
- 你原有两个
CRUD::addClause默认是AND逻辑,要求实例同时满足「直接关联当前用户」和「所属项目关联当前用户」两个条件,和你要的OR逻辑不符 instances_through的hasManyThrough关联定义不符合当前场景,无需使用该关联即可实现需求
具体实现步骤
步骤1:补全缺失的关联定义
首先在对应模型中补全以下关联:
// Project 模型 public function users() { return $this->belongsToMany(User::class, 'project_user'); } // Instance 模型 public function project() { return $this->belongsTo(Project::class); }
原来的instances_through关联可以直接删除。
步骤2:在InstanceCrudController中添加权限查询约束
替换你原来的两条addClause代码为以下内容:
// 先获取当前登录用户ID $currentUserId = backpack_auth()->id(); CRUD::addClause(function ($query) use ($currentUserId) { // 嵌套where避免OR逻辑影响其他全局查询条件 $query->where(function ($subQuery) use ($currentUserId) { // 条件1:实例直接和当前用户关联 $subQuery->whereHas('users', function ($userQuery) use ($currentUserId) { $userQuery->where('users.id', $currentUserId); }) // 条件2:实例所属项目和当前用户关联 ->orWhereHas('project.users', function ($projectUserQuery) use ($currentUserId) { $projectUserQuery->where('users.id', $currentUserId); }); }); });
可选优化:封装为模型作用域(复用性更高)
如果需要在其他场景也调用这个权限过滤逻辑,可以在Instance模型中封装为独立作用域:
// Instance 模型 public function scopeAccessibleByUser($query, int $userId) { return $query->where(function ($subQuery) use ($userId) { $subQuery->whereHas('users', fn($q) => $q->where('users.id', $userId)) ->orWhereHas('project.users', fn($q) => $q->where('users.id', $userId)); }); }
封装后控制器代码可以简化为:
CRUD::addClause('accessibleByUser', backpack_auth()->id());
效果验证
按照你给出的示例数据,用户ID为1时,查询会同时匹配:
- 直接关联的实例ID4
- 关联项目ID1下的实例ID1、ID2
最终返回3条数据,完全符合需求。
内容的提问来源于stack exchange,提问作者Miguel Heredia
相关产品推荐
相关产品推荐

