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

Laravel中能否实现多态到多态的模型关联?

多态多对多关联:获取关联模型而非中间表记录

我想要实现一个支持多个不同模型与其他多个不同模型建立关联的关系,已经创建了中间表triggerables的Schema:

Schema::create('triggerables', static function (Blueprint $table) {
  $table->id();
  $table->morphs('triggered_by');
  $table->morphs('triggerable');
});

对应的Triggerable模型代码:

class Triggerable extends Model
{
    public $timestamps = false;

    protected $table = 'triggerables';

    public function triggerable(): MorphTo
    {
        return $this->morphTo('triggerable');
    }

    public function triggeredBy(): MorphTo
    {
        return $this->morphTo('triggered_by');
    }
}

在其他模型中定义了关联方法:

public function testTriggerable(): MorphMany
{
    return $this->morphMany(Triggerable::class, 'triggered_by');
}

但当前这个关联返回的是中间表triggerables的记录,请问如何通过这个关联获取所有与之关联的不同模型实例?


解决方案

1. 预加载关联并提取模型

这是最直接的实现方式:通过with()预加载triggerable关联,再从中间表记录中提取对应的模型实例:

// 获取当前模型关联的所有目标模型
$relatedModels = $yourModel->testTriggerable()->with('triggerable')->get()->pluck('triggerable')->filter();
  • with('triggerable'):提前加载关联模型,避免N+1查询问题
  • pluck('triggerable'):从中间表记录中取出关联的模型实例
  • filter():过滤掉可能存在的无效关联记录

2. 用morphToMany直接定义关联

Laravel的morphToMany原生支持这种双向多态多对多场景,直接在业务模型中定义关联,返回目标模型而非中间表记录:

public function triggerables()
{
    return $this->morphToMany(
        \Illuminate\Database\Eloquent\Model::class,
        'triggered_by',
        'triggerables',
        'triggered_by_id',
        'triggerable_id',
        null,
        'triggerable_type'
    );
}

调用时直接获取关联模型集合:

$relatedModels = $yourModel->triggerables;

这个方法完全符合Laravel关联的使用习惯,无需额外处理中间表。

3. 自定义访问器(灵活场景)

如果需要更个性化的处理逻辑,可以给模型添加访问器:

public function getTriggerableModelsAttribute()
{
    return $this->testTriggerable->map(fn($item) => $item->triggerable)->filter();
}

之后直接通过属性访问关联模型:

$relatedModels = $yourModel->triggerable_models;

内容的提问来源于stack exchange,提问作者Mindaugas K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 07:50:19