2016-12-14 4 views
14

Ich hatte nicht viel Glück, dies aus der Laravel Weg zu sortieren. Ich stelle also zwei Fragen.Laravel hat viele viele zu viele zu einem eloquenten

Angesichts, dass ich ein Auto habe und dass Auto viele Features haben kann, aber dass Features auch nach Feature-Typ getrennt sind, wie kann ich alle Features, getrennt den Feature-Typ, für besagtes Auto zurückgeben?

Ich habe vier Tabellen, mit listings_features die Pivot-Tabelle ist:

  • Listings (id)
  • listings_features (listing_id, feature_id)
  • listings_features_types (id, Typ)
  • listings_features_values ​​(id , listing_feature_type_id, Wert)

Ich habe den folgenden Code, der wha produziert t ich brauche, aber wenn ich es verwende, erhalte ich einen Laravel Fehler ... "Call auf eine Elementfunktion addEagerConstraints() auf Zeichenfolge" ... weil ich es als solche berufen:

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

Der Code I verwende die Daten in dem Format zu erzeugen, ist ich wünsche (nicht standhaft auf)

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

Welche zurück:

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

Hier sind die Modelle (sehr einfach, gerade erst anfangen):

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

} 

Wie kann ich die Laravel Modellbeziehungen schaffen das gleiche Ergebnis erreichen zu können, sondern darüber, wie erwähnt nennen? Alternativ, wie kann ich es wie oben genannt nennen, aber den Fehler verhindern?

Wenn Sie es so weit geschafft haben, danke!

Update:

ich nicht in der Lage war es wie es ist, zum Laufen zu bringen habe ich einen SQL-Fehler, die mir das Gefühl, wie ich ein belongsToManyThrough brauchen machen, so kann ich die Tabellennamen angeben:

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

Aber den genauen Code als Antwort geschrieben unter Verwendung der unten von @Carter Fort und das Ändern der Funktionen() -Methode

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

auch hinzufügen ing zum Modell ListingFeatureValue

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

bekomme ich die Ausgabe von:

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

, die besser ist als ich, war aber es wäre, wenn die Ergebnisse schön von gruppierten Geben Sie dann Features innerhalb von dann statt jedes Feature mit einem Typ an. Macht es schwieriger zu analysieren für die Anzeige. Danke für die Hilfe bis jetzt!

Update 2

Diese meine Schema-Dateien wäre:

// 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 Vornehmen der Änderungen aus der Antwort unten (Ich werde den gesamten Code schreiben einmal arbeiten) bekomme ich schließen zu dem, was ich möchte.

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

// .... ]

Was würde Ich mag ist:

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

sorgen, um Sie zu posten r model (* listing_features * tables) deine 'public function features()' fühlt sich nicht richtig an .. –

+0

Hinzugefügt, danke !! – Spechal

+0

Auch, bevor Sie fragen, mache ich eine API zu einer bestehenden Anwendung, weshalb die Tabellennamen und andere Sachen definiert sind. :) – Spechal

Antwort

8

Sie Beziehung eine Many-to-Many nutzen könnten zwischen dem Listing und den ListingFeatureValue Modelle, Dann gruppieren Sie die zugehörigen Auflistungsfunktionen für eine bestimmte Auflistung nach ihrem Typ, indem Sie die Sammlungsmethode groupBy verwenden.

Das Listing Modell:

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

} 

Die getFeatureTypesAttribute() ist der Star der Show hier, weil Sie, dass mit dem appends Array kombinieren können die Eloquent Modell zu etwas zwingen, die zu irgendwelchen toArray() Anrufe anhängen Modellinstanz, die bei der Konvertierung Ihres Modells in JSON toJson() verwendet.

Es kann ein wenig verworren scheinen zunächst dann alle Auflistung Werte holen teilen sie die groupBy und map Erhebungsmethoden verwenden, aber es gibt keine native für Eloquent Mechanismus hasManyThrough über viele-zu-viele-Beziehungen verwenden. Es gibt eine different approach here, wenn Sie diese nicht mögen.

Das ListingFeatureValue Modell:

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

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

Ich zeige dieses hier Modell, weil die type() Beziehung oben in der getFeaturesByTypeAttribute() Methode aufgerufen wird, und wollte nicht, dass es eine Verwechslung sein.

Und nur der Vollständigkeit halber, die ListingFeatureType Modell:

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

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

Wenn Sie die Objekte mit ihren Eigenschaften und Typen für eine vollständige Ausgabe aller Ihrer Angebote, die Sie eifrig laden wollte Dazu könnte wie folgt:

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

Meine Migrationsdateien wie folgt aussehen:

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

Sie können hier mehr über die Sammlung Methoden lernen:

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

... und eifrig-Laden hier:

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

... und viele-zu-viele-Beziehungen hier:

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

+0

Allerdings konnte ich eine funktionierende Version bekommen, aber die Ausgabe ist seltsam. Ich werde den ursprünglichen Beitrag aktualisieren. Ich habe auch das Gefühl, dass ich ein goesTomanyThrough basierend auf dem generierten SQL brauche. – Spechal

+0

Ich habe meine Antwort aktualisiert, um den Migrationscode für die Pivot-Tabelle zu enthalten, die Sie benötigen. Sie müssen auch Ihre Listings mit ihren Listing-Funktionen verknüpfen/synchronisieren: '$ listing-> features() -> sync ($ arrayOfListingFeatureIDs)' –

+0

Sie können hier mehr über die Verwaltung von Viele-zu-Viele-Beziehungen lesen: https://laravel.com/docs/5.3/eloquent-relationships#updating-many-to-many-relationships –