Search code examples
phplaraveleloquent

Laravel morph map not working with extended models


I'm using Laravel's polymorphic relationships with a morph map to relate different models to a single table. However, I'm encountering an issue where only the first model in the morph map works, while the rest are ignored.

Here's how I've set up my morph map:

  public function model()
    {
 
        return $this->morphTo();
    }

Relation::morphMap([
    'coupon' => Product::class,
    'offer' => Product::class,
]);

 public function scopefilter($query)
    {
        return $query->where(function ($query) {
            // Include sliders with active morph relationships
            $query->whereHasMorph('model','*', function ($query, $type) {
                if (in_array($type,[ Blog::class, Coupon::class, Offer::class])) {
                    $query->active();
                }
            })->orWhereNull('model_type');  // Or include sliders without any morph
        });
    }

The extended models Coupon, Offer, and all inherit from the Product model.

The issue I'm facing is that when I try to retrieve a slider's associated model using $slider->model, it only returns the instance if it's a Product, but not if it's a Coupon, Offer, . However, when I change the morph map order, only the first one in the map works, and others are ignored.

I've verified that the database schema is correct, and all models are properly autoloaded. What could be causing this issue, and how can I resolve it?


Solution

  • If you have subclasses for Coupon and Offer then use them in the morph map. Having them both point the Product class will make Laravel instantiate a Product object.

    Change

    Relation::morphMap([
        'coupon' => Product::class,
        'offer' => Product::class,
    ]);
    

    to

    Relation::morphMap([
        'coupon' => Coupon::class,
        'offer' => Offer::class,
    ]);
    

    From a quick search I found this old but helpful post which says you need to override the getMorphClass function in your classes inheriting from Product. For example:

    class Coupon extends Product
    {
        public function getMorphClass()
        {
            return 'coupon';
        }
    }