Belajar CodeIgniter - Model & Database
Episode 6 of 27

Belajar CodeIgniter - Model & Database

Menghubungkan aplikasi ke database lewat konfigurasi Database, mengenal Query Builder untuk kueri fleksibel, lalu membangun class Model dengan CRUD, timestamps otomatis, dan validation bawaan untuk table posts.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 5 kita membangun sistem templating yang rapi, sekarang saatnya masuk ke sisi "M" dari MVC: Model dan Database. Di sinilah data benar-benar hidup — disimpan, diambil, diubah, dan dihapus dari database relasional.

Mengapa ini penting? Karena hampir semua aplikasi nyata adalah aplikasi CRUD (Create, Read, Update, Delete) di atas data. CodeIgniter 4 memberi dua lapisan akses data: Query Builder untuk kueri fleksibel, dan class Model yang membungkus CRUD dengan validation dan events. Di episode ini kalian akan menguasai keduanya.

Konfigurasi Database

Koneksi database diatur di app/Config/Database.php dan bisa dioverride lewat .env:

.env - koneksi MySQL
database.default.hostname = localhost
database.default.database = ci_blog
database.default.username = root
database.default.password = rahasia
database.default.DBDriver = MySQLi
database.default.port    = 3306

DBDriver menentukan driver: MySQLi untuk MySQL/MariaDB, Postgre untuk PostgreSQL, SQLite3 untuk SQLite. Buat database-nya:

Buat database di MySQL
mysql -u root -p -e "CREATE DATABASE ci_blog CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

Warning

Jangan pernah menaruh kredensial database langsung di Database.php. Selalu override lewat .env — file ini tidak ter-commit ke git, sehingga password tidak bocor dan tiap mesin punya kredensial sendiri.

Query Builder

Query Builder adalah cara berinteraksi dengan database tanpa menulis SQL mentah. Ambil koneksi lalu mulai membangun kueri:

Query Builder dasar
$db = \Config\Database::connect();
 
$builder = $db->table('posts');
$builder->select('id, title, created_at');
$builder->where('status', 'published');
$builder->orderBy('created_at', 'DESC');
$builder->limit(10);
 
$posts = $builder->get()->getResultArray();

getResultArray() mengembalikan array asosiatif; getResult() mengembalikan objek. Query Builder selalu meng-escape nilai yang dimasukkan lewat where(), sehingga kalian terlindungi dari SQL injection — dibahas detail di episode 18.

Operasi CRUD dengan Query Builder

CRUD dengan Query Builder
// CREATE
$db->table('posts')->insert([
    'title'   => 'Post baru',
    'slug'    => 'post-baru',
    'status'  => 'draft',
]);
 
// READ
$post = $db->table('posts')->where('id', 1)->get()->getRowArray();
 
// UPDATE
$db->table('posts')->where('id', 1)->update(['status' => 'published']);
 
// DELETE
$db->table('posts')->where('id', 1)->delete();

Perhatikan bahwa tiap operasi dimulai dari $db->table('posts') — ini membuat "instruksi" yang baru dieksekusi saat get(), insert(), update(), atau delete() dipanggil. Banyak error pemula muncul karena lupa memanggil method eksekusi.

Class Model

Untuk operasi berulang pada satu tabel, CodeIgniter menyediakan class CodeIgniter\Model. Buat model posts:

app/Models/PostModel.php
<?php
 
namespace App\Models;
 
use CodeIgniter\Model;
 
class PostModel extends Model
{
    protected $table         = 'posts';
    protected $primaryKey    = 'id';
    protected $useTimestamps = true;
    protected $createdField  = 'created_at';
    protected $updatedField  = 'updated_at';
    protected $allowedFields = ['title', 'slug', 'body', 'status'];
    protected $returnType    = 'array';
}

Property kunci:

PropertyFungsi
$tableNama tabel yang dibungkus model
$primaryKeyPrimary key tabel
$allowedFieldsWhitelist kolom yang boleh di-insert/update — di luar ini diabaikan
$useTimestampsIsi created_at/updated_at otomatis
$returnTypearray atau object hasil kueri

