
本文详解如何在 laravel 9 中结合多表关联(用户→部门→任务→车辆→库存)动态筛选并展示符合双重权限条件的任务:用户所属部门 + 车辆所属库存组已配置该部门权限。
本文详解如何在 laravel 9 中结合多表关联(用户→部门→任务→车辆→库存)动态筛选并展示符合双重权限条件的任务:用户所属部门 + 车辆所属库存组已配置该部门权限。
在 Laravel 应用中,实现精细化数据权限控制常需跨越多个中间表。针对您的场景——仅向登录用户展示其所属部门内、且关联车辆处于“已授权库存组”(即该库存组的 DEPARTMENT_IDS 字段包含该用户所在部门 ID)的任务列表——直接依赖 hasManyThrough 难以覆盖 STOCKS.DEPARTMENT_IDS 这一 JSON/逗号分隔字段的匹配逻辑。因此,推荐采用 Eloquent + 原生查询混合策略,兼顾可读性与灵活性。
✅ 推荐实现方式:使用 Query Builder 构建精准 JOIN 查询
首先确保模型已正确定义基础关系(便于后续扩展):
// User.php
public function departments()
{
return $this->belongsToMany(Department::class, 'department_user');
}
// Job.php
public function department() { return $this->belongsTo(Department::class); }
public function vehicle() { return $this->belongsTo(Vehicle::class); }
// Vehicle.php
public function stock() { return $this->belongsTo(Stock::class, 'stock_id'); }
然后在控制器或服务类中编写如下查询方法(注意:STOCKS.DEPARTMENT_IDS 若为 JSON 数组,需用 JSON_CONTAINS;若为逗号分隔字符串,则用 FIND_IN_SET):
use Illuminate\Support\Facades\DB;
public function getUserJobs()
{
$userId = auth()->id();
// ✅ 假设 DEPARTMENT_IDS 是逗号分隔字符串(如 "1,3,5")
return DB::table('jobs')
->select('jobs.*')
->join('department_user', 'department_user.department_id', '=', 'jobs.department_id')
->join('vehicles', 'vehicles.id', '=', 'jobs.vehicle_id')
->join('stocks', 'stocks.id', '=', 'vehicles.stock_id')
->where('department_user.user_id', $userId)
->whereRaw('FIND_IN_SET(jobs.department_id, stocks.department_ids) > 0')
->distinct()
->get();
}
⚠️ 重要注意事项:
- 若
stocks.department_ids实际为 JSON 格式(如["1","3","5"]),请改用:->whereRaw('JSON_CONTAINS(stocks.department_ids, ?, "$")', ['"' . $departmentId . '"'])
并需在WHERE中先获取用户所有部门 ID(可通过子查询或预加载优化)。DISTINCT防止因一对多关联导致重复任务。- 生产环境建议为
department_user(user_id, department_id)、jobs(department_id, vehicle_id)、vehicles(stock_id)添加复合索引提升性能。
? 替代方案:Eloquent with Subquery(更 Laravel 化)
若坚持纯 Eloquent 风格,可将权限校验下沉为子查询:
$deptIds = auth()->user()->departments->pluck('id');
$jobs = Job::whereIn('department_id', $deptIds)
->whereExists(function ($query) {
$query->from('vehicles')
->join('stocks', 'stocks.id', '=', 'vehicles.stock_id')
->whereColumn('vehicles.id', 'jobs.vehicle_id')
->whereRaw('FIND_IN_SET(jobs.department_id, stocks.department_ids) > 0');
})
->with(['department', 'vehicle.stock'])
->get();
此方式语义清晰、利于测试与复用,但复杂度略高。最终选择应基于团队规范、数据库结构及性能实测结果。
总之,面对非标准关联字段(如 DEPARTMENT_IDS 字符串/JSON),灵活组合 Query Builder 与 Eloquent 是 Laravel 9 权限过滤的最佳实践。











