簡體   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