Laravel Eloquent和命名空间问题

Len*_*eng 6 php mysql laravel eloquent laravel-4

我正在为Laravel构建一个CMS包.

此软件包中的所有模型都与IoC容器绑定并解析,以便在软件包的任何单独部署中轻松覆盖它们.

对于非多态关系,这有一定的魅力.

例如,一个Page有很多PageModules,所以它的关系改为:

// \Angel\Core\Page

public function modules()
{
    return $this->hasMany('PageModule');
}
Run Code Online (Sandbox Code Playgroud)

至:

// \Angel\Core\Page

public function modules()
{
    return $this->hasMany(App::make('PageModule'));
}
Run Code Online (Sandbox Code Playgroud)

但是我无法弄清楚如何用多态关系做同样的事情.

例如,菜单包含MenuItems,每个MenuItem可以绑定到一个其他模型,例如Page或BlogPost.

为了实现这个Laravel方式,我为MenuItem添加了以下关系:

// \Angel\Core\MenuItem

public function linkable()
{
    return $this->morphTo();
}
Run Code Online (Sandbox Code Playgroud)

而这种关系LinkableModel,其全系车型,如网页和博客帖子延伸:

// \Angel\Core\LinkableModel

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

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

linkable_type      |  linkable_id
-------------------|--------------
\Angel\Core\Page   |   11
\Angel\Core\Page   |   4
Run Code Online (Sandbox Code Playgroud)

这很好用,但是我需要linkable_type说'Page'而不是'\ Angel\Core\Page',并且要从IoC的'Page'中解析而不是硬编码到特定的命名空间类.

我试过的:

根据这个问题,它应该像为$morphClasslinkable()类定义属性一样容易,如下所示:

// \Angel\Core\Page
protected $morphClass = 'Page';
Run Code Online (Sandbox Code Playgroud)

但是当我应用它时,将menus_items表更改为如下所示:

linkable_type  |  linkable_id
---------------|--------------
Page           |   11
Page           |   4
Run Code Online (Sandbox Code Playgroud)

... Class 'Page' not found.只要在MenuItem上调用linkable(),我就会收到错误.

这是Eloquent中引发错误的确切行.

所以,我挖到了Eloquent,并认为我可以逃脱这样的事情:

// \Angel\Core\MenuItem

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

...感觉非常接近,但是唉:Eloquent在填充MenuItem的其余属性/列之前调用linkable(),因此$ this-> linkable_type为null,因此无法解决IoC中的任何问题.

非常感谢您提供任何指导!

Qua*_*unk 4

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

这在任何情况下都不起作用,因为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
);
Run Code Online (Sandbox Code Playgroud)

注意:这是 4.2.6 版本中的代码,上面链接的代码似乎来自更高版本,并且略有不同,并且该函数返回 aBelongsTo而不是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
    );
}
Run Code Online (Sandbox Code Playgroud)

这实际上应该有效(尚未测试过),但我不确定它在某些边缘情况下可能会导致任何副作用。

或者,也许您也可以覆盖模型中的整个函数MenuItem,然后调整相关部分:

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
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:这适用于延迟加载,但不适用于急切加载。 此处提出了寻求急切加载解决方案的问题。

那么关系就会像往常一样:

public function linkable()
{
    return $this->morphTo();
}
Run Code Online (Sandbox Code Playgroud)