روابط Polymorphic در Eloquent — راهنمای عمیق morphMany و morphTo
وقتی Comment هم به Post و هم به Product وصل میشود، سه جدول جدا نمیسازید — polymorphic یک جدول با commentable_type و commentable_id میسازد. Spatie Media Library، Activity Log و نوتیفیکیشن Laravel همین الگو را استفاده میکنند. پایه در روابط Eloquent؛ اینجا عمیقتر.
ساختار جدول
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->morphs('commentable'); // commentable_id + commentable_type + index
$table->foreignId('user_id')->constrained();
$table->text('body');
$table->timestamps();
});
تعریف relation
// Comment.php
public function commentable(): MorphTo
{
return $this->morphTo();
}
// Post.php
public function comments(): MorphMany
{
return $this->morphMany(Comment::class, 'commentable');
}
نام commentable prefix ستونهاست — قابل تغییر با پارامتر سوم.
ایجاد رکورد
$post->comments()->create([
'user_id' => auth()->id(),
'body' => 'نظر عالی',
]);
morphToMany — tag روی چند model
مثل taggable — یک pivot برای Post و Video.
public function tags(): MorphToMany
{
return $this->morphToMany(Tag::class, 'taggable');
}
Relation::morphMap — امنیت و refactor
پیشفرض type = نام کامل کلاس. اگر class rename کنید، داده قدیم میشکند:
// AppServiceProvider boot
Relation::enforceMorphMap([
'post' => Post::class,
'product' => Product::class,
]);
در DB ذخیره post بهجای namespace کامل — production best practice.
Eager load polymorphic
Comment::with('commentable')->get();
ممکن است N+1 روی انواع مختلف — with(['commentable' => fn ($m) => $m->constrain(...)]) در Laravel 12.
مثال Media (الگوی رایج)
public function images(): MorphMany
{
return $this->morphMany(Media::class, 'mediable');
}
Query همه comment یک user روی همه type
Comment::where('user_id', $userId)
->where('commentable_type', Post::class)
->get();
با morphMap از alias استفاده کنید.
اشتباهات
- فراموش morphMap در production
- index نداشتن روی type+id
- polymorphic وقتی belongsTo ساده کافی است
- cascade delete نادرست بین typeها
جمعبندی
Polymorphic برای shared behavior روی entityهای مختلف. Eager load، transaction برای consistency.