Полиморфные отношения в Laravel Eloquent позволяют модели принадлежать более чем одной другой модели через единую ассоциацию. Это мощный инструмент для реализации сложных связей в базе данных.
Необходимы таблицы:
comments
(id, body, commentable_id, commentable_type)posts
(id, title, content)videos
(id, title, url)Миграция для полиморфной связи:
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->text('body');
$table->unsignedBigInteger('commentable_id');
$table->string('commentable_type');
$table->timestamps();
});
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function commentable()
{
return $this->morphTo();
}
}
// Post.php
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
// Video.php
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
$post = Post::find(1);
foreach ($post->comments as $comment) {
// Работа с комментарием
}
$post->comments()->create([
'body' => 'Отличный пост!'
]);
$video->comments()->create([
'body' => 'Классное видео!'
]);
$comment = Comment::find(1);
$commentable = $comment->commentable;
// commentable будет экземпляром Post или Video
Пример: тэги для постов и видео
taggables
(tag_id, taggable_id, taggable_type)tags
(id, name)posts
и videos
как в предыдущем примереМиграция:
Schema::create('taggables', function (Blueprint $table) {
$table->unsignedBigInteger('tag_id');
$table->unsignedBigInteger('taggable_id');
$table->string('taggable_type');
});
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}
public function videos()
{
return $this->morphedByMany(Video::class, 'taggable');
}
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
// Добавление тега к посту
$post->tags()->attach($tagId);
// Получение всех постов для тега
$tag = Tag::find(1);
$posts = $tag->posts;
По умолчанию Eloquent использует полное имя класса для хранения в поле *_type
. Можно изменить это поведение:
// В модели Comment
public function commentable()
{
return $this->morphTo(null, 'commentable_type', 'commentable_id');
}
// В моделях Post/Video
public function comments()
{
return $this->morphMany(Comment::class, 'commentable', 'commentable_type', 'commentable_id');
}
Используйте полиморфные отношения для:
Избегайте избыточности: не создавайте полиморфные связи там, где подойдут обычные
Индексы: всегда добавляйте индексы для полиморфных полей
$table->index(['commentable_id', 'commentable_type']);
Comment::with('commentable')->get();
Полиморфные отношения в Eloquent предоставляют гибкий способ организации связей между моделями, когда одна модель может принадлежать разным типам моделей через единый интерфейс. Они особенно полезны для функциональности, которая может применяться к различным сущностям (комментарии, тэги, медиа). Правильное использование полиморфных отношений значительно упрощает структуру базы данных и код приложения.