(Laracast上发布的问题也没有透露任何答案,所以我试试Stackoverflow)
嗨社区,
我必须使用一个模型解决Eloquent中的数据库问题,该模型具有要从不同数据库读取的字段。由于我很难用英语/ OOP / Laravel / Eloquent / PHP术语表达我的问题,我将尝试在一个例子中表达我的需求(不关心正确的PHP语法)。
鉴于存在类似树状结构的模型,所使用的属性通常是:
[treenode]
id
parent_id (=self referencing key to id)
name
...
现在说树是存储指向不同类型节点的指针,比如房屋,汽车和用户,每个节点都存储在不同的表/模型中:
[house]
id
name
street address
zip
...
[car]
id
name
brand
horsepower
...
[user]
id
name
age
gender
...
问题显然是要有一个“treenode”模型,它透明地访问其他数据库以填充所有模型共有的“名称”字段来绘制树。
我考虑过将treenode模型更改为:
[treenode]
id
parent_id
kind (house | car | user)
data_id (key into house | car | user table)
...
下一步是“以某种方式”编码Eloquent中的“名称”字段,因此看起来它仍然是“treenode”模型的一部分,这就是我被困住的地方。我在模型中尝试了一个“计算字段”,如文档中所述,如下所示:
public function name() {
select case $this->kind {
case house: return House::findorfail($this->data_id)->first()
case car: return Car::findorfail($this->data_id)->first()
case user: return User::findorfail($this->data_id)->first()
}
}
乍一看这确实有效,但显然“名称”并未真正包含在模型的属性列表中,因此它不会被序列化,即如果我JSON_encode一个treenode,则不包括“name”。 / p>
当通过更改treenode设置“name”时会出现类似的问题,如果要更改名称,我必须将其写回正确的数据库,并且还需要JSON支持。我不知道如何实现这一目标。我读了一些访问器,比如getNameAttribute和setNameAttribute,但据我所知,只有在treenode模型中有一个“name”字段时它们才能工作。
任何人都可以将我的鼻子指向正确的方向......我可以以某种方式修改我的treenode模型,因此它包含了一个“名称”字段,它从其他表中获取其内容,并且,如果我为其分配值,则写入将名称放入其他表中,但其他方式与“treenode”模型中的名称完全相同?
THX,
阿明。
答案 0 :(得分:0)
从阅读问题来看,似乎laravel的before_script
是您问题的正确答案,因为您可以将模型与不同的模型链接而不是" harcode"作为外键的模型类型。
由于多态关系允许模型在一个关联上属于多个其他模型。
用例子检查出来:
答案 1 :(得分:0)
从你的例子中可以看出你在Polymorphic Relationships之后。
首先,将data_id
和kind
更改为kind_id
和kind_type
,即
data_id
变为kind_id
和
kind
变为kind_type
您可以使用以下命令在迁移文件中执行此操作:
$table->morphs('kind');
然后在您的treenode
模型中添加:
/**
* Kind Relationship
*
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function kind()
{
return $this->morphTo();
}
/**
* Get the name from the "kind" relationship
*
* @return mixed
*/
public function getNameAttribute()
{
return $this->kind->name;
}
然后你可以做到以下几点:
$treeNode = App\TreeNode::with('kind')->first();
$treeNode->name; //This would be the name on the other model
(以上假设您treenode
模型为App\TreeNode
。如果不是,则只需将其更改为正确的模型。
希望这有帮助!
修改
如果您已经在使用生产环境/需要按原样保存数据,那么您需要将kind_type
更新为其引用的模型的完全限定名称空间,例如。
DB::table('treenode')
->where('kind_type', 'user')
->update(['kind_type' => \App\User::class]);
您需要为所有不同的kind_type
执行此操作(您只需要在开始时执行此操作,之后使用associate()
方法时会自动执行此操作。)< / p>
或者,您可以设置变形地图:
use Illuminate\Database\Eloquent\Relations\Relation;
Relation::morphMap([
'user' => 'App\User',
]);
您可以将上述内容添加到boot()
中的AppServiceProvider
方法。