Ralph J. Smit Laravel Software Engineer
Laravel Eloquent offers a great way to support polymorphic relationships in your Laravel-application. Laravel does this by providing good support for relations.
As a small recap, polymorphic relationships in Laravel work based on two columns in your database: a column called
XXX_id. The column
XXX_type refers to the other model that this row refers to. For example, that could be something like
XXX_id column is the
id of the other model. By combining this information, Laravel knows which model it should use.
However, you might see the problem arise here: we know have information about our internal app structure inside our database. What would happen when you move the
App/Models/Post class to a new location? You guessed it: the relationships would stop working.
In order to decouple your database from your internal application structure, Laravel offers so-called morph maps. Morph maps basically allow you to register an alias, so that you e.g. had something like
video in the database, instead of
The Laravel documentation gives the following example of morph maps.
use Illuminate\Database\Eloquent\Relations\Relation;Relation::enforceMorphMap(['post' => App\Models\Post::class,'video' => App\Models\Video::class,]);
However, have you noticed that the name of the function contains
enforce. Why would that be?
If you are relatively new to the Laravel-ecosystem, you might not know that Laravel still offers an alternative method, called
Relation::morphMap(). In the past, this was the de facto way to register morph maps. Unfortunately, currently the Laravel-documentation doesn't mention this method anymore, though it still exists.
What is the reason? The reason is that Laravel added a new feature that would disallow relations where there isn't a morph map registered.
Simply put, that basically means that Laravel will throw an exception every time you try to use a polymorphic relationship without a new, specific key.
This feature is enabled by using the
Relation::enforceMorphMap() instead of
Relation::morphMap(). Laravel recommends to use this protection by default, so it doesn't write about the regular
Relation::morphMany() method in the docs.
How to fix the "No morph map defined for model" error in Laravel
Now that you all know this, you can solve the error in two ways:
- Add a new key to your
Relation::enforceMorphMap()with the model that is causing the error.
- Replace the call to
Relation::morphMap(). This will not require the morph maps anymore for your models.
The new code for solution #2 looks like this:
Relation::morphMap(['post' => App\Models\Post::class,'video' => App\Models\Video::class,]);
The perfect situation for using this solution is when you want to use morph maps in a Laravel package. In such a situation, you certainly shouldn't force the complete application to use morph maps.
That was also my problem (I sell a premium Laravel-plugin for Filament PHP), because it forced the users to always add a morph map.
There is of course a reason that the Laravel docs do not mention the basic
Relation::morphMap(), so the summary is:
Relation::enforceMorphMap()if you're using morph maps in your Laravel-application.
Relation::morphMap()if you're using morph maps in a Laravel-package.