Model Eloquent adalah class PHP biasa yang disimpan di app/Models/, dan Laravel menyediakan generator artisan agar kita tidak perlu mengetik kerangkanya dari nol. Berkat konvensi yang dibahas di chapter Konsep Eloquent , satu model bisa langsung bekerja tanpa satu baris konfigurasi pun. Pada chapter ini kita membuat model Post untuk tabel posts, menjalankannya berdampingan dengan migration, lalu membuktikan konvensi bawaannya di terminal. Setelah itu kita belajar menimpa konvensi itu lewat $table, $primaryKey, dan $timestamps untuk tabel yang strukturnya memang berbeda.

Membuat Model dengan make:model #

Perintah berikut membuat model Post:

bash
php artisan make:model Post

Output yang Dihasilkan:

text
   INFO  Model [app/Models/Post.php] created successfully.

Berkas app/Models/Post.php hasilnya sangat pendek:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    //
}

Isi class memang kosong, tetapi model ini langsung berfungsi: Eloquent menebak tabel posts dari nama class Post, memakai primary key id, dan mengisi created_at serta updated_at secara otomatis. Seluruh perilaku itu tinggal di parent class Model yang diwarisi Post. Karena tabel posts sudah kita bangun di chapter Column Types , model ini bisa langsung dipakai untuk membaca dan menulis data tabel tersebut.

Model dan Migration Sekaligus #

Model dan tabelnya biasanya lahir bersamaan. Flag -m memberi tahu artisan untuk membuat file migration sekaligus:

bash
php artisan make:model Post -m

Output yang Dihasilkan:

text
   INFO  Model [app/Models/Post.php] created successfully.

   INFO  Migration [database/migrations/2026_10_13_172825_create_posts_table.php] created successfully.

Artisan menghasilkan dua berkas: model di app/Models/Post.php dan migration kosong bernama create_posts_table yang tinggal diisi definisi kolom seperti yang sudah kita latih di section Database dan Migrations . Nama file migration di output Anda pasti berbeda karena berisi timestamp saat perintah dijalankan — itu wajar dan hanya memengaruhi urutan eksekusi.

Menimpa Nama Tabel dengan $table #

Konvensi nama tabel bekerja pada mayoritas kasus, tetapi kadang kita harus memakai nama tabel yang sudah ada atau tidak mengikuti pola jamak. Property $table menimpa tebakan Eloquent secara eksplisit:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Tulisan extends Model
{
    protected $table = 'posts';
}

Class Tulisan kini menunjuk ke tabel posts yang sama dengan model Post. Kita bisa memverifikasinya lewat method getTable():

php
$tulisan = new Tulisan;

echo 'tabel: ', $tulisan->getTable(), "\n";
echo 'jumlah baris: ', Tulisan::count(), "\n";

Output yang Dihasilkan:

text
tabel: posts
jumlah baris: 5

getTable() mengembalikan nama tabel aktif setelah konvensi dan property digabungkan, dan Tulisan::count() benar-benar membaca lima baris dari tabel posts. Dua model pada satu tabel memang jarang dibutuhkan, tetapi kasus nyatanya ada: model lama untuk tabel legacy, atau nama domain berbeda untuk data yang sama.

Primary Key dan Timestamps yang Berbeda #

Tabel tidak selalu memakai id bertambah otomatis dan tidak selalu punya kolom waktu. Sebagai contoh, mari kita buat tabel kategoris yang sederhana:

php
Schema::create('kategoris', function (Blueprint $table) {
    $table->string('kode', 10)->primary();
    $table->string('nama', 100);
});

Primary key tabel ini adalah kode bertipe string, dan tidak ada kolom created_at maupun updated_at. Model untuk tabel tersebut perlu menimpa beberapa konvensi sekaligus:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Kategori extends Model
{
    protected $primaryKey = 'kode';

    protected $keyType = 'string';

    public $incrementing = false;

    public $timestamps = false;
}

Empat property di atas mengubah perilaku inti model: $primaryKey mengarahkan find() dan getKey() ke kolom kode, $keyType dan $incrementing menyatakan bahwa kunci berupa string yang tidak diisi database, sedangkan $timestamps = false mematikan pengisian kolom waktu. Mari kita uji semuanya:

php
$kategori = new Kategori;
$kategori->kode = 'seo';
$kategori->nama = 'Search Engine Optimization';
$kategori->save();

echo 'tabel: ', $kategori->getTable(),
    ' | primary key: ', $kategori->getKeyName(),
    ' | getKey(): ', $kategori->getKey(), "\n";
echo 'cari berdasarkan kode: ', Kategori::find('seo')->nama, "\n";

Output yang Dihasilkan:

text
tabel: kategoris | primary key: kode | getKey(): seo
cari berdasarkan kode: Search Engine Optimization

save() menyimpan baris baru, lalu getKey() mengembalikan nilai kolom kunci — string seo, bukan angka. Pencarian Kategori::find('seo') juga mengarah ke kolom kode tanpa konfigurasi tambahan.

Ringkasan Property Konfigurasi #

PropertyTugasNilai bawaan
$tablemenimpa nama tabel hasil tebakantebakan jamak dari nama class
$primaryKeymenimpa nama kolom kunciid
$keyTypetipe data kunciint
$incrementingapakah kunci bertambah otomatistrue
$timestampsmengisi created_at/updated_at otomatistrue
$connectionmemakai koneksi database tertentukoneksi default

Satu yang belum kita bahas adalah $connection: property ini berguna saat satu aplikasi membaca beberapa database sekaligus, dan cara kerjanya sudah kita uji di chapter Database Connections . Untuk model yang menimpa konvensi, daftar lengkapnya juga tersedia di dokumentasi Eloquent .

Model sudah berdiri dan tebakan tabelnya sudah terbukti di terminal. Namun begitu kita mencoba mengisi banyak kolom sekaligus lewat create(), Eloquent justru menolak — penolakan itu bernama mass assignment, dan itulah topik chapter berikutnya.