Связи: многие ко многим
Ситуация
У поста много тегов, у тега много постов. Нужна промежуточная таблица.
Модели
Post:
public function tags()
{
return $this->belongsToMany(Tag::class);
}
Tag:
public function posts()
{
return $this->belongsToMany(Post::class);
}
Миграция
Имя таблицы: post_tag (алфавитный порядок, единственное число).
Schema::create('post_tag', function (Blueprint $table) {
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('tag_id')->constrained()->cascadeOnDelete();
$table->primary(['post_id', 'tag_id']);
});
Операции
Привязать
$post->tags()->attach($tagId);
$post->tags()->attach([1, 2, 3]);
Отвязать
$post->tags()->detach($tagId);
$post->tags()->detach([1, 2, 3]);
Синхронизировать
Оставить только указанные ID, остальные отвязать:
$post->tags()->sync([1, 2, 3]);
Без отвязки
Добавить новые, не трогая существующие:
$post->tags()->syncWithoutDetaching([4, 5]);
Переключить
Если есть — отвязать, если нет — привязать:
$post->tags()->toggle([1, 2, 3]);
Данные в промежуточной таблице
Если в post_tag есть дополнительные колонки (например, created_at):
return $this->belongsToMany(Tag::class)
->withPivot('created_at')
->withTimestamps();
Доступ к данным:
foreach ($post->tags as $tag) {
echo $tag->pivot->created_at;
}
Фильтрация по промежуточной таблице
return $this->belongsToMany(Tag::class)
->wherePivot('approved', 1);
Переименование pivot
return $this->belongsToMany(Tag::class)
->as('subscription');
Теперь $tag->subscription вместо $tag->pivot.