Laravel / Eloquent:在模型中计算数据库字段的方式

时间:2017-09-02 11:50:45

标签: php laravel eloquent field

(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,

阿明。

2 个答案:

答案 0 :(得分:0)

从阅读问题来看,似乎laravel的before_script是您问题的正确答案,因为您可以将模型与不同的模型链接而不是" harcode"作为外键的模型类型。

由于多态关系允许模型在一个关联上属于多个其他模型。

用例子检查出来:

  

https://console.developers.google.com/apis/dashboard

答案 1 :(得分:0)

从你的例子中可以看出你在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执行此操作(您只需要在开始时执行此操作,之后使用associate()方法时会自动执行此操作。)< / p>

或者,您可以设置变形地图:

use Illuminate\Database\Eloquent\Relations\Relation;

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

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