2014-07-12 179 views
6

我正在構建一個CMS package for LaravelLaravel雄辯和命名空間問題

此包中的所有models都綁定到IoC容器並從中解析出來,以便在包的任何單獨部署中很容易覆蓋它們。

對於非多態關係,這已經成爲一種魅力。

例如,Page有很多PageModules,所以它的關係從:更改

// \Angel\Core\Page 

public function modules() 
{ 
    return $this->hasMany('PageModule'); 
} 

到:

// \Angel\Core\Page 

public function modules() 
{ 
    return $this->hasMany(App::make('PageModule')); 
} 

但我一直無法弄清楚如何做同樣的事情與多態關係。

例如,菜單包含MenuItems,並且每個MenuItem可以綁定到單個其他模型,例如Page或BlogPost。

要做到這一點的Laravel方式,我已經添加了以下關係菜單項:

// \Angel\Core\MenuItem 

public function linkable() 
{ 
    return $this->morphTo(); 
} 

而且這種關係LinkableModel,其全系車型,如網頁和博客帖子延長:

// \Angel\Core\LinkableModel 

public function menuItem() 
{ 
    return $this->morphOne(App::make('MenuItem'), 'linkable'); 
} 

menus_items表(其中MenuItems使用)具有以下行:

linkable_type  | linkable_id 
-------------------|-------------- 
\Angel\Core\Page | 11 
\Angel\Core\Page | 4 

這很好,但我需要linkable_type來說'頁'而不是'\ Angel \ Core \ Page',並從IoC的'Page'中解析,而不是硬編碼到一個特定的命名空間類。

我試了一下:

this question,它應該是爲定義$morphClass屬性可鏈接()類,像這樣一樣簡單:

// \Angel\Core\Page 
protected $morphClass = 'Page'; 

但當我申請這個,並改變menus_items表看起來像這樣:

linkable_type | linkable_id 
---------------|-------------- 
Page   | 11 
Page   | 4 

...只要在MenuItem上調用linkable()時我只會得到一個Class 'Page' not found.錯誤。

This is the exact line in Eloquent that throws the error.

所以,我挖成雄辯,我想我或許可以用這樣的閃避:

// \Angel\Core\MenuItem 

public function linkable() 
{ 
    return $this->morphTo(null, App::make($this->linkable_type)); 
} 

......這種感覺如此接近,但很可惜:雄辯呼籲聯()在填充MenuItem的屬性/列的其餘部分之前,因此$ this-> linkable_type爲空,因此不會解析IoC中的任何內容。

非常感謝您提前接受任何指導!

回答

4
public function linkable() 
{ 
    return $this->morphTo(null, App::make($this->linkable_type)); 
} 

這將不會在任何情況下工作,因爲morphTo()Illuminate\Database\Eloquent\Model 預計多態性關係的

  1. 名稱( '聯')
  2. 類型的對象被變形('Page',不是Page的實例)
  3. 對象的ID將演變

如果不能提供他們,Laravel是足夠聰明,他們猜測,然後相應地返回Illuminate\Database\Eloquent\MorphTo對象。

另外,$this->linkable_type$this->linkable_id實際上在該上下文中應該不是null

讓我們快速瀏覽一下morphTo()功能的相關部分:

$instance = new $class; 

return new MorphTo(
    $instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name 
); 

注意:這是4.2.6版本的代碼,上面鏈接的代碼似乎是從稍後版本,並略有不同,該函數返回BelongsTo而不是MorphTo對象。

問題具體是$instance = new $class; - 該類僅僅是實例化而未解決。但是,你可以抓住的魔法一部分,處理它自己:

public function linkable() 
{ 
    $instance = App::make($this->linkable_type); 

    $id = 'linkable_id'; 
    $type = 'linkable_type'; 
    $name = 'linkable'; 

    return new MorphTo(
     $instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name 
    ); 
} 

這應該實際工作(沒有測試過),但我不知道任何副作用,它可能會導致某些邊緣案例。

或者你也可以只覆蓋全功能的MenuItem -model,只是調整相關部分:

public function morphTo($name = null, $type = null, $id = null) 
{ 
    if (is_null($name)) 
    { 
     list(, $caller) = debug_backtrace(false); 

     $name = snake_case($caller['function']); 
    } 

    list($type, $id) = $this->getMorphs($name, $type, $id); 

    //eager loading 
    if (is_null($class = $this->$type)) 
    { 
     return new MorphTo(
      $this->newQuery(), $this, $id, null, $type, $name 
     ); 
    } 

    // normal lazy loading 
    else 
    { 
     // this is the changed part 
     $instance = \App::make($class); // new $class; 

     return new MorphTo(
      $instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name 
     ); 
    } 
} 

注意:這非常適用於延遲加載,但不爲急切加載工作。 An issue has been raised seeking a solution for eager-loading here.

的關係將被如常:

public function linkable() 
{ 
    return $this->morphTo(); 
} 
+0

你是一個天才。非常感謝你的幫助。你說我們不能傳入null名稱,因爲它無法推斷出來,但[這讓我覺得我們可以!](http://laravel.com/api/source-class- Illuminate.Database.Eloquent.Model.html#523) – Leng

+0

儘管我使用Laravel 4.1,它具有[此morphTo](https://github.com/laravel/framework/blob/2f1c6cd51dfd51d573977f07e34ba609cc0bf3ac/src/Illuminate/Database/Eloquent/ Model.php#L724)。 – Leng

+0

老鼠!Quasdunk,當我急切加載這種關係時,它不再起作用,因爲在這種情況下,$ this-> linkable_type確實爲null。我猜想在加載時,Eloquent會在填寫屬性/列之前調用關係方法。 :(我會繼續尋找一個可行的解決方案 – Leng