CodeIgniter4: Database, Migration, Seeders, MVC, dan Menampilkan Data

11 minute read

Published:

Pada artikel ini kita mempraktikkan pembuatan proyek blog pribadi (MyBlog) hingga menampilkan data secara dinamis. Diawali dengan mengatur env, membuat database, lalu pembuatan migration untuk pengelolaan database, penggunaan seeders untuk memasukkan data awal. Implementasi MVC dan pengaturan view layout untuk menyajikan tampilan web yang terstruktur.

1. Membuat Project Baru

Siapkan direktori untuk menyimpan project, buka terminal, lalu lakukan instalasi menggunakan Composer.

composer create-project codeigniter4/appstarter project3

Setelah selesai instalasi, buka project3 pada VS Code. Lakukan konfigurasi environment variables. Copy file env dan rename menjadi .env:

cp -r env .env

Buka file .env dan lakukan perubahan berikut. Pada bagian ENVIRONMENT, ubah menjadi:

#---------------------------------------------------------------
# ENVIRONMENT
#---------------------------------------------------------------
CI_ENVIRONMENT = development

Pada bagian DATABASE, atur koneksi MySQL:

#---------------------------------------------------------------
# DATABASE
#---------------------------------------------------------------

database.default.hostname = localhost
database.default.database = ci4_blog
database.default.username = root
database.default.password =
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306

Jika Anda menggunakan password untuk user root, tambahkan pada database.default.password. Simpan perubahan lalu jalankan aplikasi:

php spark serve

Buka alamat http://localhost:8080 pada web browser.

2. Menyiapkan Assets Bootstrap 5

View yang akan kita buat menggunakan Bootstrap 5 untuk styling. Download file Compiled CSS and JS dari laman resmi Bootstrap 5.3 (versi terbaru saat ini v5.3.8).

  1. Klik tombol Download pada bagian “Compiled CSS and JS”.
  2. Ekstrak file bootstrap-5.3.8-dist.zip yang telah diunduh.
  3. Di dalam hasil ekstrak terdapat dua folder: css/ dan js/.
  4. Copy kedua folder tersebut ke dalam direktori public/ pada project CI4.

Struktur direktori public/ setelah ditambahkan:

public/
  css/
    bootstrap.min.css
    bootstrap.min.css.map
    ...
  js/
    bootstrap.min.js
    bootstrap.bundle.min.js
    bootstrap.min.js.map
    ...
  index.php
  ...

Selain Bootstrap, project ini juga menggunakan jQuery. Download jQuery dari jquery.com lalu letakkan file jquery.min.js ke dalam folder public/js/.

Sekarang aset CSS dan JS sudah bisa dipanggil di view menggunakan base_url():

<!-- CSS -->
<link rel="stylesheet" href="<?= base_url('css/bootstrap.min.css') ?>" />

<!-- JS -->
<script src="<?= base_url('js/jquery.min.js') ?>"></script>
<script src="<?= base_url('js/bootstrap.min.js') ?>"></script>

3. Membuat Database

Setelah konfigurasi database, buat database baru bernama ci4_blog. Bisa melalui command line atau phpMyAdmin.

Menggunakan Spark:

php spark db:create ci4_blog

Jika berhasil akan tampil output:

Database "ci4_blog" successfully created.

Selain itu, bisa juga membuat database secara manual melalui localhost/phpMyAdmin.

4. Membuat Migration

Skema tabel posts yang akan dibuat:

Field NameTypeKey
idINT(5) autoincrementPrimary
titleVARCHAR(255) 
authorVARCHAR(100) 
contentTEXT 
statusENUM(‘published’,’draft’) 
created_atDATETIME 
slugVARCHAR(100) 

Buat file migration untuk tabel posts dengan perintah berikut:

php spark make:migration create_posts_table

Output jika berhasil:

File created: APPPATH/Database/Migrations/2026-03-25-021344_CreatePostsTable.php

