[英]Laravel hasMany Many to Many To One Eloquent
我沒有太多的運氣從Laravel的方式解決這個問題。 所以我提出了兩個問題。
鑒於我有一輛汽車並且該汽車可以有許多功能,但功能也按功能類型分隔,如何為所述汽車返回所有功能,將功能類型分開?
我有四個表,listing_features是數據透視表:
我有以下代碼,它產生了我需要的東西,但是當我使用它時,我得到一個Laravel錯誤......“在字符串上調用成員函數addEagerConstraints()”...因為我這樣調用它:
Listing::with(
'features',
)->get();
我用來生成我想要的格式(不是堅定的)數據的代碼是
public function features()
{
$out = array();
$features = $this->hasMany('App\Models\ListingFeature', 'listing_id', 'id')->select('feature_id')->get();
$types = ListingFeatureType::all();
foreach($types as $key => $obj){
$out[$key]['listing_feature_type_id'] = $obj->id;
$out[$key]['name'] = $obj->listing_feature_type;
$out[$key]['features'] = ListingFeatureValue::whereIn('id', $features->toArray())->where('listing_feature_type_id', '=', $obj->id)->get()->toArray();
}
return json_encode($out);
}
哪個回報:
[
{
"listing_feature_type_id": "0f40888c-3b09-40ed-aef6-0fddc1a155b6",
"name": "Safety",
"features": [
{
"id": "0ed0ad63-a6ed-4818-8c6f-ee048694dcd9",
"listing_feature_type_id": "0f40888c-3b09-40ed-aef6-0fddc1a155b6",
"listing_feature_text": "Anti-Lock Brakes"
},
{
"id": "37abeef2-dc22-4995-8503-f89962242ea6",
"listing_feature_type_id": "0f40888c-3b09-40ed-aef6-0fddc1a155b6",
"listing_feature_text": "Collision Detection"
},
{
"id": "3c0728e1-91f7-4f44-ac0b-429eda816692",
"listing_feature_type_id": "0f40888c-3b09-40ed-aef6-0fddc1a155b6",
"listing_feature_text": "Dual Airbags"
},
{
"id": "4255b8b4-e71c-4059-8a22-1b9894512564",
"listing_feature_type_id": "0f40888c-3b09-40ed-aef6-0fddc1a155b6",
"listing_feature_text": "Side Airbags"
}
]
},
{
"listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"name": "Interior",
"features": [
{
"id": "1b89581e-1a30-4dce-9455-ab0ad4c49bcf",
"listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_text": "Privacy Glass"
},
{
"id": "59e3628f-3cef-4447-9cb2-71be4a3046a4",
"listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_text": "Onboard GPS"
},
{
"id": "66fe416b-98dc-45c8-979d-78f2ea7fe876",
"listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_text": "In-dash Navigation"
},
{
"id": "8fe836a3-5596-4306-aac1-bae4cb596e20",
"listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_text": "Power Windows"
},
{
"id": "e4addb5a-1b26-4ae3-b0ee-3b8bce892fb9",
"listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_text": "Tinted Windows"
},
{
"id": "f95b8253-a2b8-4bfc-90c0-0fc656c3f200",
"listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_text": "CD Player"
}
]
},
{
"listing_feature_type_id": "8d16e8ea-3d38-48dc-8e56-00d1cc736f0d",
"name": "Exterior",
"features": [
{
"id": "3aa6dd05-dd3a-4e93-ad06-295687a8dda1",
"listing_feature_type_id": "8d16e8ea-3d38-48dc-8e56-00d1cc736f0d",
"listing_feature_text": "Spoiler"
}
]
}
]
以下是模型(非常基本,剛剛開始):
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ListingFeatureValue extends Model
{
protected $table = 'listings_features_values';
public $timestamps = false;
public $incrementing = false;
public function type() {
return $this->belongsTo('App\Models\ListingFeatureType', 'listing_feature_type_id', 'id');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ListingFeatureType extends Model
{
protected $table = 'listings_features_types';
public $timestamps = false;
public $incrementing = false;
public function values() {
return $this->hasMany('App\Models\ListingFeatureValue', 'listing_feature_type_id', 'id');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ListingFeature extends Model
{
protected $table = 'listings_features';
public $timestamps = false;
public $incrementing = false;
}
如何創建Laravel模型關系以實現相同的結果集,但如上所述調用它? 或者,我如何如上所述調用它但停止發生錯誤?
如果你做到這一點,謝謝!
更新:
我無法按原樣運行,我得到一個SQL錯誤,這讓我覺得我需要一個belongsToManyThrough,所以我可以指定表名:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'ad_l5.listing_listing_feature' doesn't exist (SQL: select `listings_features`.*, `listing_listing_feature`.`listing_id` as `pivot_listing_id`, `listing_listing_feature`.`listing_feature_id` as `pivot_listing_feature_id` from `listings_features` inner join `listing_listing_feature` on `listings_features`.`id` = `listing_listing_feature`.`listing_feature_id` where `listing_listing_feature`.`listing_id` in (b266c874-1cef-4f49-b65f-f91ddaaf6aee, e93674ca-3f82-45d8-9961-e8569cac164b))
但是使用從@Carter Fort下面的答案發布的確切代碼並將features()方法更改為
return $this->belongsToMany(ListingFeatureValue::class, 'listings_features', 'listing_id', 'feature_id');
還添加了ModelFeatureValue模型
public function type()
{
return $this->belongsTo(ListingFeatureType::class, 'listing_feature_type_id', 'id');
}
我得到的輸出:
"featuresByType": { "": [ { "id": "3aa6dd05-dd3a-4e93-ad06-295687a8dda1", "listing_feature_type_id": "8d16e8ea-3d38-48dc-8e56-00d1cc736f0d", "listing_feature_text": "Spoiler", "pivot": { "listing_id": "e93674ca-3f82-45d8-9961-e8569cac164b", "feature_id": "3aa6dd05-dd3a-4e93-ad06-295687a8dda1" }, "type": { "id": "8d16e8ea-3d38-48dc-8e56-00d1cc736f0d", "listing_feature_type": "Exterior" } }, { "id": "f95b8253-a2b8-4bfc-90c0-0fc656c3f200", "listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd", "listing_feature_text": "CD Player", "pivot": { "listing_id": "e93674ca-3f82-45d8-9961-e8569cac164b", "feature_id": "f95b8253-a2b8-4bfc-90c0-0fc656c3f200" }, "type": { "id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd", "listing_feature_type": "Interior" } }, { "id": "66fe416b-98dc-45c8-979d-78f2ea7fe876", "listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd", "listing_feature_text": "In-dash Navigation", "pivot": { "listing_id": "e93674ca-3f82-45d8-9961-e8569cac164b", "feature_id": "66fe416b-98dc-45c8-979d-78f2ea7fe876" }, "type": { "id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd", "listing_feature_type": "Interior" } }, { "id": "0ed0ad63-a6ed-4818-8c6f-ee048694dcd9", "listing_feature_type_id": "0f40888c-3b09-40ed-aef6-0fddc1a155b6", "listing_feature_text": "Anti-Lock Brakes", "pivot": { "listing_id": "e93674ca-3f82-45d8-9961-e8569cac164b", "feature_id": "0ed0ad63-a6ed-4818-8c6f-ee048694dcd9" }, "type": { "id": "0f40888c-3b09-40ed-aef6-0fddc1a155b6", "listing_feature_type": "Safety" } }, ...
這比我更好,但是如果結果按類型分組然后在其中的特征而不是每個附加類型的特征,那將是很好的。 使解析顯示更難。 感謝您的幫助!
更新2
這些將是我的架構文件:
// listings
Schema::create('listings', function (Blueprint $table) {
$table->string('id');
$table->string('title');
});
// listings to features pivot
Schema::create('listings_features', function (Blueprint $table) {
$table->string('listing_id');
$table->string('feature_id');
});
// feature types (i.e. Safety)
Schema::create('listings_features_types', function(Blueprint $table){
$table->string('id');
$table->string('listing_feature_type');
});
// feature values (i.e. Anti-Lock Brakes)
Schema::create('listings_features_values', function(Blueprint $table){
$table->string('id');
$table->string('listing_feature_type_id'); // links to listings_features_types
$table->string('listing_feature_text');
});
更新3從下面的答案進行更改(我將在工作后發布所有代碼)我接近我想要的。
"features": [
{
"id": "3aa6dd05-dd3a-4e93-ad06-295687a8dda1",
"listing_feature_type_id": "8d16e8ea-3d38-48dc-8e56-00d1cc736f0d",
"listing_feature_text": "Spoiler",
"pivot": {
"listing_id": "e93674ca-3f82-45d8-9961-e8569cac164b",
"feature_id": "3aa6dd05-dd3a-4e93-ad06-295687a8dda1"
},
"type": {
"id": "8d16e8ea-3d38-48dc-8e56-00d1cc736f0d",
"listing_feature_type": "Exterior"
}
},
{
"id": "f95b8253-a2b8-4bfc-90c0-0fc656c3f200",
"listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_text": "CD Player",
"pivot": {
"listing_id": "e93674ca-3f82-45d8-9961-e8569cac164b",
"feature_id": "f95b8253-a2b8-4bfc-90c0-0fc656c3f200"
},
"type": {
"id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_type": "Interior"
}
},
{
"id": "66fe416b-98dc-45c8-979d-78f2ea7fe876",
"listing_feature_type_id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_text": "In-dash Navigation",
"pivot": {
"listing_id": "e93674ca-3f82-45d8-9961-e8569cac164b",
"feature_id": "66fe416b-98dc-45c8-979d-78f2ea7fe876"
},
"type": {
"id": "84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_type": "Interior"
}
// ....]
我想要的是:
{
"feature_types":[
{
"type":{
"id":"8d16e8ea-3d38-48dc-8e56-00d1cc736f0d",
"listing_feature_type":"Interior",
"features":[
{
"id":"3aa6dd05-dd3a-4e93-ad06-295687a8dda1",
"listing_feature_type_id":"8d16e8ea-3d38-48dc-8e56-00d1cc736f0d",
"listing_feature_text":"GPS"
},
{
"id":"66fe416b-98dc-45c8-979d-78f2ea7fe876",
"listing_feature_type_id":"84dcce5c-34b9-4c8b-9066-5b20a42cf4cd",
"listing_feature_text":"In-dash Navigation"
},
] "pivot":{
"listing_id":"e93674ca-3f82-45d8-9961-e8569cac164b",
"feature_id":"f95b8253-a2b8-4bfc-90c0-0fc656c3f200"
}
}
}
]
}
您可以使用Listing
和ListingFeatureValue
模型之間的多對多關系,然后使用groupBy
Collection方法按類型對給定列表的相關列表功能進行groupBy
。
上市模型:
class Listing extends Model {
protected $hidden = [
'features'
];
protected $appends = [
'feature_types'
];
public function features(){
return $this->belongsToMany(ListingFeatureValue::class, 'listings_features', 'listing_id', 'feature_id');
}
public function getFeatureTypesAttribute()
{
return $this->features->groupBy(function ($feature, $key) {
return $feature->type->id;
})->map(function($features, $key){
$type = ListingFeatureType::find($key);
$type->features = $features;
return $type;
})->values();
}
}
getFeatureTypesAttribute()
是此處show的明星,因為您可以將它與appends
數組組合以強制Eloquent模型將其附加到對模型實例的任何toArray()
調用,這是toJson()
在轉換時使用的模型到JSON。
首先獲取所有列表值然后使用groupBy
和map
集合方法划分它們似乎有點費解,但是沒有通過多對多關系使用hasManyThrough
本機hasManyThrough
機制。 如果您不喜歡這個,那么這里有一個不同的方法 。
ListingFeatureValue模型:
class ListingFeatureValue extends Model
{
public $table = 'listings_features_values';
public function type()
{
return $this->belongsTo(ListingFeatureType::class, 'feature_type_id');
}
}
我在這里展示這個模型是因為在上面的getFeaturesByTypeAttribute()
方法中調用了type()
關系,並且不希望出現任何混淆。
而且,為了完整起見, ListFeatureType模型:
class ListingFeatureType extends Model
{
public $table = "listings_features_types";
public function listings()
{
return $this->hasMany(ListingFeatureValue::class, 'listing_feature_type_id');
}
}
如果您希望按照其功能和類型急切加載列表以獲得所有商家信息的完整輸出,則可以這樣執行:
App\Listing::with('features.type')->get()->toJson();
我的遷移文件如下所示:
//create_listings_table
Schema::create('listings', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid');
$table->timestamps();
});
//create_listings_features_values_table
Schema::create('listings_features_values', function (Blueprint $table) {
$table->increments('id');
$table->string('listing_feature_text');
$table->integer('listing_feature_type_id')->unsigned();
$table->timestamps();
});
//create_listings_features_types_table
Schema::create('listings_features_types', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
//create_listings_features_table
Schema::create('listings_features', function(Blueprint $table){
$table->integer('listing_id')->unsigned();
$table->integer('listing_feature_id')->unsigned();
});
您可以在此處了解有關Collection方法的更多信息:
https://laravel.com/docs/5.3/collections#available-methods
......並且熱切地加載到這里:
https://laravel.com/docs/5.3/eloquent-relationships#eager-loading
......以及這里的多對多關系:
https://laravel.com/docs/5.3/eloquent-relationships#many-to-many
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.