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:
- One-to-One Polymorphic
- One-to-Many Polymorphic
- 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!
Projects to explore next
Source-code projects from the KritiMyantra catalogue. Check each project's details before buying.
Flask Authentication System (Free Version) - Kritim Yantra
🛠 Features✔ Google & GitHub Authentication✔ User Registration & Login✔ Profile/Dashboard Access✔ Secure & Mi...
Flask Blog CMS with Admin Dashboard — Python Source Code
A Flask-based blogging website with a built-in admin dashboard. Manage articles, images, categories, tags and featured p...
Laravel 12 + ReactJS Starter Kit: Add Multi-Language Support (Arabic, English, Spanish) with Blog CRUD
🚀 Installation & Setup Download & Extract Get the ZIP from kritimyantra.com and extract it. Includes preconfigu...
Comments
No comments yet. Be the first to comment.
Sign in to join the discussion.