Di section sebelumnya kita memakai Query Builder lewat DB::table() untuk menyisipkan dan membaca data, dan hasilnya selalu berupa stdClass — baris pasif yang tidak punya perilaku, tidak tahu cara menyimpan dirinya sendiri, dan tidak mengenali tabel asalnya. Sementara itu, aplikasi kita hidup di dunia object PHP: class, method, dan type declaration. Object-Relational Mapping (ORM) adalah jembatan di antara dua dunia tersebut, dan Eloquent adalah implementasi Laravel untuk jembatan itu. Chapter ini membedah konsep ORM, pola ActiveRecord yang diadopsi Eloquent, konvensi nama yang membuat model nyaris tanpa konfigurasi, dan apa yang Eloquent tambahkan di atas Query Builder.

Tabel Menjadi Class, Baris Menjadi Object #

ORM memetakan struktur database ke struktur object program. Eloquent menjalankan tiga pemetaan dasar yang konsisten di seluruh framework:

Dunia databaseDunia PHP
Tabel postsClass App\Models\Post
Satu baris pada tabel postsSatu instance Post, misalnya $post
Kolom judul pada baris tersebutAtribut $post->judul

Berdasarkan pemetaan di atas, membaca satu baris berarti membangun satu object, dan menulis perubahan berarti memanggil method penyimpanan pada object tersebut. Kode $post->judul tidak berbeda dari akses property biasa — hanya saja nilainya dibaca dari kolom tabel, bukan dari property yang dideklarasikan manual. Diagram berikut memperlihatkan pemetaan model Post yang sudah kita pakai sejak chapter Column Types :

Satu class dipetakan ke satu tabel, dan setiap atribut instance dipetakan ke satu kolom. Konsekuensinya, tabel apa pun yang bisa kita jelaskan dengan skema juga bisa kita jelaskan dengan class — dan sebaliknya.

Pola ActiveRecord #

Eloquent mengadopsi pola desain ActiveRecord: satu class model membungkus satu tabel, sekaligus membawa seluruh perilaku akses data di dalam class yang sama. Method pencarian seperti Post::find(3) adalah method statis pada class, sedangkan method penyimpanan seperti $post->save() dan $post->delete() adalah method instance yang beroperasi pada satu baris. Data dan perilakunya menjadi satu kesatuan; tidak ada layer tambahan untuk menuliskan query.

Konsekuensi praktisnya, Post::find(3) mengembalikan object yang mengetahui primary key miliknya sendiri. Kita bisa mengubah atributnya lalu memanggil save() untuk menuliskan perubahan kembali ke baris asalnya, tanpa pernah menyentuh query UPDATE secara manual. Pola inilah yang membuat kode controller terasa ringkas: ambil object, ubah, simpan.

Konvensi Nama yang Menghapus Konfigurasi #

Model Eloquent bisa berdiri dengan isi class kosong karena semua keputusan penting sudah diambil lewat konvensi. Tabel berikut merangkum konvensi bawaan yang paling sering kita temui:

AspekKonvensi bawaanContoh
Nama tabelbentuk jamak snake_case dari nama classPost → tabel posts
Primary keykolom id yang bertambah otomatisPost::find(3)
Timestampskolom created_at dan updated_at terisi otomatister-update setiap save()
Koneksikoneksi database default aplikasiconfig('database.default')

Konvensi bukan paksaan. Setiap butir di atas bisa ditimpa lewat property seperti $table, $primaryKey, atau $timestamps ketika tabel kita memang berbeda — cara menimpanya menjadi isi chapter berikutnya.

Apa yang Eloquent Tambahkan di Atas Query Builder #

Eloquent tidak menggantikan Query Builder; Eloquent dibangun di atasnya. Rantai where(), orderBy(), hingga join() tetap bekerja seperti biasa karena setiap model membungkus query builder yang sama. Yang Eloquent tambahkan adalah identitas dan perilaku pada hasil query: baris kembali sebagai object yang mengenali tabelnya, kunci primernya, dan relasinya. Fitur-fitur yang lahir dari fondasi itu antara lain method relationship seperti hasMany(), attribute casting, proteksi mass assignment, query scope, event, sampai soft delete — semuanya dapat dipelajari bertahap di dokumentasi resmi Eloquent .

Bukti paling sederhana perbedaan kedua dunia bisa kita lihat dengan query yang sama pada data seeding Budi dan Siti:

php
use App\Models\Post;
use Illuminate\Support\Facades\DB;

$baris = DB::table('posts')->where('published', true)->first();

$post = Post::where('published', true)->first();

echo 'Query Builder -> ', get_class($baris), ' | judul: ', $baris->judul, "\n";
echo 'Eloquent       -> ', get_class($post), ' | judul: ', $post->judul, "\n";
echo 'casting Eloquent: ', $post->updated_at->format('Y-m-d H:i'), "\n";

Output yang Dihasilkan:

text
Query Builder -> stdClass | judul: Belajar Eloquent
Eloquent       -> App\Models\Post | judul: Belajar Eloquent
casting Eloquent: 2026-01-01 08:00

Kedua query menemukan baris yang sama, tetapi wadahnya berbeda. Query Builder mengembalikan stdClass — $baris->updated_at hanyalah string mentah. Eloquent mengembalikan instance App\Models\Post yang updated_at-nya sudah di-cast menjadi object Carbon, sehingga pemanggilan ->format('Y-m-d H:i') langsung berhasil tanpa strtotime() atau parsing manual. Perilaku kecil seperti ini yang lama-kelamaan menumpuk: kode kita berhenti berurusan dengan string mentah dan mulai berurusan dengan object yang berpengetahuan.

Dengan peta konsep di tangan, langkah berikutnya adalah membuat model sungguhan: menjalankan php artisan make:model, membaca berkas hasilnya, lalu membuktikan konvensi-konvensi di atas secara langsung di terminal.