Get "PHP 8 in a Nuthshell" (Now with PHP 8.4)
Amit Merchant

Amit Merchant

A blog on PHP, JavaScript, and more

Aliasing polymorphic types in Laravel's Eloquent

When working with polymorphic relationships in Laravel’s Eloquent, it’s important to specify the “type” of the related model. You can do this by using morphOne, morphMany, and morphToMany methods.

Let’s say we have Book and Author models which shares a polymorphic relationship with Rating model. And the table structure of all these would look like following.

books
    id - integer
    name - string

authors
    id - integer
    name - string

ratings
    id - integer
    url - string
    ratingable_id - integer
    ratingable_type - string

Here, as you might know, the ratingable_type column of the ratings table detrmines which “type” of parent model to return when accessing the ratingable relation.

So, for instance, if you want to specify this into the Book model, you can do it using morphOne method like so.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Rating extends Model
{
    /**
     * Get the parent ratingable model (book or author).
     */
    public function ratingable()
    {
        return $this->morphTo();
    }
}

class Book extends Model
{
    /**
     * Get the book's rating.
     */
    public function rating()
    {
        return $this->morphOne(Rating::class, 'ratingable');
    }
}

Now, as you can see, we specified the “type” in the morphOne as the fully qualified class name (FQCN) of the model. But, we can do this the better way using something called “map morphing”.

Aliasing Polymorphich Types

There’s this another way in which you can “map” these FQCNs to strings using Illuminate\Database\Eloquent\Relations\Relation’s morphMap method. You can register this in the boot method of your App\Providers\AppServiceProvider class.

So, if you want to map/alias the App\Models\Rating to rating string, you can do it like so.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Relations\Relation;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Relation::morphMap([
            'rating' => 'App\Models\Rating',
        ]);
    }
}

And now you can specify rating as the polymorphic type instead of giving the FQCN like so.

class Book extends Model
{
    /**
     * Get the book's rating.
     */
    public function rating()
    {
        return $this->morphOne('rating', 'ratingable');
    }
}

Benefits of using aliasing types

The main benefit of aliasing polymorphic type is…

  • You get a central place where you can manage your polymorphic types.
  • As you are aliasing models as strings from a central place, it’s now safe for you to rename the models. By doing so, you don’t have to go over places just to rename the classes.

Caution when using “map morph”

It’s important to note here that, when you start using “map morph” in your existing application, every morphable *_type (ratingable_type in our example) column value in your database that still contains a fully-qualified class will need to be converted to its “map” name.

Learn the fundamentals of PHP 8 (including 8.1, 8.2, and 8.3), the latest version of PHP, and how to use it today with my new book PHP 8 in a Nutshell. It's a no-fluff and easy-to-digest guide to the latest features and nitty-gritty details of PHP 8. So, if you're looking for a quick and easy way to PHP 8, this is the book for you.

Like this article?

Buy me a coffee

👋 Hi there! I'm Amit. I write articles about all things web development. You can become a sponsor on my blog to help me continue my writing journey and get your brand in front of thousands of eyes.

Comments?