2017-09-02 34 views
0

(问题上Laracast张贴过,没有透露任何答案,所以我给#1一试)Laravel /雄辩:模型计算数据库字段如何

嗨社区,

我已经解决一个数据库问题,在一个模型中拥有一个可以从不同数据库中读取的字段。由于我在使用英文/ 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) 
... 

下一步是“莫名其妙”代码“名”雄辩领域,所以它看起来像它仍然是“树节点”的一部分模型,这是我卡住的地方。我尝试了“计算字段”的模式里面,像文档所描述的,就像这样:

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”不包括在内。

和设置“名称”,通过改变一个树节点时,会出现类似问题,如果名字改变,我不得不把它写回到正确的数据库,并且还需要JSON支持。我不知道如何才能做到这一点。我读了关于访问器的信息,比如getNameAttribute和setNameAttribute,但据我所见,只有treenode模型中存在“名称”字段时才能使用。

任何人都可以将我的鼻子指向正确的方向......我可以以某种方式重做我的treenode模型,因此它包含了从其他表中获取其内容的“名称”字段,并且,如果我为其分配值,将名称写入其他表格中,但其他行为与包含在“treenode”模型中时完全相同?

Thx,

Armin。

+0

您使用的是什么版本的Laravel? –

+0

V5.4,对不起,我忘了提。但是我已经看到了你提出的答案,这看起来很有希望。我今晚会试一试,并尽快告诉你结果。同时:谢谢! – Nimral

回答

0

从阅读问题似乎laravel的Polymorphic Relations是你的问题的正确答案,因为你可以连接不同型号的模型,而不是“harcode”的模式作为外键的类型。

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

检查了这一点与例如:

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

+0

这似乎是要走的路,但似乎罗斯打了你几秒钟才能给出答案。尽管如此,非常感谢您的意见,似乎这正是我所期待的! – Nimral

+0

哈哈很好,你可以upvote :) :) – Sletheren

+0

先测试,然后加油:-) Upvote来了,承诺:-) – Nimral

0

从你的例子,它听起来就像你Polymorphic Relationships后。

首先,改变data_idkindkind_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()方法,这将自动发生这样做开头,后)。

或者,你可以设置一个变形地图:

use Illuminate\Database\Eloquent\Relations\Relation; 

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

您可以将上述添加到boot()方法在AppServiceProvider

+0

嗨Ross,到目前为止没有太多的运气。两个问题:首先,我改变了你的建议模型,但Treenode模型似乎还没有包含“名称”属性,这是我想要实现的目标之一。 – Nimral

+0

此外,命名空间似乎有一个严重的问题,我的模型没有找到。我得到这个错误:“Symfony \ Component \ Debug \ Exception \ FatalThrowableError:Class'user'not found in [...] \厂商\ laravel \框架\ SRC \照亮\数据库\锋\关注\ HasRelationships.php:487。我尝试将App \ User语句放入我的控制器以及Treenode模型文件中,并且我可以在两个文件中成功查询任何用户模型,例如, $ test = User :: find(6),但是当我从控制器调用$ node-> kind->名称时,错误仍然存​​在。 – Nimral

+0

你也改变你的表列名称吗?确保您正在关注PSR-1和PSR-4例如类名与文件名完全匹配,并且它们被写入StudlyClass,即'User.php'和'class User''''user'。 –