Laravel有很多很多到一个雄辩 [英] Laravel hasMany Many to Many To One Eloquent

查看:116
本文介绍了Laravel有很多很多到一个雄辩的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我没有太多的运气把这个Laravel的方式。所以我提出两个问题。



鉴于我有一辆汽车,那辆汽车可以有很多功能,但是功能也由功能类型分隔,我如何返回所有功能,分离功能类型,为所述的汽车?



我有四个表,其中listing_features是枢纽表:




  • 列表(id)

  • listing_features(listing_id,feature_id)

  • listing_features_types(id,type) li>
  • listing_features_values(id,listing_feature_type_id,value)



我有以下代码,需要,但是当我使用它,我得到一个Laravel错误...调用一个成员函数addEagerConstraints()在字符串...因为我这样调用:

 列表:: 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()) - >其中('listing_feature_type_id','=',$ obj- > ID) - >得到() - >指定者();
}
return json_encode($ out);
}

哪些返回:

  [
{
listing_feature_type_id:0f40888c-3b09-40ed-aef6-0fddc1a155b6,
name:安全,
features:[
{
id:0ed0ad63-a6ed-4818-8c6f-ee048694dcd9,
listing_feature_type_id:0f40888c-3b09-40ed-aef6- 0fddc1a155b6,
listing_feature_text:防抱死制动器
},
{
id:37abeef2-dc22-4995-8503-f89962242ea6,
listing_feature_type_id:0f40888c-3b09-40ed-aef6-0fddc1a155b6,
listing_feature_text:碰撞检测
},
{
id 3c0728e1-91f7-4f44-ac0b-429eda816692,
listing_feature_type_id:0f40888c-3b09-40ed-aef6-0fddc1a155b6,
listing_feature_text:双安全气囊
},
{
id:4255b8b4-e71c-4059-8a22-1b9894512564,
listing_feature_type_id:0f 40888c-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:隐私玻璃
},
{
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:有色Windows
},
{
id:f95b8253-a2b8-4bfc-90c0-0fc656c3f200,
listing_feature_type_id:84dcce5c-34b9-4c8b-9066-5b20a42cf4cd,
listing_feature_text CD播放器
}
]
},
{
listing_feature_type_id:8d16e8ea-3d38-48dc-8e56-00d1cc736f0d,
名称:外观,
功能:[
{
id:3aa6dd05-dd3a-4e93-ad06-295687a8dda1,
listing_feature_type_id 8d16e8ea-3d38-48dc-8e56-00d1cc736f0d,
listing_feature_text:Spoiler
}
]
}
]

这是模型(非常基本,刚开始):

  php 

命名空间App \Models;

使用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 

命名空间App \Models;

使用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 

命名空间App \Models;

使用Illuminate\Database\Eloquent\Model;

class ListingFeature extends Model
{

protected $ table ='listings_features';
public $ timestamps = false;
public $ incrementing = false;

}

如何创建Laravel模型关系以实现相同结果集,但是如上所述调用它?或者,我如何可以像上面那样调用它,但是停止发生错误?



如果你这么做,谢谢!



更新:



