Laravel 12 Polymorphic Relationships: The Ultimate Guide

Author

Kritim Yantra

Apr 06, 2025

Laravel 12 Polymorphic Relationships: The Ultimate Guide

Introduction to Polymorphic Relationships

Polymorphic relationships allow a model to belong to multiple other models on a single association. This powerful feature lets you create flexible database structures where one model can belong to various models without needing separate tables for each relationship.

Real-World Use Cases

  • Comment system: Comments can belong to Posts, Videos, or Products
  • Media attachments: Files can be attached to multiple models
  • Activity feeds: Activities can track actions on different models

Types of Polymorphic Relationships

Laravel supports three polymorphic relationship types:

  1. One-to-One Polymorphic
  2. One-to-Many Polymorphic
  3. Many-to-Many Polymorphic

1. One-to-Many Polymorphic Relationship

Example Scenario: Comments System

Comments can belong to either Posts or Videos.

Database Structure

comments
  id - integer
  body - text
  commentable_id - integer
  commentable_type - string

posts
  id - integer
  title - string
  body - text

videos
  id - integer
  title - string
  url - string

Migrations

// Create comments table
Schema::create('comments', function (Blueprint $table) {
    $table->id();
    $table->text('body');
    $table->unsignedBigInteger('commentable_id');
    $table->string('commentable_type');
    $table->timestamps();
});

Model Setup

// Comment.php
class Comment extends Model
{
    public function commentable()
    {
        return $this->morphTo();
    }
}

// Post.php
class Post extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

// Video.php
class Video extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

Using the Relationship

// Create comment for a post
$post = Post::find(1);
$comment = $post->comments()->create([
    'body' => 'Great post!'
]);

// Create comment for a video
$video = Video::find(1);
$comment = $video->comments()->create([
    'body' => 'Nice video!'
]);

// Retrieve comments
$post = Post::with('comments')->find(1);
foreach ($post->comments as $comment) {
    echo $comment->body;
}

2. Many-to-Many Polymorphic Relationship

Example Scenario: Taggable System

Tags can be applied to Posts, Videos, and Products.

Database Structure

tags
  id - integer
  name - string

taggables
  tag_id - integer
  taggable_id - integer
  taggable_type - string

Migrations

Schema::create('taggables', function (Blueprint $table) {
    $table->unsignedBigInteger('tag_id');
    $table->unsignedBigInteger('taggable_id');
    $table->string('taggable_type');
});

Model Setup

// Tag.php
class Tag extends Model
{
    public function posts()
    {
        return $this->morphedByMany(Post::class, 'taggable');
    }

    public function videos()
    {
        return $this->morphedByMany(Video::class, 'taggable');
    }
}

// Post.php
class Post extends Model
{
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

// Video.php
class Video extends Model
{
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

Using the Relationship

// Attach tags to a post
$post = Post::find(1);
$post->tags()->attach([1, 2, 3]);

// Attach tags to a video
$video = Video::find(1);
$video->tags()->attach([2, 4]);

// Get all tags for a post
$post = Post::with('tags')->find(1);
foreach ($post->tags as $tag) {
    echo $tag->name;
}

// Find all posts with a specific tag
$tag = Tag::find(1);
$posts = $tag->posts;

3. One-to-One Polymorphic Relationship

Example Scenario: Image Attachments

Images can belong to either Users or Posts.

Database Structure

images
  id - integer
  url - string
  imageable_id - integer
  imageable_type - string

Model Setup

// Image.php
class Image extends Model
{
    public function imageable()
    {
        return $this->morphTo();
    }
}

// User.php
class User extends Model
{
    public function image()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

// Post.php
class Post extends Model
{
    public function image()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

Using the Relationship

// Create image for a user
$user = User::find(1);
$user->image()->create(['url' => 'users/1.jpg']);

// Create image for a post
$post = Post::find(1);
$post->image()->create(['url' => 'posts/1.jpg']);

// Retrieve image
$user = User::with('image')->find(1);
echo $user->image->url;

Advanced Polymorphic Techniques

1. Custom Polymorphic Types

By default, Laravel 12 stores the fully-qualified class name. You can customize this:

use Illuminate\Database\Eloquent\Relations\Relation;

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

2. Eager Loading Polymorphic Relationships

// Eager load comments with their commentable models
$comments = Comment::with('commentable')->get();

foreach ($comments as $comment) {
    if ($comment->commentable instanceof Post) {
        // Handle post comment
    } elseif ($comment->commentable instanceof Video) {
        // Handle video comment
    }
}

3. Querying Polymorphic Relationships

// Get all comments for posts
$comments = Comment::where('commentable_type', 'App\Models\Post')->get();

// Get all tags assigned to videos
$tags = Tag::whereHas('videos')->get();

Conclusion

Polymorphic relationships in Laravel 12 provide incredible flexibility when you need models to associate with multiple other models. Key takeaways:

One-to-Many Polymorphic: For comment-like systems
Many-to-Many Polymorphic: For tagging systems
One-to-One Polymorphic: For single attachments
Customize with morph maps and advanced querying

📌 Questions? Drop them in the comments below!

Tags

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts

What Are Laravel 12 Service Providers?
Web Development
What Are Laravel 12 Service Providers?
#Laravel #Vue
Kritim Yantra Kritim Yantra
Mar 02, 2025
Laravel 12 & Vue3 Integration: How to Build API Calls for Dynamic Output
Kritim Yantra Kritim Yantra
Mar 13, 2025
Understanding Facades in Laravel 12: How to Create Custom Facades
Kritim Yantra Kritim Yantra
Mar 16, 2025