laraveleloquentrelasiMenengah3 mnt baca

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.

bash
php artisan make:migration create_post_tag_table
php
Schema::create('post_tag', function (Blueprint $table) {
    $table->id();
    $table->foreignId('post_id')->constrained()->cascadeOnDelete();
    $table->foreignId('tag_id')->constrained()->cascadeOnDelete();
    $table->timestamps();
});

Definisikan belongsToMany

php
// 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

php
$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():

php
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. Memanggil attach(3) dua kali membuat dua baris pivot identik. Kalau relasi bisa di-attach berulang (misalnya dari request yang di-submit dua kali), pakai syncWithoutDetaching() atau buat unique index di migration: $table->unique(['post_id', 'tag_id']).