Laravel Polymorphic Relationships – Complete Guide
Polymorphic relationships in Laravel allow a model to belong to more than one other model using a single association.
They are especially useful when multiple models share the same kind of relationship — such as comments, likes, tags, or images.
When to Use Polymorphic Relationships?
Use polymorphic relationships when:
- You have a single model (e.g.
Comment) that can belong to multiple other models (e.g.Post,Video,Product) - You don’t want to create separate foreign keys or tables for each relationship type.
Example Use Case: Comments on Posts and Videos
Let’s say you want to allow users to comment on both blog posts and videos.
Instead of creating two separate tables like post_comments and video_comments, you can create one comments table using polymorphic relationships.
Step-by-Step Implementation
1. Create Models & Migrations
Run:
php artisan make:model Post -m php artisan make:model Video -m php artisan make:model Comment -m
2. Posts Table Migration (database/migrations/xxxx_create_posts_table.php)
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->timestamps();
});
3. Videos Table Migration
Schema::create('videos', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->timestamps();
});
4. Comments Table Migration
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->text('body');
// Polymorphic relation fields
$table->unsignedBigInteger('commentable_id');
$table->string('commentable_type');
$table->timestamps();
});
Here,commentable_idandcommentable_typedetermine the model (Post or Video) the comment belongs to.
5. Define Relationships in Models
In Comment.php:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $fillable = ['body'];
public function commentable()
{
return $this->morphTo();
}
}
In Post.php:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = ['title'];
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
In Video.php:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
protected $fillable = ['title'];
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
6. Using the Relationship (Example)
Create Post and Add Comment:
$post = Post::create(['title' => 'Laravel Polymorphic Tutorial']); $post->comments()->create(['body' => 'Great article!']);
Create Video and Add Comment:
$video = Video::create(['title' => 'Laravel Video']); $video->comments()->create(['body' => 'Awesome tutorial!']);
7. Accessing Comments
Get all comments of a post:
$post = Post::find(1);
foreach ($post->comments as $comment) {
echo $comment->body;
}
Get the parent of a comment:
$comment = Comment::find(1); $parent = $comment->commentable; // Could be Post or Video
Reverse: One Model with Many Parent Models
The power of polymorphic is that you can go both ways:
$post->comments→ all comments for the post$comment->commentable→ the post or video it belongs to
Real-Life Use Cases
comments→ for posts, products, videos, etc.images→ for users, posts, categoriestags→ for articles, videos, photoslikes→ for any content
Tips & Gotchas
TipDescriptionUse correct typecommentable_type must store full class name (App\Models\Post)morphTo() magicLaravel auto-resolves based on *_id and *_typeIndex columnsAdd indexes on commentable_id and commentable_type for speedUse with()Eager load relationships to reduce queries
Bonus: Migration Index Example
$table->index(['commentable_id', 'commentable_type']);
Summary
FeatureBenefitmorphTo()Allows one model to belong to multiple typesmorphMany() / morphOne()Used by the parent modelsReduces tablesClean design, less duplicationGood for shared behaviorsLike comments, tags, uploads
Conclusion
Laravel’s polymorphic relationships are a powerful way to manage shared relationships across multiple models. They save you from writing repetitive code and keep your database clean and efficient.
Comments (0)