Laravel hasMany Many to Many To One Eloquent

后端 未结 1 1142
没有蜡笔的小新
没有蜡笔的小新 2021-02-07 12:37

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 al

1条回答
  •  借酒劲吻你
    2021-02-07 12:42

    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

    0 讨论(0)
提交回复
热议问题