Laravel Eloquent Relationship: Belajar One to One, One to Many, dan Many to Many
Dalam aplikasi Laravel, data hampir selalu memiliki hubungan dengan data lainnya. User dapat memiliki profile. Satu user dapat membuat banyak artikel. Satu artikel dapat memiliki banyak komentar. Di sisi lain, satu artikel juga dapat memiliki banyak tag, dan satu tag dapat digunakan oleh banyak artikel.
Jika hubungan tersebut ditangani menggunakan query database secara manual di berbagai tempat, kode aplikasi akan cepat menjadi rumit.
Laravel menyediakan Eloquent Relationship untuk mengatasi masalah tersebut.
Dengan Eloquent Relationship, hubungan antar-tabel dapat didefinisikan langsung pada model sehingga kode menjadi lebih ekspresif, mudah dibaca, dan lebih mudah dipelihara.
Artikel ini membahas konsep relationship Eloquent dari dasar hingga praktik yang umum digunakan dalam aplikasi Laravel.
Apa Itu Eloquent Relationship?
Eloquent Relationship adalah fitur Laravel Eloquent ORM yang memungkinkan sebuah model berhubungan dengan model lainnya berdasarkan relasi antar-tabel di database.
Misalnya terdapat dua tabel:
users
↓
posts
Seorang user dapat memiliki banyak post.
Dalam model User, hubungan tersebut dapat ditulis:
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
Setelah relationship dibuat, data dapat diakses dengan:
$user->posts;
Eloquent akan menangani query database yang diperlukan untuk mengambil post milik user tersebut.
Mengapa Relationship Penting?
Tanpa relationship, developer mungkin harus menulis query secara manual setiap kali membutuhkan data yang berhubungan.
Dengan relationship, kode dapat dibuat lebih deklaratif.
Contohnya:
$user->posts;
lebih mudah dipahami daripada harus mengulang query berdasarkan user_id di banyak tempat.
Relationship juga membantu ketika aplikasi memiliki struktur data yang kompleks.
Misalnya:
User
├── Profile
└── Posts
├── Comments
└── Tags
Model dapat merepresentasikan hubungan tersebut secara langsung.
Konsep Foreign Key
Sebelum memahami relationship Eloquent, penting untuk memahami foreign key.
Misalnya tabel users memiliki:
id
name
email
Kemudian tabel posts memiliki:
id
user_id
title
content
posts.user_id adalah foreign key yang menunjuk ke users.id.
Secara konsep:
users.id
↑
|
posts.user_id
Eloquent menggunakan struktur tersebut untuk mengetahui bagaimana dua model berhubungan.
Tiga Relationship Dasar yang Wajib Dipahami
Dalam aplikasi Laravel, tiga relationship yang paling sering digunakan adalah:
- One to One
- One to Many
- Many to Many
Selain itu Laravel juga memiliki relationship yang lebih lanjut, seperti:
- Has One Through
- Has Many Through
- One of Many
- Polymorphic One to One
- Polymorphic One to Many
- Polymorphic Many to Many
Untuk memahami relationship secara kuat, tiga tipe dasar sebaiknya dikuasai terlebih dahulu.
One to One
One to One berarti satu record memiliki satu record yang berhubungan.
Contoh paling mudah adalah:
User
↓
Profile
Satu user memiliki satu profile.
Struktur database dapat dibuat seperti:
users
├── id
├── name
└── email
profiles
├── id
├── user_id
└── bio
Karena foreign key berada pada tabel profiles, maka Profile memiliki hubungan dengan User.
Migration untuk One to One
Migration users:
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamps();
});
Migration profiles:
Schema::create('profiles', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')
->unique()
->constrained()
->cascadeOnDelete();
$table->text('bio')->nullable();
$table->timestamps();
});
Perhatikan penggunaan:
->unique()
Jika setiap user hanya boleh memiliki satu profile, user_id sebaiknya dibuat unique.
Dengan demikian database juga membantu memastikan aturan One to One tersebut.
hasOne() pada Model User
Pada model User:
use Illuminate\Database\Eloquent\Relations\HasOne;
public function profile(): HasOne
{
return $this->hasOne(Profile::class);
}
Sekarang profile dapat diambil dengan:
$user = User::find(1);
$profile = $user->profile;
belongsTo() pada Model Profile
Relationship dari arah sebaliknya:
use Illuminate\Database\Eloquent\Relations\BelongsTo;
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
Sekarang:
$profile = Profile::find(1);
$user = $profile->user;
Keduanya dapat digunakan karena relationship didefinisikan pada kedua model.
Cara Memahami hasOne() dan belongsTo()
Kesalahan umum developer pemula adalah menghafalkan method tanpa memahami arahnya.
Gunakan aturan sederhana:
User
↓ hasOne()
Profile
Artinya:
User memiliki satu Profile.
Sedangkan:
Profile
↓ belongsTo()
User
Artinya:
Profile dimiliki oleh User.
Perhatikan model yang sedang menjadi titik awal relationship.
One to Many
One to Many berarti satu record memiliki banyak record lainnya.
Contoh:
User
↓
Posts
Satu user dapat memiliki banyak post.
Tetapi satu post hanya memiliki satu user.
Strukturnya:
users
├── id
├── name
└── email
posts
├── id
├── user_id
├── title
└── content
Migration One to Many
Migration posts:
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')
->constrained()
->cascadeOnDelete();
$table->string('title');
$table->text('content');
$table->timestamps();
});
Berbeda dengan One to One, user_id tidak dibuat unique.
Alasannya karena satu user boleh memiliki banyak post.
Contohnya:
users
id = 1
posts
id = 1, user_id = 1
id = 2, user_id = 1
id = 3, user_id = 1
hasMany() pada Model User
Pada User:
use Illuminate\Database\Eloquent\Relations\HasMany;
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
Mengambil semua post:
$user = User::find(1);
$posts = $user->posts;
Karena hasilnya berupa collection, data dapat diproses menggunakan loop:
foreach ($user->posts as $post) {
echo $post->title;
}
belongsTo() pada Model Post
Pada Post:
use Illuminate\Database\Eloquent\Relations\BelongsTo;
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
Sekarang:
$post = Post::find(1);
echo $post->user->name;
Relasinya menjadi:
User
↓ hasMany()
Posts
Post
↓ belongsTo()
User
Membuat Data Melalui Relationship
Relationship juga dapat digunakan untuk membuat record baru.
Misalnya:
$user->posts()->create([
'title' => 'Belajar Laravel',
'content' => 'Memahami Eloquent Relationship',
]);
Laravel akan mengisi user_id berdasarkan user yang menjadi parent relationship.
Ini lebih nyaman dibanding:
Post::create([
'user_id' => $user->id,
'title' => 'Belajar Laravel',
'content' => 'Memahami Eloquent Relationship',
]);
Keduanya valid, tetapi relationship membuat konteks parent-child lebih eksplisit.
Mass Assignment pada Relationship
Saat menggunakan:
$user->posts()->create([
'title' => 'Belajar Laravel',
'content' => '...',
]);
model Post tetap perlu mengizinkan field yang digunakan.
Contoh:
protected $fillable = [
'title',
'content',
];
Jangan memasukkan field sensitif atau field yang tidak seharusnya dapat diisi melalui mass assignment.
Menambahkan Beberapa Record Melalui Relationship
Untuk membuat banyak record sekaligus, Anda juga dapat menggunakan:
$user->posts()->createMany([
[
'title' => 'Artikel Pertama',
'content' => 'Isi artikel pertama',
],
[
'title' => 'Artikel Kedua',
'content' => 'Isi artikel kedua',
],
]);
Foreign key tetap diatur berdasarkan relationship.
Many to Many
Many to Many terjadi ketika banyak record dapat berhubungan dengan banyak record lainnya.
Contoh populer:
Posts
↕
Tags
Satu post dapat memiliki banyak tag.
Satu tag juga dapat digunakan oleh banyak post.
Contohnya:
Post A
├── Laravel
├── PHP
└── Backend
Post B
├── Laravel
└── Database
Karena satu post memiliki banyak tag dan satu tag dapat digunakan banyak post, dibutuhkan tabel penghubung.
Apa Itu Pivot Table?
Pivot table adalah tabel yang menghubungkan dua tabel dalam relationship Many to Many.
Misalnya:
posts
tags
post_tag
Tabel post_tag:
post_id
tag_id
Strukturnya:
posts
↓
post_tag
↑
tags
Migration Pivot Table
Migration dapat dibuat seperti:
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']);
});
Primary key gabungan tersebut mencegah kombinasi post dan tag yang sama dimasukkan lebih dari sekali.
belongsToMany()
Pada model Post:
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}
Pada model Tag:
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}
Sekarang:
$post->tags;
akan mengambil semua tag yang berhubungan dengan post.
Sedangkan:
$tag->posts;
mengambil semua post yang menggunakan tag tersebut.
Menambahkan Relationship dengan attach()
Misalnya post dengan ID 1 ingin diberi tag dengan ID 2:
$post->tags()->attach(2);
Beberapa tag sekaligus:
$post->tags()->attach([1, 2, 3]);
Anda juga dapat memasukkan data pivot tambahan:
$post->tags()->attach([
1 => ['created_by' => 10],
]);
Tentu saja kolom created_by harus tersedia pada pivot table.
Menghapus Relationship dengan detach()
Untuk menghapus hubungan tertentu:
$post->tags()->detach(2);
Menghapus beberapa relationship:
$post->tags()->detach([1, 2]);
Menghapus semua relationship:
$post->tags()->detach();
Perintah tersebut menghapus relationship dari pivot table, bukan menghapus record Tag dari tabel tags.
Menggunakan sync()
sync() sangat berguna ketika aplikasi memiliki form yang mengirim daftar ID terbaru.
Misalnya:
$post->tags()->sync([1, 3, 5]);
Laravel akan menyesuaikan isi pivot table sehingga relationship yang tersisa adalah tag 1, 3, dan 5.
Tag yang sebelumnya terhubung tetapi tidak ada dalam array dapat dilepas.
syncWithoutDetaching()
Jika ingin menambahkan relationship tanpa menghapus relationship yang sudah ada:
$post->tags()->syncWithoutDetaching([4, 5]);
Ini berguna ketika aplikasi ingin menambahkan beberapa tag tanpa memengaruhi tag yang sudah terpasang.
Pivot Table dengan Kolom Tambahan
Pivot table tidak selalu hanya berisi dua foreign key.
Contohnya relationship:
User
↕
Course
Tabel pivot:
course_user
├── user_id
├── course_id
├── enrolled_at
└── status
Kolom tambahan tersebut dapat menyimpan informasi tentang relationship.
Mengakses Data Pivot
Pada model:
public function courses(): BelongsToMany
{
return $this->belongsToMany(Course::class)
->withPivot('enrolled_at', 'status');
}
Kemudian:
foreach ($user->courses as $course) {
echo $course->pivot->status;
}
Property pivot berisi data dari tabel pivot.
Memberi Nama Pivot Model
Jika pivot memiliki logic yang cukup kompleks, Anda dapat menggunakan custom pivot model.
Contohnya:
return $this->belongsToMany(Course::class)
->using(CourseUser::class);
Pendekatan ini berguna ketika pivot bukan sekadar tabel penghubung sederhana, tetapi memiliki perilaku atau aturan bisnis tertentu.
Custom Foreign Key
Laravel menggunakan konvensi penamaan untuk menebak foreign key.
Contoh:
return $this->hasMany(Post::class);
Laravel biasanya mencari:
posts.user_id
Namun, jika kolom Anda bernama:
posts.author_id
relationship dapat ditulis:
return $this->hasMany(Post::class, 'author_id');
Ini berguna ketika database menggunakan naming convention yang berbeda.
Custom Local Key
Jika primary key parent bukan id, key tersebut juga dapat ditentukan.
Contoh:
return $this->hasMany(Post::class, 'author_id', 'uuid');
Artinya relationship menggunakan:
posts.author_id
yang mengarah ke:
users.uuid
Pastikan struktur database memang menggunakan key tersebut.
Custom Pivot Table
Laravel biasanya dapat menebak nama pivot table berdasarkan nama model.
Untuk Post dan Tag, Laravel mengharapkan:
post_tag
Jika nama pivot berbeda, tentukan secara eksplisit:
return $this->belongsToMany(
Tag::class,
'article_categories'
);
Foreign key pivot juga dapat ditentukan jika struktur database tidak mengikuti konvensi Laravel.
Eager Loading
Salah satu konsep terpenting dalam relationship adalah eager loading.
Misalnya Anda mengambil semua post:
$posts = Post::all();
Kemudian:
foreach ($posts as $post) {
echo $post->user->name;
}
Kode tersebut terlihat sederhana, tetapi dapat menghasilkan banyak query database.
Masalah ini dikenal sebagai N+1 query problem.
Solusinya:
$posts = Post::with('user')->get();
Kemudian:
foreach ($posts as $post) {
echo $post->user->name;
}
Relationship user sudah dimuat bersama data post.
Apa Itu N+1 Query Problem?
Misalnya terdapat 100 post.
Aplikasi menjalankan:
1 query
→ mengambil 100 posts
100 query
→ mengambil user masing-masing post
Total dapat menjadi sekitar:
101 queries
Inilah yang disebut N+1.
Dengan eager loading:
Post::with('user')->get();
Eloquent dapat mengambil data relationship secara lebih efisien.
Secara konsep:
1 query
→ posts
1 query
→ users terkait
Jumlah query dapat jauh lebih sedikit.
Eager Loading Banyak Relationship
Jika sebuah halaman membutuhkan user dan tags:
$posts = Post::with([
'user',
'tags',
])->get();
Relationship dapat dimuat sekaligus.
Nested Eager Loading
Relationship juga dapat dimuat secara bertingkat.
Misalnya:
Post
↓
User
↓
Profile
Gunakan:
$posts = Post::with('user.profile')->get();
Untuk relationship yang lebih kompleks:
$posts = Post::with([
'user.profile',
'tags',
])->get();
Gunakan eager loading hanya untuk relationship yang benar-benar dibutuhkan.
Eager Loading dengan Kondisi
Anda dapat memberikan constraint:
$posts = Post::with([
'comments' => function ($query) {
$query->latest();
},
])->get();
Ini berguna ketika relationship membutuhkan filtering atau ordering tertentu.
Lazy Eager Loading dengan load()
Terkadang model sudah terlanjur diambil:
$posts = Post::all();
Kemudian Anda baru mengetahui bahwa membutuhkan user.
Anda dapat menggunakan:
$posts->load('user');
Ini berbeda dari:
Post::with('user')->get();
karena with() digunakan sebelum query utama dijalankan, sedangkan load() digunakan setelah model sudah tersedia.
loadMissing()
Jika ingin memuat relationship hanya jika belum dimuat:
$posts->loadMissing('user');
Ini berguna dalam kode yang dipanggil dari beberapa bagian aplikasi dan ingin menghindari pemuatan relationship yang sama secara tidak perlu.
Memeriksa Relationship yang Sudah Dimuat
Eloquent menyediakan:
$post->relationLoaded('user');
Contohnya:
if ($post->relationLoaded('user')) {
// relationship sudah tersedia
}
Hal ini dapat membantu ketika Anda ingin memastikan akses relationship tidak memicu query tambahan secara tidak sengaja.
has() untuk Mencari Model yang Memiliki Relationship
Misalnya ingin mengambil user yang memiliki setidaknya satu post:
$users = User::has('posts')->get();
Laravel akan mencari user berdasarkan keberadaan relationship tersebut.
Anda juga dapat menentukan jumlah:
$users = User::has('posts', '>=', 5)->get();
Artinya mengambil user yang memiliki minimal lima post.
whereHas() untuk Filtering Relationship
Misalnya ingin mencari user yang memiliki post dengan status published:
$users = User::whereHas('posts', function ($query) {
$query->where('status', 'published');
})->get();
Ini sangat berguna untuk filter berdasarkan data relationship.
Contoh lainnya:
$posts = Post::whereHas('tags', function ($query) {
$query->where('name', 'Laravel');
})->get();
Artinya mengambil post yang memiliki tag Laravel.
whereDoesntHave()
Untuk mencari model yang tidak memiliki relationship tertentu:
$users = User::whereDoesntHave('posts')->get();
Artinya mengambil user yang belum memiliki post.
Menghitung Relationship dengan withCount()
Jika hanya membutuhkan jumlah relationship, tidak selalu perlu mengambil seluruh datanya.
Contoh:
$users = User::withCount('posts')->get();
Sekarang setiap user memiliki property:
$user->posts_count;
Contoh penggunaan:
foreach ($users as $user) {
echo $user->name;
echo $user->posts_count;
}
Ini lebih tepat ketika halaman hanya membutuhkan jumlah data, bukan seluruh post.
withExists()
Jika aplikasi hanya ingin mengetahui apakah relationship tersedia, Anda dapat menggunakan:
$users = User::withExists('posts')->get();
Kemudian dapat memeriksa property yang dihasilkan untuk mengetahui apakah user memiliki post.
Ini dapat menjadi alternatif yang lebih tepat daripada mengambil seluruh relationship hanya untuk mengecek keberadaannya.
Relationship dengan Soft Delete
Jika model yang berhubungan menggunakan Soft Deletes, hasil relationship dapat dipengaruhi oleh global scope soft delete.
Misalnya:
$post->user;
Jika user terkait sudah di-soft-delete, user tersebut mungkin tidak muncul pada relationship normal.
Untuk kebutuhan tertentu, relationship dapat dikonfigurasi agar menyertakan data yang sudah di-soft-delete.
Contohnya:
public function user(): BelongsTo
{
return $this->belongsTo(User::class)->withTrashed();
}
Gunakan pendekatan tersebut hanya jika memang sesuai dengan aturan bisnis aplikasi.
withDefault() untuk Relationship yang Tidak Ada
Bayangkan sebuah Post dapat memiliki user yang belum tersedia.
Daripada:
$post->user->name;
menghasilkan error ketika user tidak ada, relationship dapat menggunakan default model:
public function user(): BelongsTo
{
return $this->belongsTo(User::class)
->withDefault();
}
Default object tersebut dapat mencegah error ketika relationship kosong.
Anda juga dapat memberikan nilai default:
public function user(): BelongsTo
{
return $this->belongsTo(User::class)
->withDefault([
'name' => 'Guest',
]);
}
Nullable Relationship
Tidak semua relationship wajib tersedia.
Misalnya sebuah post boleh dibuat tanpa author tertentu.
Migration dapat menggunakan:
$table->foreignId('user_id')
->nullable()
->constrained()
->nullOnDelete();
Dengan begitu, ketika user dihapus, user_id dapat menjadi NULL.
Model:
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
Ketika mengakses:
$post->user;
hasilnya dapat berupa null.
Karena itu kode aplikasi perlu menangani kemungkinan tersebut.
Kesalahan Umum: Salah Menentukan Relationship
Contoh yang sering terjadi:
public function user()
{
return $this->hasOne(User::class);
}
pada model Post.
Jika tabel posts memiliki user_id, biasanya yang benar:
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
Ingat:
User memiliki Post
→ hasMany()
Post dimiliki User
→ belongsTo()
Kesalahan Umum: Foreign Key Tidak Sesuai
Relationship dapat terlihat benar tetapi gagal karena nama kolom tidak sesuai.
Misalnya model mengharapkan:
user_id
tetapi database memiliki:
author_id
Jika menggunakan naming custom, tentukan foreign key secara eksplisit:
return $this->belongsTo(User::class, 'author_id');
Kesalahan Umum: Pivot Table Tidak Sesuai Konvensi
Laravel memiliki konvensi penamaan pivot table.
Jika Laravel mengharapkan:
post_tag
tetapi database memiliki:
post_tags
relationship dapat gagal jika nama tersebut tidak dikonfigurasi dengan benar.
Jika menggunakan nama custom:
return $this->belongsToMany(
Tag::class,
'post_tags'
);
Kesalahan Umum: Tidak Menggunakan Eager Loading
Kode seperti:
$posts = Post::all();
foreach ($posts as $post) {
echo $post->user->name;
}
dapat menjadi masalah ketika jumlah data besar.
Biasakan mengevaluasi relationship yang digunakan pada loop dan pertimbangkan:
$posts = Post::with('user')->get();
Kesalahan Umum: Terlalu Banyak Eager Loading
Kebalikan dari N+1 juga perlu diperhatikan.
Jangan melakukan:
Post::with([
'user',
'user.profile',
'comments',
'comments.user',
'tags',
'categories',
'attachments',
'likes',
])->get();
jika halaman sebenarnya hanya membutuhkan user dan tags.
Eager loading yang berlebihan dapat membuat query dan penggunaan memory meningkat.
Prinsipnya sederhana:
Load relationship yang memang dibutuhkan oleh use case tersebut.
Kesalahan Umum: Menganggap Relationship Selalu Mengembalikan Satu Object
hasOne() biasanya menghasilkan satu model atau null.
belongsTo() juga demikian.
Tetapi hasMany() dan belongsToMany() menghasilkan collection.
Contoh:
$user->profile;
berbeda dengan:
$user->posts;
posts dapat berisi banyak model.
Untuk collection:
foreach ($user->posts as $post) {
// ...
}
Pemahaman ini penting agar tidak salah menggunakan property relationship.
Kesalahan Umum: Menghapus Data Parent Tanpa Memikirkan Child
Misalnya user memiliki banyak post.
Jika user dihapus, apa yang harus terjadi pada post?
Pilihan dapat berbeda berdasarkan kebutuhan:
User dihapus
↓
Posts ikut dihapus
atau:
User dihapus
↓
Posts tetap ada
↓
user_id menjadi NULL
Aturan tersebut sebaiknya ditentukan pada database dan migration.
Contoh:
->cascadeOnDelete();
atau:
->nullOnDelete();
Jangan memilih cascade hanya karena lebih mudah. Pastikan perilakunya sesuai dengan kebutuhan aplikasi.
Relationship dan Database Design Harus Konsisten
Eloquent Relationship bukan pengganti desain database.
Model:
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
harus memiliki struktur database yang mendukung:
posts.user_id
Begitu pula Many to Many membutuhkan pivot table yang sesuai.
Karena itu, desain relationship sebaiknya dimulai dari pemahaman terhadap data:
Apa yang dimiliki?
Apa yang dimiliki oleh siapa?
Apakah satu atau banyak?
Apakah relationship membutuhkan atribut tambahan?
Setelah itu barulah migration dan model dibuat.
Contoh Struktur Blog Laravel
Untuk aplikasi blog sederhana, struktur relationship dapat berupa:
User
├── Profile
└── Posts
├── Comments
└── Tags
Relationship-nya:
User
→ hasOne Profile
User
→ hasMany Posts
Post
→ belongsTo User
Post
→ hasMany Comments
Comment
→ belongsTo Post
Post
↔ belongsToMany Tags
Tag
↔ belongsToMany Posts
Dengan struktur tersebut, model dapat menjadi representasi yang jelas dari domain aplikasi.
Contoh Implementasi Model
Model User:
class User extends Authenticatable
{
public function profile(): HasOne
{
return $this->hasOne(Profile::class);
}
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
Model Post:
class Post extends Model
{
protected $fillable = [
'title',
'content',
'user_id',
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}
}
Model Comment:
class Comment extends Model
{
protected $fillable = [
'content',
'user_id',
'post_id',
];
public function post(): BelongsTo
{
return $this->belongsTo(Post::class);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
Model Tag:
class Tag extends Model
{
protected $fillable = [
'name',
];
public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}
}
Mengambil Data Blog dengan Relationship
Misalnya ingin menampilkan post beserta author, komentar, dan tag:
$posts = Post::with([
'user',
'comments.user',
'tags',
])->latest()->get();
Kemudian pada view:
@foreach ($posts as $post)
<h2>{{ $post->title }}</h2>
<p>Author: {{ $post->user->name }}</p>
@foreach ($post->tags as $tag)
<span>{{ $tag->name }}</span>
@endforeach
@endforeach
Relationship membuat kode view tetap mudah dipahami.
Kapan Sebaiknya Menggunakan Relationship?
Gunakan relationship ketika hubungan tersebut merupakan bagian nyata dari struktur data aplikasi.
Contohnya:
User → Profile
jika setiap user memiliki profile.
User → Posts
jika user dapat membuat banyak post.
Post ↔ Tags
jika post dan tag memiliki hubungan Many to Many.
Jangan membuat relationship hanya untuk mengurangi beberapa baris query. Relationship sebaiknya merepresentasikan hubungan domain dan database yang memang masuk akal.
Tips Merancang Relationship Laravel
Sebelum membuat relationship, tanyakan beberapa hal:
1. Siapa parent dan child?
Contoh:
User → Posts
User adalah parent, Post adalah child.
2. Berapa banyak record yang dapat dimiliki?
Jika satu:
hasOne()
Jika banyak:
hasMany()
3. Di mana foreign key berada?
Foreign key biasanya berada pada tabel yang memiliki hubungan belongsTo().
4. Apakah kedua sisi relationship perlu didefinisikan?
Sering kali iya.
Contohnya:
User → posts
Post → user
Dengan dua arah tersebut, navigasi data menjadi lebih fleksibel.
5. Apakah membutuhkan pivot table?
Jika:
A → banyak B
B → banyak A
kemungkinan besar membutuhkan Many to Many dengan pivot table.
Ringkasan Method Relationship
Sebagai referensi cepat:
| Method | Makna | Contoh |
|---|---|---|
hasOne() | Memiliki satu | User → Profile |
belongsTo() | Dimiliki oleh | Post → User |
hasMany() | Memiliki banyak | User → Posts |
belongsToMany() | Banyak ke banyak | Post ↔ Tag |
Kemudian beberapa method penting untuk mengambil relationship:
| Method | Kegunaan |
|---|---|
with() | Eager loading sebelum query |
load() | Eager loading setelah model tersedia |
loadMissing() | Load jika belum tersedia |
has() | Filter berdasarkan keberadaan relationship |
whereHas() | Filter relationship berdasarkan kondisi |
whereDoesntHave() | Mencari model tanpa relationship |
withCount() | Mengambil jumlah relationship |
attach() | Menambahkan Many to Many |
detach() | Menghapus Many to Many |
sync() | Menyinkronkan Many to Many |
syncWithoutDetaching() | Menambah tanpa melepas relationship lama |
Kesimpulan
Laravel Eloquent Relationship membantu developer bekerja dengan data yang saling berhubungan tanpa harus menulis query database secara manual di setiap bagian aplikasi.
Konsep yang paling penting untuk dikuasai adalah:
- One to One menggunakan
hasOne()danbelongsTo(). - One to Many menggunakan
hasMany()danbelongsTo(). - Many to Many menggunakan
belongsToMany()dan pivot table. - Foreign key menentukan bagaimana tabel saling terhubung.
attach(),detach(), dansync()digunakan untuk mengelola Many to Many.with()danload()membantu mengontrol eager loading.- N+1 query problem perlu diperhatikan ketika mengakses relationship dalam loop.
has(),whereHas(), danwithCount()berguna untuk query berdasarkan relationship.- Struktur database, migration, dan relationship pada model harus konsisten.
Jika konsep parent, child, foreign key, dan cardinality sudah dipahami, method Eloquent seperti hasMany(), belongsTo(), dan belongsToMany() akan jauh lebih mudah dipahami.
Pada akhirnya, tujuan Eloquent Relationship bukan sekadar membuat query lebih pendek, tetapi membuat hubungan antar-data terlihat jelas di dalam kode aplikasi Laravel.

