Laravel中能否创建双向多态多对多关联?
Laravel 实现双向多态多对多关联('shown' 和 'recommendable')
你遇到的问题核心是没有明确指定双向多态关联的外键与关联键,Laravel 的 morphToMany 方法默认会根据模型名生成字段规则,但你的中间表是双向多态结构,必须手动指定字段映射才能正常工作。
问题分析
你的中间表 recommendables 包含两组多态字段:
shown_id/shown_type:标记「展示项」的模型ID和类型recommendable_id/recommendable_type:标记「推荐项」的模型ID和类型
原关联定义中,morphToMany 会默认将当前模型的主键对应到第二个参数(如recommendable)的_id字段,导致框架错误查找group_id这类不符合表结构的字段。
修正后的关联实现
修改 RecommendableTrait,为每个关联手动指定外键(当前模型在中间表的字段)和关联键(关联模型在中间表的字段):
trait RecommendableTrait { // 当前模型作为「展示项」关联的推荐分组 public function recommendedGroups() { return $this->morphToMany( Group::class, 'recommendable', 'recommendables', 'shown_id', // 当前模型在中间表的ID字段(作为展示项) 'recommendable_id'// 关联模型在中间表的ID字段(作为推荐项) )->withTimestamps(); } // 当前模型作为「展示项」关联的推荐商品 public function recommendedProducts() { return $this->morphToMany( Product::class, 'recommendable', 'recommendables', 'shown_id', 'recommendable_id' )->withTimestamps(); } // 将当前模型作为「推荐项」的展示分组 public function shownGroups() { return $this->morphToMany( Group::class, 'shown', 'recommendables', 'recommendable_id',// 当前模型在中间表的ID字段(作为推荐项) 'shown_id' // 关联模型在中间表的ID字段(作为展示项) )->withTimestamps(); } // 将当前模型作为「推荐项」的展示商品 public function shownProducts() { return $this->morphToMany( Product::class, 'shown', 'recommendables', 'recommendable_id', 'shown_id' )->withTimestamps(); } // 可选:合并获取所有推荐资源(分组+商品) public function allRecommended() { return $this->recommendedGroups->merge($this->recommendedProducts); } // 可选:合并获取所有展示当前模型的资源 public function allShownOn() { return $this->shownGroups->merge($this->shownProducts); } }
关键参数说明
morphToMany 的核心参数对应关系:
$related:关联的目标模型类$name:多态关联的名称(对应中间表的字段前缀)$table:中间表名称$foreignPivotKey:当前模型在中间表的ID字段$relatedPivotKey:关联模型在中间表的ID字段
测试验证
可以通过以下代码验证关联是否正常工作:
// 创建测试数据 $group = Group::create(['name' => '数码分组']); $product = Product::create(['name' => '手机']); // 给分组添加推荐商品 $group->recommendedProducts()->attach($product); // 获取分组的推荐商品 dump($group->recommendedProducts); // 应返回创建的手机商品 // 获取商品被哪些分组展示 dump($product->shownGroups); // 应返回创建的数码分组
注意事项
- 确保中间表的
morphs('shown')和morphs('recommendable')已正确生成对应字段 - 如果模型主键不是默认的
id,需要在morphToMany中额外指定$parentKey和$relatedKey参数
内容的提问来源于stack exchange,提问作者Stroomschok
相关产品推荐
相关产品推荐

