You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 19:45:04