我无法使其正常工作,我有一个SQL错误,让我感觉到像我需要一个belongsToManyThrough,所以我可以指定表名称:

  SQLSTATE [42S02]:未找到基表或视图:1146表'ad_l5.listing_listing_feature'不存在(SQL:select`listing_features`。*,`listing_listing_feature`.`listing_id`为`pivot_listing_id`,`listing_listing_feature`.`listing_feature_id`为`pivot_listing_feature_id``````````````````内部连接` (b266c874-1cef-4f49-b65f-f91ddaaf6aee,e93674ca-3f82-45d8-9961-e8569cac164b)中的'listing_listing_feature```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` b $ b  

但使用确切的代码发布为下面的答案从@Carter Fort并将features()方法更改为

  return $ this-> belongsToMany (ListingFeatureValue :: class,'listing_features','listing_id','feature_id'); 

还添加到模型列表功能值

  public function type()
{
return $ this-> belongsTo(ListingFeatureType :: class,'listing_feature_type_id','id' );
}

我得到的输出:



 featuresByType:{:[{id:3aa6dd05-dd3a-4e93-ad06-295687a8dda1 ,list_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室内}} ,{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 :防抱死制动器,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:安全}},...  

div>



这比我更好,但是如果结果按类型分组,然后在其中的功能,而不是每个功能都有类型连接。使其难以解析显示。感谢您的帮助!



更新2



这些将是我的模式文件:

  // Listing 
Schema :: create('listing'函数(Blueprint $ table){
$ table-> string('id');
$ table-> string('title');
});

//列出功能pivot
模式:: create('listing_features',功能(Blueprint $ table){
$ table-> string('listing_id');
$ table-> string('feature_id');
});

//功能类型(即安全性)
模式:: create('listings_features_types',功能(Blueprint $ table){
$ table-> string('id' );
$ table-> string('listing_feature_type');
});

//功能值(即防抱死制动)
Schema :: create('listings_features_values',function(Blueprint $ table){
$ table-> string 'id');
$ table-> string('listing_feature_type_id'); //链接到listing_features_types
$ table-> string('listing_feature_text');
});

更新3
从下面的答案中进行更改我会发布所有代码一次工作)我接近我想要的。

 功能
{
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 :外部
}
},
{
id:f95b8253-a2b8-4bfc-90c0-0fc656c3f200,
listing_feature_type_id:84dcce5c -34b9-4c8b-9066-5b20a42cf4cd,
listing_feature_text:CD播放器,
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 :内部
}

// ....
]



我想要的是:

  {
feature_types:[
{
type:{
id:8d16e8ea-3d38-48dc-8e56-00d1cc736f0d,
listing_feature_type:Interior,
features:[
{
id:3aa6dd05-dd3a-4e93-ad06-295 687a8dda1,
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
}
}
}
]
}


解决方案

您可以使用列表之间的多对多关系 ListingFeatureValue 模型,然后使用 groupBy Co将其给定列表的相关列表功能按类型分组



列表模型:

  class Listing Model {

protected $ hidden = [
'features'
];

protected $ appends = [
'feature_types'
];

public function features(){
return $ this-> belongsToMany(ListingFeatureValue :: class,'listing_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()是这里的节目的明星,因为您可以将其与追加数组组合,以强制Eloquent模型将其附加到任何 toArray()调用模型实例,这是将模型转换为JSON时使用的 toJson() / p>

似乎有点复杂,首先获取所有列表值,然后使用 groupBy map 收集方法,但是没有本机的强大的机制,通过多对多关系使用 hasManyThrough 。如果您不喜欢这里,请不同的方法一个。



ListingFeatureValue 模型:

  class ListingFeatureValue extends Model 
{
public $ table ='listings_features_values';

public function type()
{
return $ this-> belongsTo(ListingFeatureType :: class,'feature_type_id');
}
}

我在这里显示这个模型,因为 type()关系在上面的 getFeaturesByTypeAttribute()方法中调用,不希望有任何混淆。 p>

而且,为了完整起见, ListingFeatureType 模型:

  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') - >得到() - >的toJSON(); 

我的迁移文件如下所示:

  // create_listings_table 
Schema :: create('listing',function(Blueprint $ table){
$ table-> incremental('id');
$ table-> string('uuid');
$ table-> timestamps();
});

// create_listings_features_values_table
模式:: create('listing_features_values',功能(Blueprint $ table){
$ table-> increment('id');
$ table-> string('listing_feature_text');
$ table->整数('listing_feature_type_id') - > unsigned();
$ table-> timestamps();
});

// create_listings_features_types_table
模式:: create('listings_features_types',功能(Blueprint $ table){
$ table-> increment('id');
$ table-> string('name');
$ table-> timestamps();
});

// create_listings_features_table
Schema :: create('listing_features',function(Blueprint $ table){
$ table-> integer('listing_id') - > unsigned ();
$ table-> integer('listing_feature_id') - > unsigned();
});

您可以在这里了解有关收集方法的更多信息:



https://laravel.com/docs/5.3/collections#available-方法



...并在此加载:



https://laravel.com/docs/5.3/eloquent-relationships#eager-loading



...和多对多关系在这里:



https://laravel.com/docs/5.3/eloquent-relationships#many-to-many


I haven't had much luck sorting this out the Laravel way. So I pose two questions.

Given that I have a Car and that Car can have many Features, but that Features are also separated by Feature Type, how can I return all Features, separated the Feature Type, for said Car?

I have four tables, with listings_features being the pivot table:

  • listings (id)
  • listings_features (listing_id, feature_id)
  • listings_features_types (id, type)
  • listings_features_values (id, listing_feature_type_id, value)

I have the following code, which produces what I need, but when I use it, I get a Laravel error ... "Call to a member function addEagerConstraints() on string" ... because I invoke it as such:

Listing::with(
        'features',
    )->get();

The code I am using to produce the data in the format I desire (not steadfast on) is

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

Which returns:

[
  {
    "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"
      }
    ]
  }
]

Here are the models (very basic, just starting out):

<?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;

}

How can I create the Laravel model relationships to achieve the same result set but calling it as mentioned above? Alternatively, how can I call it as above but stop the error from occurring?

If you made it this far, thanks!

Update:

I wasn't able to get it working as is, I got a SQL error which makes me feel like I need a belongsToManyThrough so I can specify the table names:

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

But using the exact code posted as the answer below from @Carter Fort and changing the features() method to

return $this->belongsToMany(ListingFeatureValue::class, 'listings_features', 'listing_id', 'feature_id');

Also adding to the model ListingFeatureValue

public function type()
    {
        return $this->belongsTo(ListingFeatureType::class, 'listing_feature_type_id', 'id');
    }

I get the output of:

"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"
}
},
  ...

