发现 ORM 方法 MorphToMany 的一个 Bug

person表
id integer
name string
address_rel表
id integer
lsc integer (11 or 101) 此处在 MorphMap 定义映射关系
lid integer
address integer
address表
id integer
country integer 国家ID
province integer 省ID
city integer 市区ID
….. 省略

首先,在AppServiceProvider我定义了morphMap:

Relation::morphMap([
    '11' => Person::class,
    '101' => Company::class,
]);

然后,在Person模型中,定义了获取所有地址的方法:

public function address()
{
    return $this->morphToMany(
        Address::class,  //地址表
        'lsc',  //多态关联表中的映射表关系
        'address_rel',  //多态关联表
        'lid', //映射表ID
        'address' //地址ID
    );
}

最后,在 Controller 层,来获取 Person 的所有地址:

$person = Person::find(1);
$person->address->toArray();

此时报错信息为:

"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'lu_address_rel.lsc_type' in 'field list' (SQL: select `lu_address`.*, `lu_address_rel`.`lid` as `pivot_lid`, `lu_address_rel`.`address` as `pivot_address`, `lu_address_rel`.`lsc_type` as `pivot_lsc_type` from `lu_address` inner join `lu_address_rel` on `lu_address`.`id` = `lu_address_rel`.`address` where `lu_address_rel`.`lid` = 56 and `lu_address_rel`.`lsc_type` = 11)"

通过上面可以看到,我们传的 lsc 在 Laravel 中自动拼上了 _type,而 lid 是正确的,这时我们通过追查源码发现

发现 ORM 方法 MorphToMany 的一个 Bug
如上图所示,在我们传入 $foreignPivotKey 字段时,Laravel 做了相应的判断处理,如果传了这个字段(也就是 lid),则完全使用用户传入的值,否则将拼接为 $name . ‘_id’ ,这里的 $name 就是我们在 Model 中传入的第二个参数

那么我们接着来看 $name 参数是如何处理的

发现 ORM 方法 MorphToMany 的一个 Bug
追查到这里发现,Laravel 是直接将用户传入的 $name 参数拼上了 _type ,这就出现了上面的报错信息。

通过以上信息发现我们如果要用到 MorphToMany 方法,就必须要把表设计改为 Laravel 的规范,否则,目前的 Laravel 版本中用 MorphToMany 是完成不了需求的。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 4

我靠,那链接不就是我的么。。。 :grin:

3年前 评论
邢闯洋 (楼主) 3年前
黑将军

或许不能算bug吧,只是扩展性差,确实用这个得按照laravel标准来设计表,不方便,之前也打算用MorphToMany,也是遇到相同的问题

3年前 评论
邢闯洋 (楼主) 3年前

发现wx群友一枚 :smile:

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!