How to get a collection of multiple ralationships using Eloquent?

  laravel

I have a table that contains foreign keys of product properties and their values.

product_id feature_id value_id
1 1 2
1 1 3
1 2 4

How to get a collection of that values using Eloquent?

Something like this

product => [
    id => 1,
    ...
    features => Collection: [
        Feature: [
            id => 1,
            name => Size,
            values => [
                Value: [
                    id => 2,
                    name => M
                ],
                Value: [
                    id: 3,
                    name: L
                ]
            ]
        ],
        Feature: [
            id => 2,
            name => Color,
            values => [
                Value: [
                    id => 4,
                    name => Red
                ]
            ]
        ]
    ]
]

This is my solution.

class Product extends Model
{
    protected $appends = ['features'];
    protected array $features;
    protected bool $featuresAppend = false;

    public function getFeaturesAttribute(): Collection
    {
        if ($this->featuresAppend === false) {
            $this->appendFeatures();
        }
        return collect($this->features);
    }

    public function productFeatures(): BelongsToMany
    {
        return $this->belongsToMany(Feature::class, 'product_features');
    }

    public function productFeatureValues(): BelongsToMany
    {
        return $this->belongsToMany(
            FeatureValue::class,
            'product_features',
            'product_id',
            'value_id'
        );
    }

    protected function appendFeatures(): void
    {
        // Get futures and values by relationships
        $features = $this->productFeatures()->get()->keyBy('id');
        $values = $this->productFeatureValues()->get()->keyBy('id');

        // Create features-values structure
        $features->each(
            function ($f) {
                $this->features[$f->id] = new StdClass();
                $this->features[$f->id]->feature = $f;
            }
        );

        // Appends values to future
        $values->each(
            function ($v) {
                if (array_key_exists($v->feature_id, $this->features)) {
                    $this->features[$v->feature_id]->values[$v->id] = $v;
                }
            }
        );

        $this->featuresAppend = true;
    }
}

I’m looking for a better solution to this problem or a solution using native Laravel features.

Source: Laravel

Leave a Reply