繁体   English   中英

Laravel/Eloquent:模型中计算的数据库字段如何

[英]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_idkind更改为kind_idkind_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',
]);

您可以将上述内容添加到AppServiceProviderboot()方法中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM