Complete Guide to Laravel Polymorphic Relationships with Real Examples

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;

Leave a Reply

Your email address will not be published. Required fields are marked *