简体   繁体   English

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

[英]Laravel/Eloquent: calculated database field in model how

(Question posted on Laracast too, didn't reveal any answer yet, so I give Stackoverflow a try) (Laracast 上也有问题,还没有给出答案,所以我试试 Stackoverflow)

Hi community,嗨社区,

I have to solve a database problem in Eloquent with a model which has a field which is to be read from different databases.我必须使用模型解决 Eloquent 中的数据库问题,该模型具有要从不同数据库读取的字段。 Since I have difficulties expressing my problem properly in English/OOP/Laravel/Eloquent/PHP terminology, I'll try to express my needs in an example (don't care much about correct PHP syntax).由于我很难用英语/OOP/Laravel/Eloquent/PHP 术语正确表达我的问题,我将尝试用一个例子来表达我的需求(不太关心正确的 PHP 语法)。

Given there is a model resembling a tree-like structure, attributes used are usually:鉴于有一个类似于树状结构的模型,使用的属性通常是:

[treenode]
id
parent_id (=self referencing key to id)
name
...

Now say the tree is to store pointers to nodes of different kinds, say, houses, cars and users, each of which is stored in a different table/model:现在说树是存储指向不同类型节点的指针,比如房子、汽车和用户,每个节点都存储在不同的表/模型中:

[house]
id
name
street address
zip
...

[car]
id
name
brand
horsepower
...

[user]
id
name
age
gender
...

The problem is obviously to have a model for "treenode" which transparently accesses the other databases to populate the "name" field, which all the models have in common, to draw the tree.问题显然是要有一个“树节点”模型,它透明地访问其他数据库以填充所有模型共有的“名称”字段,以绘制树。

I thought about changing the treenode model to:我想过将树节点模型更改为:

[treenode]
id
parent_id
kind (house | car | user)
data_id (key into house | car | user table)
...

The next step was to "somehow" code the "name" field in Eloquent, so it appears like it still was part of the "treenode" model, and this is where I am stuck.下一步是在 Eloquent 中“以某种方式”对“名称”字段进行编码,因此看起来它仍然是“树节点”模型的一部分,这就是我被卡住的地方。 I tried a "calculated field" inside the model, like described in the docs, like so:我在模型中尝试了一个“计算字段”,如文档中所述,如下所示:

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()
}
}

This does work somehow at first glance, but obviously "name" isn't really included in the model's attributes list, so it doesn't get serialized, ie if I JSON_encode a treenode, "name" is not included.乍一看,这确实以某种方式起作用,但显然“名称”并未真正包含在模型的属性列表中,因此它不会被序列化,即如果我对树节点进行 JSON_encode,则不包括“名称”。

And a similar problem arises when setting "name" by changing a treenode, if the name is to be changed, I'd have to write it back into the correct database, and JSON support was also required.通过更改树节点来设置“名称”时会出现类似的问题,如果要更改名称,我必须将其写回正确的数据库,并且还需要JSON支持。 I have no clue how I could achieve this.我不知道如何实现这一目标。 I read about accessors, like getNameAttribute and setNameAttribute but as far as I have seen they work only if there is a "name" field in the treenode model.我读过访问器,如 getNameAttribute 和 setNameAttribute,但据我所知,它们仅在树节点模型中有“名称”字段时才起作用。

Can anyone point my nose into the right direction ... can I somehow rework my treenode model so it incudes a "name" field which gets its contents from the other tables, and, if I asssign a value to it, writes the name into the other tables, but otherwise behave exactly like when it was included in the "treenode" model?任何人都可以将我的鼻子指向正确的方向......我可以以某种方式重新设计我的树节点模型,以便它包含一个“名称”字段,该字段从其他表中获取其内容,并且,如果我为其分配一个值,则将名称写入其他表,但在其他方面的行为与将其包含在“树节点”模型中时完全一样?

Thx,谢谢,

Armin.阿明。

From reading problem it seems that laravel's Polymorphic Relations are the right answer for your problem, since you can link a model with different models and not "harcode" the type of the model as a foreign key.从阅读问题来看,laravel 的Polymorphic Relations似乎是您问题的正确答案,因为您可以将模型与不同的模型联系起来,而不是将模型的类型“硬编码”为外键。

Since polymorphic relations allow a model to belong to more than one other model on a single association.由于多态关系允许模型在单个关联上属于多个其他模型。

Check this out with example:看看这个例子:

https://laravel.com/docs/5.4/eloquent-relationships#polymorphic-relations https://laravel.com/docs/5.4/eloquent-relationships#polymorphic-relations

From your example it sounds like you're after Polymorphic Relationships .从您的示例来看,您似乎在追求Polymorphic Relationships

Firstly, change data_id and kind to kind_id and kind_type ie首先,将data_idkind更改为kind_idkind_type

data_id becomes kind_id and data_id变成kind_id并且

kind becomes kind_type kind变成kind_type

you can do this in your migrations file with:您可以在迁移文件中使用以下命令执行此操作:

$table->morphs('kind');

Then in your treenode model add:然后在您的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;
}

Then you could do the following:那么你可以执行以下操作:

$treeNode = App\TreeNode::with('kind')->first();

$treeNode->name; //This would be the name on the other model

(The above assumes that you treenode model is App\\TreeNode . If it isn't then simply change it to whatever is correct). (以上假设您的treenode模型是App\\TreeNode 。如果不是,则只需将其更改为正确的即可)。

Edit编辑

If you're already working with a production environment / need to keep your data as is then you will need to update the kind_type to be the fully qualified namespace of the model that it's referencing eg如果您已经在生产环境中工作/需要保持数据原样,那么您需要将kind_type更新为它引用的模型的完全限定名称空间,例如

DB::table('treenode')
    ->where('kind_type', 'user')
    ->update(['kind_type' => \App\User::class]);

You will need to do this for all the different kind_type s (you should only need to do this at the beginning, after that when you use the associate() method this will happen automatically).您将需要对所有不同的kind_type执行此kind_type (您只需要在开始时执行此操作,之后当您使用associate()方法时,这将自动发生)。

Alternatively, you can set up a morph map:或者,您可以设置一个变形贴图:

use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
    'user' => 'App\User',
]);

You can add the above to the boot() method in your AppServiceProvider .您可以将上述内容添加到AppServiceProviderboot()方法中。

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

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