Introduction to Laravel Polymorphic Relationship
When building applications, we often encounter situation where the same type of relationship needs to be attached with multiple models. For example, you might want to allow users to add comments not just to posts, but also to images and videos. Instead of creating a separate table like post_comments, image_comments, video_comments or managing multiple belongsTo relation, Laravel provides polymorphic relationship. This feature allows you to handle such scenarios in a clean, efficient, and scalable way.
In this article, we’ll explore how to set up a polymorphic relationship in Laravel using Category, Post, and a shared Seo model.
What is a Polymorphic Relationship in Laravel?
A polymorphic relation allows a model to belong to more than one type of model using a single association. For example:
- A SEO model can belong to a Category
- A same SEO model can belong to Post
This relation can be:
- One to one polymorphic
- One to Many polymorphic
- One of Many polymorphic
- Many of Many Polymorphic
Read more about Polymorphic relationship.
Database Schema
Lets suppose we have a migration of Post & Category as:
categories
id - integer (primary key)
name - string
created_at - timestamp
updated_at - timestamp
posts
id - integer (primary key)
title - string
content - text
created_at - timestamp
updated_at - timestamp
seos
id - integer (primary key)
meta_title - string
meta_description- string
meta_keywords - json
seoable_id - integer (ID of related model: post/category)
seoable_type - string(Class name: Post or Category)
created_at - timestamp
updated_at - timestamp
The seoable_id & seoable_type columns will store the information of model and its id.
Model
Lets define the relationship on model.
Post Model
In the Post model:
public function seo():MorphOne
{
return $this->morphOne(Seo::class, 'seoable');
}
In the category model:
public function seo():MorphOne
{
return $this->morphOne(Seo::class, 'seoable');
}
In the SEO model:
public function seoable(): MorphTo
{
return $this->morphTo();
}
Creating A Relationship Record:
To create a record, it is very simple. Lets first create one category record.
$category = Category::create(['name' => 'Programming']);
Now, if i want to add seo for the above category model. I can simple use:
$category->seo()->create([
'meta_title' => 'Programming Tutorials',
'meta_description' => 'Best programming tutorials with SEO support.',
'meta_keywords' => 'php, laravel, tutorials'
]);
Similarly for Post record:
$post = Post::create([
'title' => 'Laravel Polymorphic Example',
'content' => 'This is how you use polymorphic relationships in Laravel.',
]);
Now to add SEO fields for my post:
$post->seo()->create([
'meta_title' => 'Laravel Polymorphic SEO',
'meta_description' => 'Learn polymorphic relationships in Laravel.',
'meta_keywords' => 'laravel, polymorphic, seo'
]);
See how simple is that.
Retrieving Records:
Now, the main important thing that we need to know is how we can retrieve the records.
To retrieve the SEO for our category:
$category = Category::with('seo')->first();
echo $category->seo->meta_description; // we are using morphOne
Similarly to retrieve the SEO of our post:
$post = Post::with('seo')->first();
echo $post->seo->meta_title;
What if we need to get reverse data from Seo table to parent table, for this we can easily call the relationship defined on our SEO table.
$seo = Seo::first();
// this will return either a Post or Category model instance
$relatedModel = $seo->seoable;