原因
我有一个包含slugs的表的遗留系统。
当这些记录匹配时,它代表某种具有布局ID的页面。
因为这些页面可能有不同的资源需求,所以它取决于可以连接表的布局ID。
我使用Laravel的Eloquent模型。
我想要的是拥有一个包含布局特定关系的子模型。
class Page extends Model {
// relation 1, 2, 3 that are always present
}
class ArticlePage extends Page {
// relation 4 and 5, that are only present on an ArticlePage
}
但是在我的控制器中,为了知道我需要哪种布局,我必须查询:
url: / {slug}
$page = Slug::where('slug', $slug)->page;
if ($page->layout_id === 6) {
//transform $page (Page) to an ArticlePage
}
因此,我得到了一个Page的实例,但我想将其转换或转换为ArticlePage的实例来加载它的附加关系。我怎样才能做到这一点?
答案 0 :(得分:4)
你需要调查Laravel中的Polymorphic relations来实现这一目标。多态关系允许您根据字段的类型检索不同的模型。在Slug
模型中,您需要这样的内容:
public function page()
{
return $this->morphTo('page', 'layout_id', 'id');
}
在您的某个服务提供商中,例如AppServiceProvider
您需要提供变形图来告诉Laravel将某些ID映射到某些模型类。例如:
Relation::morphMap([
1 => Page::class,
// ...
6 => ArticlePage::class,
]);
现在,无论何时使用page
关系,Laravel都会检查类型并为您提供正确的模型。
注意:我对参数等不是100%肯定,我没有测试过,但您应该可以从文档中解决这个问题。
如果您的layout_id
位于Page
模型上,我看到的唯一解决方案是向您的Page
模型中添加能够转换的模式您的现有页面基于其ArticlePage
属性的layout_id
或其他页面类型。你应该可以尝试这样的事情:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Page extends Model
{
const LAYOUT_ARTICLE = 6;
protected $layoutMappings = [
// Add your other mappings here
self::LAYOUT_ARTICLE => ArticlePage::class
];
public function toLayoutPage()
{
$class = $this->layoutMappings[$this->layout_id];
if (class_exists($class)) {
return (new $class())
->newInstance([], true)
->setRawAttributes($this->getAttributes());
}
throw new \Exception('Invalid layout.');
}
}
这样做的目的是查找基于layout_id
属性的映射,然后创建一个正确类型的新类,并使用您正在创建的页面填充其属性。这应该是你需要的,如果你看看Laravel的Illuminate\Database\Eloquent::newFromBuilder()
方法,Laravel在创建新模型实例时会调用它,你可以看到发生了什么以及我如何获得上面的代码。您应该能够像这样使用它:
$page = Slug::where('slug', $slug)
->first()
->page
->toLayoutPage();
这将为您提供ArticlePage
答案 1 :(得分:0)
据我所知,没有内置功能。 但你可以这样做。
$page = Slug::where('slug', $slug)->page;
if ($page->layout_id === 6) {
$page = ArticlePage::fromPage($page);
}
然后在ArticlePage上创建静态方法
public static function fromPage(Page $page)
{
$articlePage = new self();
foreach($page->getAttributes() as $key => $attribute) {
$articlePage->{$key} = $attribute;
}
return $articlePage
}
根据您的用例,可能很聪明地创建一个静态方法,在Slug的关系页面()上自动执行此操作。