I'm available to work on new projects starting August 2018! Get in touch!

Back to post list

Laravel 5.2: Morph Map

15-01-2016

A new undocumented feature in laravel 5.2 was introduced: The Morph Map for morphTo relations.

We all know the polymorphic relations, they are a type of relation to link multiple models with one common model. For instance if you have a User and a Blog Post model, both of these can have a "Picture" relationship.

From the documentation:

Polymorphic relations allow a model to belong to more than one other model on a single association. For example, imagine users of your application can "like" both posts and comments. Using polymorphic relationships, you can use a single likes table for both of these scenarios.

Let's use the example from the documentation:

posts
    id - integer
    name - string

videos
    id - integer
    name - string

tags
    id - integer
    name - string

taggables
    tag_id - integer
    taggable_id - integer
    taggable_type - string

You can see here, both videos and posts can have tags associated with them. In laravel 5.1 the contents of taggables table looked something like this:

| tag_id        | taggable_id           | taggable_type  |
| ------------- |-----------------------| ---------------------|
| 1             | 1                     | App\Models\Post |
| 2             | 1                     | App\Models\Post |
| 1             | 1                     | App\Models\Video |

This is very nice and was extremely usefull in certain situations.

However there is one big flaw with this. What if... the namespace of the Post model changes ?

Yep indeed, you will have to make some sort of migration to rename all occurences in the taggables table. Not very nice is it ?

In laravel 5.2, morphMap came to the resque of this "issue".

You can with this feature define a map of classes that will be used in the morphTo type relations. In our example this can be:

Relation::morphMap([
    'post' => \App\Models\Post::class,
    'video' => \App\Models\Video::class,
]);

Now when you save a new morphTo relationship, instead of having the full namespace in the taggable_type column, you will have the key name of the map.

| tag_id        | taggable_id           | taggable_type  |
| ------------- |-----------------------| ---------------------|
| 1             | 1                     | post |
| 2             | 1                     | post |
| 1             | 1                     | video |

You can now safely and easily refactor the namespace of the Post model, without having to change the data in the database table.

Further details can be found in the laravel test suite. This is a good example of why many say the tests are documentation!

Edit: It seems to be already available in laravel 5.1, added since pull request 10141

I'm available to work on new projects starting August 2018! Get in touch!

Deploy your projects with zero downtime Laravel: Validate login and register forms on the same view