Laravel Eloquent多层belongsToMany关联如何获取中间表模型的关联关系
解决方案
你当前的问题是默认belongsToMany关联没有绑定自定义中间表模型,且直接加载的是Resource模型全局的actions关联,和中间表access_resource的绑定无关,按以下步骤调整即可实现需求。
前置配置修正
首先确认AccessResource中间表模型配置正确,因为需要作为独立模型加载关联:
use Illuminate\Database\Eloquent\Relations\Pivot; class AccessResource extends Pivot // 也可以继承Model,继承Pivot更适配中间表场景 { public $incrementing = true; // 必须开启,因为你的中间表有自增主键id protected $table = 'system_access_resource'; public function actions() { return $this->belongsToMany(Action::class, 'system_access_resource_action', 'access_resource_id', 'action_id'); } // 定义和Resource的关联,方便后续查询 public function resource() { return $this->belongsTo(Resource::class, 'resource_id'); } }
方案1:保留原关联结构,最小改动实现
第一步:修改Access模型的resources关联
class Access extends Model { public function resources() { return $this->belongsToMany(Resource::class, 'system_access_resource', 'access_id', 'resource_id') ->using(AccessResource::class) // 绑定自定义中间表模型 ->withPivot('id'); // 必须查询中间表主键,用于加载关联actions } }
第二步:调整查询逻辑
查询时加载中间表的actions关联,再通过访问器挂载到Resource对象上:
// 执行查询 $accessList = Access::with(['resources' => function ($query) { $query->with('pivot.actions'); }])->get(); // 给Resource模型追加actions访问器,直接输出你要的结构 class Resource extends Model { // 原有逻辑保留 public function getActionsAttribute() { // 如果是从Access关联查询过来,就返回中间表绑定的actions,否则返回全局actions return $this->pivot?->actions ?? $this->belongsToMany(Action::class, 'resource_action', 'resource_id', 'action_id')->get(); } protected $appends = ['actions']; // 接口输出时自动带上该字段 }
方案2:调整关联层级,逻辑更清晰(推荐)
该方案避免混淆Resource全局actions和当前Access下的专属actions,维护成本更低:
第一步:给Access模型新增中间表关联
class Access extends Model { // 原有resources关联可以保留,也可以删掉 public function accessResources() { return $this->hasMany(AccessResource::class, 'access_id'); } }
第二步:查询并格式化输出
// 嵌套加载关联 $accessList = Access::with([ 'accessResources.resource', 'accessResources.actions' ])->get(); // 格式化输出为你需要的结构 $result = $accessList->map(function ($access) { return [ 'id' => $access->id, 'name' => $access->name, 'resources' => $access->accessResources->map(function ($accessResource) { return [ 'id' => $accessResource->resource->id, 'name' => $accessResource->resource->name, 'actions' => $accessResource->actions ]; }) ]; });
注意事项
- 必须保证
system_access_resource表有自增id主键,否则无法关联system_access_resource_action表 - 如果用API资源层做输出,格式化逻辑可以统一放到资源类中,代码更整洁
内容的提问来源于stack exchange,提问作者Rafael L R
相关产品推荐
相关产品推荐

