laravelpolymorphic-associations

How can I tell if a model is morph in laravel


Is there a simple way to determine if a model is part of a polymorphic relationship?

My use case

I have to merge models as well as all of their related models. The process is somewhat different for a polymorphic relationship than it is for a traditional one-to-many or many-to-many relationship.

What I've tried

Let's suppose I have two models. Banner is polymorphic but Appointment is not.

class Banner extends Model
{
  public function bannerable(): MorphTo
  {
    return $this->morphTo();
  }
}

class Appointment extends Model
{
  public function provider(): BelongsTo
  {
    return $this->belongsTo(User::class);
  }
}

I tried looking at the morphType and also looking to see if the method exists on the class, but no luck.

> (new Banner)->morphTo()->getMorphType()
= "eval_type"

> (new Appointment)->morphTo()->getMorphType()
= "eval_type"

> method_exists(Banner::class, 'morphTo')
= true

> method_exists(Appointment::class, 'morphTo')
= true

Solution

  • You could use Reflection on the model classes, and then check if they have any method that returns a polymorphic relation type (MorphTo, MorphOne , MorphMany, etc).

    This is what it looks like.

    use App\Models\Appointment;
    use App\Models\Banner;
    use Illuminate\Database\Eloquent\Relations\MorphTo;
    use ReflectionClass;
    use ReflectionMethod;
    
    $is_appointment_model_polymorphic =  collect((new ReflectionClass(Appointment::class))->getMethods())
        ->where('class', Appointment::class) // discard methods that are declared in the parent class, such as morphTo()
        ->filter(function (ReflectionMethod $rm): bool {
            $returnType = $rm->getReturnType()->getName();
    
            return $returnThype === MorphTo::class
            // or return in_array($returnType, [MorphTo::class, ... ]
        })
        ->isNotEmpty();