Buka file baru pada folder app/Database/Migrations dan ubah menjadi seperti berikut:

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class CreatePostsTable extends Migration
{
    public function up()
    {
        // Membuat kolom/field untuk tabel posts
        $this->forge->addField([
            'id'          => [
                'type'           => 'INT',
                'constraint'     => 5,
                'unsigned'       => true,
                'auto_increment' => true
            ],
            'title'       => [
                'type'           => 'VARCHAR',
                'constraint'     => '255'
            ],
            'author'      => [
                'type'           => 'VARCHAR',
                'constraint'     => 100,
                'default'        => 'John Doe',
            ],
            'content' => [
                'type'           => 'TEXT',
                'null'           => true,
            ],
            'status'      => [
                'type'           => 'ENUM',
                'constraint'     => ['published', 'draft'],
                'default'        => 'draft',
            ],
            'created_at DATETIME DEFAULT CURRENT_TIMESTAMP'
        ]);

        // Membuat primary key
        $this->forge->addKey('id', TRUE);

        // Membuat tabel posts
        $this->forge->createTable('posts', TRUE);
    }

    public function down()
    {
        // menghapus tabel posts
        $this->forge->dropTable('posts');
    }
}

Pada method up() kita menambahkan kode untuk membuat tabel posts dengan field-field sesuai struktur tabel. Pada method down() kita menambahkan kode untuk menghapus tabel. Jalankan migration:

php spark migrate

Output jika berhasil:

Running all new migrations...
    Running: (App) 2026-03-25-021344_App\Database\Migrations\CreatePostsTable
Migrations complete.

Sekarang cek database melalui phpMyAdmin. Akan terdapat dua tabel: migrations dan posts. Tabel migrations otomatis dibuat untuk menyimpan versi migrasi yang sudah dilakukan.

Rollback dan Alter Migration

Jika terjadi perubahan skema atau ingin menambahkan field baru, kita bisa melakukan rollback lalu mengubah file migrasi dan melakukan migrasi kembali, atau dipersingkat dengan:

php spark migrate:refresh

Cara lain, misalnya ingin menambahkan kolom slug pada tabel posts, bisa membuat file migrasi baru:

php spark make:migration alter_posts_table

Buka file baru _AlterPostsTable.php pada folder app/Database/Migrations dan ubah menjadi:

class AlterPostsTable extends Migration
{
    public function up()
    {
        $this->forge->addColumn('posts', [
            'slug VARCHAR(100) UNIQUE'
        ]);
    }

    public function down()
    {
        // ...
    }
}

Kemudian jalankan migrasi:

php spark migrate

Cek kembali tabel posts dari phpMyAdmin, akan ada kolom baru bernama slug. Tabel migrations juga akan memiliki data baru dengan nomor batch 2.

5. Membuat Seeders

Seed data adalah data awal untuk mengisi tabel. Berguna untuk keperluan testing dan menyiapkan data yang diperlukan di awal. Buat file seeder dengan perintah:

php spark make:seeder PostSeeder

Output jika berhasil:

File created: APPPATH/Database/Seeds/PostSeeder.php

File baru akan ada di folder app/Database/Seeds dengan nama PostSeeder.php. Ubah isi function run() menjadi:

class PostSeeder extends Seeder
{
    public function run()
    {
        // membuat data
        $posts_data = [
            [
                'title' => 'Mulai Nyobain Codeigniter',
                'slug'  => 'codeigniter-starter',
                'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore aliqua.'
            ],
            [
                'title' => 'Cara Mudah Buat Hello World',
                'slug' => 'hello-world',
                'content' => 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam.'
            ],
            [
                'title' => 'Meetup Komunitas Kelas Koding',
                'slug' => 'meetup-comunity',
                'content' => 'At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis voluptatum deleniti atque corrupti quos.'
            ]
        ];

        foreach($posts_data as $data){
            // insert semua data ke tabel
            $this->db->table('posts')->insert($data);
        }
    }
}

Pada method run() kita membuat array berisi data yang akan disimpan dalam tabel posts, lalu menggunakan perulangan foreach untuk menyimpan semuanya. Jalankan seeder:

php spark db:seed PostSeeder

Output jika berhasil:

Seeded: App\Database\Seeds\PostSeeder

Tabel posts sekarang memiliki data awal.

6. Membuat View Layout

