發現 ORM 方法 MorphToMany 的一個 Bug

邢闖洋發表於2020-07-17
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 協議》,轉載必須註明作者和本文連結

相關文章