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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 00:09:03