Query builder adalah cara Eloquent menyaring, mengurutkan, dan menghitung baris tanpa menulis SQL. Kamu merangkai syaratnya satu per satu (where, orderBy), lalu menutupnya dengan satu perintah yang benar-benar mengirim query ke database (get, first, atau count). Bayangin formulir pencarian di katalog perpustakaan: centang "masih ada stoknya", urutkan "stok terbanyak dulu". Selama kamu mengisinya, belum ada yang dicari. Pencarian baru jalan saat kamu menekan tombol Cari, dan kamu bisa minta hasilnya berupa daftar buku, satu buku teratas, atau jumlahnya saja.
🧪 Tebakan cepat: perpustakaan ini gak punya buku karya Tere Liye.
Book::where('author', 'Tere Liye')->get()menghasilkan apa:null, Collection kosong, atau error? Tebak dulu, jawabannya ada di bagian "Akhirnya: get(), first(), atau count()".
Data contoh
Tabel books sekarang berisi empat buku: tiga dari awal, ditambah Ronggeng Dukuh Paruk yang dibuat dengan create() di pelajaran Eloquent Dasar. Data yang sama ada di Lab.
| id | title | author | stock |
|---|---|---|---|
| 1 | Laskar Pelangi | Andrea Hirata | 3 |
| 2 | Bumi Manusia | Pramoedya Ananta Toer | 0 |
| 3 | Cantik Itu Luka | Eka Kurniawan | 2 |
| 4 | Ronggeng Dukuh Paruk | Ahmad Tohari | 1 |
where: menyaring baris
$tersedia = Book::where('stock', '>', 0)->get();
// select * from "books" where "stock" > 0
// Laskar Pelangi, Cantik Itu Luka, Ronggeng Dukuh Paruk
$habis = Book::where('stock', 0)->get();
// select * from "books" where "stock" = 0
// Bumi Manusia
| Buku | stock | stock > 0? |
|---|---|---|
| Laskar Pelangi | 3 | ya |
| Bumi Manusia | 0 | tidak, tersaring |
| Cantik Itu Luka | 2 | ya |
| Ronggeng Dukuh Paruk | 1 | ya |
where('stock', '>', 0)punya tiga bagian: kolom, operator, nilai. Operator lain:=,!=,<,>=,<=, danlikeuntuk pola teks, misalnyawhere('title', 'like', 'B%').where('stock', 0)dengan dua bagian artinya sama dengan:=ditulis otomatis.- Dua
whereberturut-turut digabung dengan and:Book::where('stock', '>', 0)->where('stock', '<', 3)->get()cuma mengembalikan Cantik Itu Luka dan Ronggeng Dukuh Paruk. Mau salah satu syarat saja? PakaiorWhere().
orderBy dan limit: mengurutkan dan membatasi
$terbanyak = Book::where('stock', '>', 0)
->orderBy('stock', 'desc')
->get();
// select * from "books" where "stock" > 0 order by "stock" desc
// Laskar Pelangi (3), Cantik Itu Luka (2), Ronggeng Dukuh Paruk (1)
orderBy('stock', 'desc')mengurutkan dari angka terbesar, jadi stok terbanyak di depan.orderBy('stock', 'asc')membalik urutannya: terkecil dulu.'asc'juga arah bawaannya, jadiorderBy('stock')sama saja. Untuk teks,orderBy('title')mengurutkan A sampai Z.limit(2)atautake(2)menambahlimit 2: cuma dua baris pertama yang diambil.- Urutan rangkaiannya bebas, tapi kebiasaannya
wheredulu, laluorderBy, lalu penutupnya.
Akhirnya: get(), first(), atau count()
Book::where(...) sendirian belum mengirim apa pun. Dia cuma menyimpan rangkaian syaratnya (sebuah Builder). Query baru dikirim saat rangkaiannya ditutup:
$favorit = Book::orderBy('stock', 'desc')->first();
// select * from "books" order by "stock" desc limit 1
echo $favorit->title; // Laskar Pelangi
$jumlahTersedia = Book::where('stock', '>', 0)->count();
// select count(*) as "aggregate" from "books" where "stock" > 0
echo $jumlahTersedia; // 3
$tereLiye = Book::where('author', 'Tere Liye')->get();
echo count($tereLiye); // 0
| Penutup | Tambahan di SQL | Hasilnya | Kalau gak ada yang cocok |
|---|---|---|---|
get() |
(gak ada) | Collection berisi object Book |
Collection kosong |
first() |
limit 1 |
satu object Book |
null |
count() |
select count(*) as "aggregate" |
angka | 0 |
Jadi buku Tere Liye yang gak ada menghasilkan Collection kosong, bukan null dan bukan error. Itu jawaban tebakannya. foreach di atasnya gak jalan sekali pun, dan count()-nya 0. Yang bisa null cuma first() (dan find()), jadi cek dulu sebelum membaca $buku->title.
count()menyuruh database yang menghitung, dan cuma satu angka yang kembali ke PHP.count(Book::all())juga benar, tapi mengambil semua baris dulu.- Hitungan lain bekerja sama:
Book::sum('stock')mengirimselect sum("stock") as "aggregate" from "books"dan menjawab 6. Ada jugamin(),max(), danavg(). Book::all()sama denganget()tanpa syarat apa pun.
📌 Mengintip SQL-nya
Ganti penutupnya dengan toRawSql() untuk melihat SQL tanpa menjalankannya:
echo Book::where('stock', '>', 0)->orderBy('title')->toRawSql();
// select * from "books" where "stock" > 0 order by "title" asc
toSql() menampilkan versi dengan tanda ? di tempat nilainya. Nilainya dikirim terpisah (binding), dan itulah yang membuat query builder aman dari SQL injection.
⚠️ Jebakan yang sering ketemu
- Lupa penutupnya.
$buku = Book::where('stock', '>', 0);masih Builder, bukan daftar buku.count($buku)berhenti dengancount(): Argument #1 ($value) must be of type Countable|array, Illuminate\Database\Eloquent\Builder given. Tambahkan->get(). - Arah urutan terbalik. Termurah atau tersedikit dulu itu
'asc', termahal atau terbanyak dulu itu'desc'. - Memakai
first()laluforeach.first()mengembalikan satu object, bukan Collection. Untuk banyak baris, pakaiget(). - Di latihan, label harus persis. Output-nya dicari
Produk mahal:danTotal produk:, lengkap dengan titik duanya.
TL;DR: Query builder merangkai syarat lalu menutupnya. where('kolom', 'operator', nilai) menyaring (dua where = and), orderBy('kolom', 'asc') mengurutkan dari terkecil ('desc' dari terbesar), limit(n) membatasi. Penutupnya yang mengirim query: get() mengembalikan Collection (kosong kalau gak ada yang cocok), first() menambah limit 1 dan mengembalikan satu object atau null, count() menyuruh database menghitung dan mengembalikan satu angka. Tanpa penutup, yang kamu pegang cuma Builder. toRawSql() menunjukkan SQL-nya tanpa menjalankannya.