Kita akan membuat view untuk web MyBlog. Buat file home.php untuk menggantikan welcome_message.php dalam folder app/Views. Tambahkan juga file about.php, contact.php, dan faqs.php.

Konfigurasi Route dan Controller

Buka app/Config/Routes.php dan tambahkan route:

$routes->get('/', 'Home::index');
$routes->get('/about', 'Page::about');
$routes->get('/contact', 'Page::contact');
$routes->get('/faqs', 'Page::faqs');

Ubah app/Controllers/Home.php:

class Home extends BaseController
{
    public function index(): string
    {
        return view('home');
    }
}

Buat controller baru app/Controllers/Page.php:

class Page extends BaseController
{
    public function about()
    {
        echo view("about");
    }

    public function contact()
    {
        echo view("contact");
    }

    public function faqs()
    {
        echo view("Faqs");
    }
}

View home.php

Buat file app/Views/home.php dengan struktur HTML Bootstrap:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyBlog</title>

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="<?= base_url('css/bootstrap.min.css') ?>" />
</head>

<body>
    <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
        <div class="container">
            <a class="navbar-brand" href="<?= base_url() ?>">MyBlog</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
                data-bs-target="#navbarNav" aria-controls="navbarNav"
                aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav">
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page"
                           href="<?= base_url() ?>">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="<?= base_url('about') ?>">About</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="<?= base_url('post') ?>">Blog</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="<?= base_url('contact') ?>">Contact</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="<?= base_url('faqs') ?>">FAQ</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>

    <div class="p-5 mb-4 bg-light rounded-3">
      <div class="container py-5">
        <h1 class="display-5 fw-bold">Selamat Datang</h1>
      </div>
    </div>

    <div class="container">
        <div class="row">
            <div class="col-md-12 my-2 card">
                <div class="card-body">
                    <h5 class="h5">Mulai ngoding PHP nich</h5>
                    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
                </div>
            </div>
            <div class="col-md-12 my-2 card">
                <div class="card-body">
                    <h5 class="h5">Jadi paham CSS dan JS</h5>
                    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
                </div>
            </div>
            <div class="col-md-12 my-2 card">
                <div class="card-body">
                    <h5 class="h5">Codeigniter asyik juga kok</h5>
                    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
                </div>
            </div>
        </div>
    </div>

    <div class="container py-4">
        <footer class="pt-3 mt-4 text-muted border-top">
            <div class="container">
                &copy; <?= Date('Y') ?>
            </div>
        </footer>
    </div>

    <!-- Jquery dan Bootstrap JS -->
    <script src="<?= base_url('js/jquery.min.js') ?>"></script>
    <script src="<?= base_url('js/bootstrap.min.js') ?>"></script>
</body>

</html>

View about.php, contact.php, faqs.php

Buat halaman statis lainnya dengan struktur serupa, hanya berbeda pada bagian konten. Misalnya about.php berisi tentang profil dan data diri; contact.php berisi “Alamat”, “Email”, “No.HP”; dan faqs.php berisi daftar pertanyaan dan jawaban seputar layanan.

7. Menampilkan Data

Sekarang kita membuat halaman untuk menampilkan data postingan dari database. Sebelum mulai, perhatikan struktur direktori app/Views yang akan digunakan pada project MyBlog ini:

app/Views/
  home.php            ← Halaman utama (beranda)
  about.php           ← Halaman tentang / profil
  contact.php         ← Halaman kontak
  faqs.php            ← Halaman FAQ
  post.php            ← Daftar semua postingan
  post_detail.php     ← Detail satu postingan

Setiap file view memiliki peran masing-masing:

  • home.php — menampilkan halaman beranda dengan konten statis.
  • about.php, contact.php, faqs.php — halaman statis informasi.
  • post.php — menampilkan daftar postingan dari database (data dinamis).
  • post_detail.php — menampilkan isi lengkap satu postingan berdasarkan slug.

File-file view ini dipanggil oleh controller yang bersesuaian melalui fungsi view() atau echo view(). Hubungan antara Route, Controller, dan View dapat digambarkan sebagai berikut:

RouteControllerView
/Home::indexhome.php
/aboutPage::aboutabout.php
/contactPage::contactcontact.php
/faqsPage::faqsfaqs.php
/postPost::indexpost.php
/post/(:any)Post::viewPost/$1post_detail.php

