2014-07-12 178 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