That is better than I was at, but it would be nice if the results were grouped by type then features within then instead of it being each feature with a type attached. Makes it harder to parse for display. Thanks for the help thus far!

Update 2

These would be my schema files:

// 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');
});

Update 3 Making the changes from the answer below (I will post all code once working) I get close to what I would like.

"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"
}

// .... ]

What I would like is:

{
   "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"
            }
         }
      }
   ]
}

解决方案

You could use a Many-to-Many relationship between the Listing and the ListingFeatureValue models, then group the related listing features for a given listing by their type using the groupBy Collection method.

The Listing model:

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

}

The getFeatureTypesAttribute() is the star of the show here, because you can combine that with the appends array to force the Eloquent model to append that to any toArray() calls to the model instance, which is what toJson() uses when converting your model to JSON.

It may seem a little convoluted to first fetch all the listing values then divide them using the groupBy and map collection methods, but there is no native Eloquent mechanism for using hasManyThrough via many-to-many relationships. There's a different approach here if you don't like this one.

The ListingFeatureValue model:

class ListingFeatureValue extends Model
{
    public $table = 'listings_features_values';

    public function type()
    {
        return $this->belongsTo(ListingFeatureType::class, 'feature_type_id');
    }
}

I'm showing this model here because the type() relationship is called in the getFeaturesByTypeAttribute() method above and didn't want there to be any confusion.

And, just for the sake of completeness, the ListingFeatureType model:

class ListingFeatureType extends Model
{
    public $table = "listings_features_types";

    public function listings()
    {
        return $this->hasMany(ListingFeatureValue::class, 'listing_feature_type_id');
    }
}

If you wanted to eager-load the listings with their features and types for a full output of all your listings, you could do so like this:

App\Listing::with('features.type')->get()->toJson();

My migration files look like this:

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

You can learn more about the Collection methods here:

https://laravel.com/docs/5.3/collections#available-methods

...and eager-loading here:

https://laravel.com/docs/5.3/eloquent-relationships#eager-loading

...and many-to-many relationships here:

https://laravel.com/docs/5.3/eloquent-relationships#many-to-many

这篇关于Laravel有很多很多到一个雄辩的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