مقاله

Comment روی Post و Video، Media Library و morphMap — polymorphic relation از مبتدی تا production.

روابط Polymorphic در Eloquent — راهنمای عمیق morphMany و morphTo

روابط 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.

معماری دامنه