CRUD dengan Model

Menggunakan PostModel
$postModel = new \App\Models\PostModel();
 
// CREATE
$id = $postModel->insert([
    'title'  => 'Judul pertama',
    'slug'   => 'judul-pertama',
    'body'   => 'Isi post',
    'status' => 'draft',
]);
 
// READ - semua dengan filter
$posts = $postModel->where('status', 'published')
                   ->orderBy('created_at', 'DESC')
                   ->findAll();
 
// READ - satu record
$post = $postModel->find($id);
 
// UPDATE
$postModel->update($id, ['status' => 'published']);
 
// DELETE
$postModel->delete($id);

Model juga menyediakan findAll(), first(), where() chaining, pagination (paginate(10)), dan masih banyak lagi. Karena ini adalah class, logika akses data bisa di-extend: validasi, events, relasi — kita akan kembangkan di episode 21.

Tip

Jika insert() atau update() gagal tanpa error yang jelas, kemungkinan besar kolom yang dikirim tidak ada di $allowedFields. Model menolak menulis kolom di luar whitelist — ini fitur keamanan yang membingungkan kalau tidak dipahami.

Validation di Model

Model bawaan bisa menvalidasi data sebelum insert/update:

Validation rules di model
protected $validationRules = [
    'title'  => 'required|max_length[255]',
    'slug'   => 'required|alpha_dash|is_unique[posts.slug]',
    'status' => 'required|in_list[draft,published]',
];

Saat insert() dipanggil, data divalidasi otomatis. Jika gagal, $model->errors() berisi pesan error:

Menangkap error validation
if (! $postModel->save($data)) {
    $errors = $postModel->errors();
    return redirect()->back()->withInput()->with('errors', $errors);
}

save() menangani insert atau update secara cerdas — jika ada $data['id'] yang cocok dengan primary key, ia update; jika tidak, ia insert. Validasi dan form handling penuh akan kita dalami di episode 8.

Praktik: CRUD Posts

Sekarang gabungkan semuanya dalam controller:

app/Controllers/Posts.php
<?php
 
namespace App\Controllers;
 
use App\Models\PostModel;
 
class Posts extends BaseController
{
    public function index(): string
    {
        $postModel = new PostModel();
        $data = [
            'title' => 'Daftar Post',
            'posts' => $postModel->where('status', 'published')
                                ->orderBy('created_at', 'DESC')
                                ->findAll(),
        ];
 
        return view('posts/index', $data);
    }
 
    public function show(int $id): string
    {
        $post = (new PostModel())->find($id);
 
        if ($post === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }
 
        return view('posts/show', ['post' => $post]);
    }
}

PageNotFoundException mengubah akses ke post yang tidak ada menjadi halaman 404 — bukan error kosong. Ini contoh kecil dari error handling yang benar.

Ringkasan Model & Database

  • Konfigurasi DB di Database.php / .env; DBDriver memilih MySQL, PostgreSQL, atau SQLite.
  • Query Builder memberikan kueri fleksibel dengan escaping otomatis.
  • class Model membungkus CRUD: $table, $allowedFields, timestamps, return type.
  • Validation rules di model menolak data tidak valid sebelum menyentuh database.
  • PageNotFoundException mengubah data tidak ditemukan menjadi 404 yang benar.

Penutup

Inti yang harus dibawa pulang:

  • Kredensial database di .env, bukan di config file yang ter-commit.
  • Query Builder meng-escape nilai otomatis — hindari SQL mentah.
  • Model menolak kolom di luar $allowedFields — isi whitelist dengan benar.
  • Gunakan save() untuk insert/update cerdas dan tangkap errors() saat validasi gagal.

Di episode 7 selanjutnya kita akan membahas migrations dan seeding — mengelola skema database sebagai kode dengan php spark make:migration, php spark migrate, serta mengisi data awal dengan seeder. Ini praktik yang mengubah cara kalian berkolaborasi dengan tim, karena skema kini tersimpan di git!

Belajar CodeIgniter - Model & Database | Belajar CodeIgniter