Membuat Controller Post

Buka terminal dan jalankan:

php spark make:controller Post

Output jika berhasil:

File created: APPPATH/Controllers/Post.php

Buka file app/Controllers/Post.php dan isi dengan:

use App\Models\PostModel;
use CodeIgniter\Exceptions\PageNotFoundException;

class Post extends BaseController
{
    public function index()
    {
        // buat object model $post
        $post = new PostModel();
        /*
         siapkan data untuk dikirim ke view dengan nama $posts
         dan isi datanya dengan post yang sudah terbit
        */
        $data['posts'] = $post->where('status', 'published')->findAll();

        // kirim data ke view
        echo view('post', $data);
    }

    public function viewPost($slug)
    {
        $post = new PostModel();
        $data['post'] = $post->where([
            'slug' => $slug,
            'status' => 'published'
        ])->first();

        // tampilkan 404 error jika data tidak ditemukan
        if (!$data['post']) {
            throw PageNotFoundException::forPageNotFound();
        }

        echo view('post_detail', $data);
    }
}

Pada kode di atas, method findAll() digunakan untuk mengambil semua data, dan first() untuk mengambil satu data saja. Method where() menentukan kondisi data yang diambil — dalam kasus ini, post yang statusnya published dan berdasarkan slug.

Membuat Model Post

Buat file Model baru:

php spark make:model PostModel

Output jika berhasil:

File created: APPPATH/Models/PostModel.php

Buka app/Models/PostModel.php dan isi dengan:

class PostModel extends Model
{
    protected $table            = 'posts';
    protected $primaryKey       = 'id';

    protected $useAutoIncrement = true;
    protected $allowedFields    = ['title', 'content', 'status', 'author', 'slug'];
}

Menambahkan Route

Buka app/Config/Routes.php dan tambahkan route baru:

$routes->get('/post', 'Post::index');
$routes->get('/post/(:any)', 'Post::viewPost/$1');

Membuat View Post

Buat file app/Views/post.php. Pada bagian navbar tambahkan link Blog, dan pada bagian konten isi dengan:

<div class="container">
    <div class="row">
        <?php foreach ($posts as $post) : ?>
            <div class="col-md-12 my-2 card">
                <div class="card-body">
                    <h5 class="h5"><a href="/post/<?= $post['slug'] ?>"><?= $post['title'] ?></a></h5>
                    <p><?= substr($post['content'], 0, 120) ?></p>
                </div>
            </div>
        <?php endforeach ?>
    </div>
</div>

Membuat View Post Detail

Buat file app/Views/post_detail.php dengan konten:

<div class="container">
    <div class="row">
        <div class="col-md-12 my-2 card">
            <div class="card-body">
                <h5 class="h5"><?= $post['title'] ?></h5>
                <span><?= $post['author'] ?> | <?= $post['created_at'] ?></span>
                <p><?= $post['content'] ?></p>
            </div>
        </div>
    </div>
</div>

MyBlog CI4

Jalankan aplikasi dan buka localhost:8080/post untuk melihat daftar postingan, atau localhost:8080/post/{slug} untuk melihat detail postingan.

8. Ringkasan

Praktik ini mencakup langkah-langkah penting dalam pengembangan aplikasi web menggunakan CodeIgniter 4:

  • Migration digunakan untuk membuat dan mengelola struktur tabel dalam database. Mendukung rollback dan alter migration untuk perubahan skema.
  • Seeders digunakan untuk mengisi data awal yang diperlukan untuk testing maupun kebutuhan awal aplikasi.
  • Controller mengambil data dari database menggunakan method findAll() dan first() pada Model.
  • Model mendefinisikan tabel, primary key, dan field yang diperbolehkan untuk operasi database.
  • View menampilkan data dinamis dari database, baik berupa daftar postingan maupun detail per postingan.
  • Route mengatur mapping URL ke method yang sesuai pada Controller.

Dengan pola MVC ini, aplikasi web menjadi terstruktur, mudah dirawat, dan dapat menampilkan data secara dinamis baik untuk konten statis maupun dinamis seperti postingan blog.