[英]Laravel/Eloquent: calculated database field in model how
(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]
id
parent_id
kind (house | car | user)
data_id (key into house | car | user table)
...
下一步是在 Eloquent 中“以某种方式”对“名称”字段进行编码,因此看起来它仍然是“树节点”模型的一部分,这就是我被卡住的地方。 我在模型中尝试了一个“计算字段”,如文档中所述,如下所示:
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,则不包括“名称”。
通过更改树节点来设置“名称”时会出现类似的问题,如果要更改名称,我必须将其写回正确的数据库,并且还需要JSON支持。 我不知道如何实现这一目标。 我读过访问器,如 getNameAttribute 和 setNameAttribute,但据我所知,它们仅在树节点模型中有“名称”字段时才起作用。
任何人都可以将我的鼻子指向正确的方向......我可以以某种方式重新设计我的树节点模型,以便它包含一个“名称”字段,该字段从其他表中获取其内容,并且,如果我为其分配一个值,则将名称写入其他表,但在其他方面的行为与将其包含在“树节点”模型中时完全一样?
谢谢,
阿明。
从阅读问题来看,laravel 的Polymorphic Relations
似乎是您问题的正确答案,因为您可以将模型与不同的模型联系起来,而不是将模型的类型“硬编码”为外键。
由于多态关系允许模型在单个关联上属于多个其他模型。
看看这个例子:
https://laravel.com/docs/5.4/eloquent-relationships#polymorphic-relations
从您的示例来看,您似乎在追求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
执行此kind_type
(您只需要在开始时执行此操作,之后当您使用associate()
方法时,这将自动发生)。
或者,您可以设置一个变形贴图:
use Illuminate\Database\Eloquent\Relations\Relation;
Relation::morphMap([
'user' => 'App\User',
]);
您可以将上述内容添加到AppServiceProvider
的boot()
方法中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.