Relasi Many to Many di Eloquent
Hubungkan post dan tag lewat tabel pivot dengan belongsToMany, attach, sync, dan data pivot.
Konsep dan tabel pivot
Many to many: satu post punya banyak tag, satu tag dipakai banyak post. Butuh tabel perantara (pivot), misalnya post_tag dengan kolom post_id dan tag_id. Nama tabel pivot mengikuti urutan alfabetis nama model tunggal.
php artisan make:migration create_post_tag_tableSchema::create('post_tag', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('tag_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});Definisikan belongsToMany
// app/Models/Post.php
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}
// app/Models/Tag.php
public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}attach, detach, sync
$post = Post::find(1);
// Tambah relasi (bisa satu ID atau array)
$post->tags()->attach(3);
$post->tags()->attach([3, 5, 7]);
// Hapus relasi tertentu
$post->tags()->detach(3);
// Samakan persis dengan array ini (hapus yang tidak ada di array)
$post->tags()->sync([3, 5]);
// sync tanpa menghapus yang sudah ada
$post->tags()->syncWithoutDetaching([8]);sync() paling sering dipakai di form edit dengan checkbox tag: kirim array ID dari form, biarkan Laravel yang menyesuaikan.
Data tambahan di pivot
Kadang pivot butuh kolom sendiri, misalnya created_by. Tambahkan kolomnya di migration, lalu akses dengan withPivot():
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class)
->withPivot('created_by')
->withTimestamps();
}
// Akses:
foreach ($post->tags as $tag) {
echo $tag->pivot->created_by;
}Catatan teknis:
attach()tidak mengecek duplikasi. Memanggilattach(3)dua kali membuat dua baris pivot identik. Kalau relasi bisa di-attach berulang (misalnya dari request yang di-submit dua kali), pakaisyncWithoutDetaching()atau buat unique index di migration:$table->unique(['post_id', 'tag_id']).