author Ahmad Muhardian

Tutorial Codeigniter 4: Cara Membuat CRUD dan Validasi Data


Codeigniter4 Crud

Pada tutorial sebelumnya, kita sudah membuat tabel dengan CI Migration.

Jika kamu belum membacanya, silakan baca terlebih dahulu:

Nah, sekarang kita akan belajar cara membuat CRUD di Codeigniter.

CRUD merupakan singkatan dari Create, Read, Update, dan Delete. Ini merupakan hal dasar yang harus kamu ketahui dalam operasi database.

Langkah-langkah membuat CRUD di Codeigniter:

  1. Buat tabel di database (sudah dilakukan di tutorial sebelumnya);
  2. Buat class Model;
  3. Buat class Controller;
  4. Terakhir buat View.

Pada tutorial ini, kita akan banyak bekerja dalam membuat Model, Controller, dan View.

Pastikan kamu mengikuti dengan teliti..

Hingga pada akhir tutorial ini, kamu akan bisa menguasai cara membuat CRUD di Codeigniter 4, dilengkapi dengan validasi data.

Sudah siap?

Mari kita mulai..

Membuat NewsModel

Model merupakan class yang berfungsi untuk operasi database seperti insert data, read data, update, dan delete.

Di dalam class model, terdapat fungsi-fungsi yang siap pakai untuk mengakses database.

Fungsi-fungsi ini disebut query builder, yang sebenarnya menjalankan sebuah query SQL.

Jadi berkat fungsi-fungsi ini, kita tidak perlu membuat query. Cukup panggil fungsinya.

Nah, untuk membuat Model di Codeigniter 4, kita harus melakukan extends atau mewariskan class Model.

Mari kita buat!

Buatlah file baru di dalam folder app/Models dengan nama NewsModel.php, lalu isi dengan kode berikut:

<?php

namespace App\Models;

use CodeIgniter\Model;

class NewsModel extends Model
{
    protected $table      = 'news';
    protected $primaryKey = 'id';

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

Penjelasan kode:

Pada class NewsModel terdapat beberapa member yang menjadi konfigurasi untuk Model:

  • $table adalah nama tabel yang akan digunakan oleh Model;
  • $primaryKey adalah nama kolom untuk primary key;
  • $useAutoIncrement untuk mengaktifkan auto increment pada primary key;
  • $allowedFields berisi daftar nama kolom yang boleh kita isi.

Selain keempat properti ini, masih ada lagi properti lainnya.

Kamu bisa melihatnya di dokumentasi model CI.

Class NewsModel nantinya akan kita gunakan pada Controller untuk mengakses database.

Oke sekarang lanjut, kita coba membaca data.

Read Data News

Pertama kita kerjakan dulu fitur untuk read news. Jadi nantinya saat user kita membuka halaman /news ia akan mendapatkan list news terbaru yang sudah terbit.

Lalu saat membuka /news/slug-news maka akan ditampilkan halaman news. Ini mirip seperti artikel pada blog.

Tambahkan route untuk membuka halaman news, buka file Config/Routers.php, kemudian tambahkan ini:

$routes->get('/news', 'News::index');
$routes->get('/news/(:any)', 'News::viewNews/$1');

Route /news/(:any) memiliki parameter berupa slug, nantinya parameter ini dapat kita akses dari controller. O ya, jangan lupa juga tambahkan /$1 agar parameter bisa terbaca di controller.

Route parameter

Langkah berikutnya, kita tambahkan route ini ke dalam menu.

<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
    <div class="container">
        <a class="navbar-brand" href="<?= base_url() ?>">Home</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-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" href="<?= base_url('news') ?>">News</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('contact') ?>">Contact</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="<?= base_url('faqs') ?>">Faqs</a>
                </li>
            </ul>
        </div>
    </div>
</nav>

Setelah itu…

Ubahlah controller News.php, menjadi seperti ini:

News.php
<?php

namespace App\Controllers;

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

class News extends BaseController
{
	public function index()
	{
    // buat object model $news
    $news = new NewsModel();

    /*
     siapkan data untuk dikirim ke view dengan nama $newses
     dan isi datanya dengan news yang sudah terbit
    */
    $data['newses'] = $news->where('status', 'published')->findAll();

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

	//------------------------------------------------------------

	public function viewNews($slug)
	{
		$news = new NewsModel();
		$data['news'] = $news->where([
			'slug' => $slug,
			'status' => 'published'
		])->first();

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

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

Pada kode di atas kita menggunakan method findAll() untuk mengambil semua data di database dan first() untuk mengambil satu data saja.

Di sana kita juga menggunakan where() untuk menentukan data mana yang akan di ambil.

Pada kasus di atas, kita mengambil data news yang statusnya sudah terbit (published) dan juga mengambil berdasarkan slug.

Terakhir..

Mari kita ubah view untuk News.

Buka file Views/news.php, lalu ubah isinya menjadi seperti ini:

Views/news.php
<?= $this->extend('layout/post_layout') ?>

<?= $this->section('content') ?>

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

    <?php endforeach ?>
</div>


<?= $this->endSection() ?>

Setelah itu, buat satu lagi view untuk menampilkan detail news. Pada folder Views buat file baru bernama news_detail.php dengan isi sebagai berikut:

Views/news_detail.php
<?= $this->extend('layout/post_layout') ?>

<?= $this->section('content') ?>
<h2 class="h2"><?= $news['title'] ?></h2>
<div class="mb-5">
    <span><?= $news['created_at'] ?></span>
</div>
<div><?= $news['content'] ?></div>

<?= $this->endSection() ?>

Oke beres..

Sekarang coba buka localhost:8080/news.

Maka hasilnya:

read news

Oke, sekarang kita sudah berhasil menampilkan data di sisi depan website.

Berikutnya, kita akan mengerjakan sisi admin.

Membuat Halaman Admin untuk News

Berbeda dengan halaman /news, halaman Admin akan kita gunakan untuk menambahkan news, mengubah, dan menghapus news.

Berikut ini langkah-langkah membuat halaman Admin untuk News:

Step 1 – Membuat Route Admin

Kali ini kita akan menggunakan route group untuk membuat group route /admin.

Silakan buka file Config/Routes.php, kemudian tambahkan kode berikut.

$routes->group('admin', function($routes){
	$routes->get('news', 'NewsAdmin::index');
	$routes->get('news/(:segment)/preview', 'NewsAdmin::preview/$1');
    $routes->add('news/new', 'NewsAdmin::create');
	$routes->add('news/(:segment)/edit', 'NewsAdmin::edit/$1');
	$routes->get('news/(:segment)/delete', 'NewsAdmin::delete/$1');
});

Coba perhatikan!

Kode di atas adalah kode untuk membuat group route.

Artinya semua route yang ada di dalam group admin, harus dibuka dengan /admin baru diikuti route-nya.

Contoh, mau buka form create.. maka harus buka alamat /admin/news/new.

Coba perhatikan juga method yang digunakan pada route.

Ada yang menggunakan get() dan ada juga add().

Apa bedanya?

Bedanya, method add() bisa dibuka dengan dua method yakni get() dan post(). Sedangkan get() hanya untuk GET saja.

Mengapa kita pakai add() pada route create dan edit?

Karena selain menampilkan form create dan edit (GET), kita juga akan mengirim data (POST).

ci4 route get vs add

Bagaimana, paham tidak?

Oke lanjut..

Pada route yang sudah dibuat, kita membutuhkan controller NewsAdmin untuk meng-handle route tersebut.

Mari kita buat!

Step 2 – Membuat NewsAdmin Controller

Buatlah file baru di dalam app/Controllers dengan nama NewsAdmin.php kemudian isi dengan kode berikut:

app/Controllers/NewsAdmin.php
<?php namespace App\Controllers;

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

class NewsAdmin extends BaseController
{
	public function index()
	{
        $news = new NewsModel();
        $data['newses'] = $news->findAll();
		echo view('admin_list_news', $data);
    }

    //--------------------------------------------------------------------------
    
    public function preview($id)
	{
		$news = new NewsModel();
		$data['news'] = $news->where('id', $id)->first();
		
		if(!$data['news']){
			throw PageNotFoundException::forPageNotFound();
		}
		echo view('news_detail', $data);
    }

    //--------------------------------------------------------------------------
    
    public function create()
    {
        // lakukan validasi
        $validation =  \Config\Services::validation();
        $validation->setRules(['title' => 'required']);
        $isDataValid = $validation->withRequest($this->request)->run();

        // jika data valid, simpan ke database
        if($isDataValid){
            $news = new NewsModel();
            $news->insert([
                "title" => $this->request->getPost('title'),
                "content" => $this->request->getPost('content'),
                "status" => $this->request->getPost('status'),
                "slug" => url_title($this->request->getPost('title'), '-', TRUE)
            ]);
            return redirect('admin/news');
        }
		
        // tampilkan form create
        echo view('admin_create_news');
    }

    //--------------------------------------------------------------------------

    public function edit($id)
    {
        // ambil artikel yang akan diedit
        $news = new NewsModel();
        $data['news'] = $news->where('id', $id)->first();
        
        // lakukan validasi data artikel
        $validation =  \Config\Services::validation();
        $validation->setRules([
            'id' => 'required',
            'title' => 'required'
        ]);
        $isDataValid = $validation->withRequest($this->request)->run();
        // jika data vlid, maka simpan ke database
        if($isDataValid){
            $news->update($id, [
                "title" => $this->request->getPost('title'),
                "content" => $this->request->getPost('content'),
                "status" => $this->request->getPost('status')
            ]);
            return redirect('admin/news');
        }

        // tampilkan form edit
        echo view('admin_edit_news', $data);
    }

    //--------------------------------------------------------------------------

	public function delete($id){
        $news = new NewsModel();
        $news->delete($id);
        return redirect('admin/news');
    }
}

Pada controller ini, kita membuat 5 method yakni:

  • index() untuk menampilkan list artikel;
  • preview($id) untuk menampilkan preview berdasarkan $id artikel;
  • create() untuk membuat artikel baru;
  • edit() untuk edit artikel;
  • dan delete($id) untuk menghapus artikel berdasarkan $id.

Sudah paham?

Jika belum..

Saya akan jelaskan satu-per-satu.

Mari kita mulai dari method index().

Method ini bertugas untuk menampilkan list news atau artikel.

code-method-index

Pada method index() kita menggunakan method findAll() untuk mengambil semua artikel yang ada di tabel news.

Sebenarnya ini tidak direkomendasikan, jika ada banyak sekali data news. Karena akan membuat performanya lambat.

Mungkin nanti akan kita ubah saat menerapkan sorting dan pagination.

Lanjut ke method preview($id)..

code method preview

Method ini berfungsi untuk menampilkan preview dari artikel. Pada method ini, kita menggunakan method first() untuk mengambil satu artikel saja.

Jika artikel tidak ditemukan di database, maka kita akan menampilkan halaman 404 error.

Lanjut ke method create()..

code-method-create

Method ini berfungsi untuk menampilkan form create dan menyimpan data yang di POST dari form create news.

Sebelum menyimpan data ke database, pastikan sudah lolos validasi. Karena bisa saja data yang dimasukkan user tidak valid.

Lanjut ke method edit()..

code method edit

Method edit() hampir sama seperti method create() hanya saja di method edit() kita harus mengambil data yang akan diedit lalu ditampilkan pada form.

Terakhir method delete()..

code-method-delete

Seperti namanya, method ini bertugas untuk menghapus news.

Jika ada yang kurang kamu pahami, silakan tanyakan di komentar!

Berikutnya kita akan membuat layout dan view untuk Admin.

Step 3 – Membuat Layout dan View untuk Admin

Karena tampilan halaman admin berbeda dengan halaman depan, maka kita perlu membuat template layout yang berbeda.

Buatlah file baru di dalam layout/admin dengan nama navbar.php

Views/layout/admin/navbar.php
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container">
        <a class="navbar-brand" href="<?= base_url('admin') ?>">Admin Home</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse justify-content-between" id="navbarNav">
            <ul class="navbar-nav">
                <li class="nav-item">
                    <a class="nav-link" href="<?= base_url('admin/news') ?>">News</a>
                </li>
            </ul>
            <ul class="navbar-nav">
                <li class="nav-item">
                    <a href="<?= base_url('admin/news/new') ?>" class="btn btn-primary mr-3">New Post</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="<?= base_url('admin/setting') ?>">Setting</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="<?= base_url('auth/logout') ?>">Logout</a>
                </li>
            </ul>
        </div>
    </div>
</nav>

Buatlah file baru di dalam layout/admin dengan nama admin_layout.php kemudian isi dengan kode berikut:

Views/layout/admin/admin_layout.php
<!DOCTYPE html>
<html lang="en">

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

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

<body>

    <?= $this->include('layout/admin/navbar') ?>

    <div class="container my-5">
        <div class="row">
            <div class="col-md-12">
                <?= $this->renderSection('content') ?>
            </div>
        </div>
    </div>

    <!-- Custom scripts for all pages-->
    <script src="<?= base_url('js/jquery.min.js') ?>"></script>
    <script src="<?= base_url('js/bootstrap.min.js') ?>"></script>

</body>

</html>

Sekarang kita punya layout untuk admin.

file layout admin

Layout sudah selesai, berikutnya kita buat view untuk News Admin.

Ada tiga view yang kita butuhkan:

  1. View untuk list news (admin_list_news.php)
  2. View untuk menulis news (admin_create_news.php)
  3. View untuk edit news (admin_edit_news.php)

Mari kita buat satu per satu.

Buatlah file baru di dalam folder app/Views dengan nama admin_list_news.php, lalu isi dengan kode berikut:

Views/admin_list_news.php
<?= $this->extend('layout/admin/admin_layout') ?>

<?= $this->section('content') ?>

<table class="table">
<thead>
<tr>
    <th>#</th>
    <th>Title</th>
    <th>Status</th>
    <th>Action</th>
</tr>
</thead>
<tbody>
<?php foreach($newses as $news): ?>
<tr>
    <td><?= $news['id'] ?></td>
    <td>
        <strong><?= $news['title'] ?></strong><br>
        <small class="text-muted"><?= $news['created_at'] ?></small>
    </td>
    <td>
        <?php if($news['status'] === 'published'): ?>
        <small class="text-success"><?= $news['status'] ?></small>
        <?php else: ?>
        <small class="text-muted"><?= $news['status'] ?></small>
        <?php endif ?>
    </td>
    <td>
        <a href="<?= base_url('admin/news/'.$news['id'].'/preview') ?>" class="btn btn-sm btn-outline-secondary" target="_blank">Preview</a>
        <a href="<?= base_url('admin/news/'.$news['id'].'/edit') ?>" class="btn btn-sm btn-outline-secondary">Edit</a>
        <a href="#" data-href="<?= base_url('admin/news/'.$news['id'].'/delete') ?>" onclick="confirmToDelete(this)" class="btn btn-sm btn-outline-danger">Delete</a>
    </td>
</tr>
<?php endforeach ?>
</tbody>
</table>

<div id="confirm-dialog" class="modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-body">
        <h2 class="h2">Are you sure?</h2>
        <p>The data will be deleted and lost forever</p>
      </div>
      <div class="modal-footer">
        <a href="#" role="button" id="delete-button" class="btn btn-danger">Delete</a>
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
      </div>
    </div>
  </div>
</div>

<script>
function confirmToDelete(el){
    $("#delete-button").attr("href", el.dataset.href);
    $("#confirm-dialog").modal('show');
}
</script>


<?= $this->endSection() ?>

Setelah itu, buat lagi file baru di dalam app/Views dengan nama admin_create_news.php dan isi sebagai berikut:

Views/admin_create_news.php
<?= $this->extend('layout/admin/admin_layout') ?>

<?= $this->section('content') ?>

<form action="" method="post" id="text-editor">
    <div class="form-group">
        <label for="title">Title</label>
        <input type="text" name="title" class="form-control" placeholder="News title" required>
    </div>
    <div class="form-group">
        <textarea name="content" class="form-control" cols="30" rows="10" placeholder="Write a great news!"></textarea>
    </div>
    <div class="form-group">
        <button type="submit" name="status" value="published" class="btn btn-primary">Publish</button>
        <button type="submit" name="status" value="draft" class="btn btn-secondary">Save to Draft</button>
    </div>
</form>


<?= $this->endSection() ?>

Terakhir, kita akan buat form edit.

Buat satu lagi file baru di dalam folder app/Views dengan nama admin_edit_news.php dan isi sebagai berikut:

Views/admin_edit_news.php
<?= $this->extend('layout/admin/admin_layout') ?>

<?= $this->section('content') ?>

<form action="" method="post" id="text-editor">
    <input type="hidden" name="id" value="<?= $news['id'] ?>" />
    <div class="form-group">
        <label for="title">Title</label>
        <input type="text" name="title" class="form-control" 
            placeholder="News title" value="<?= $news['title'] ?>" required>
    </div>
    <div class="form-group">
        <textarea name="content" 
            class="form-control" 
            cols="30" rows="10" 
            placeholder="Write a great news!"><?= $news['content'] ?></textarea>
    </div>
    <div class="form-group">
        <button type="submit" name="status" value="published" class="btn btn-primary">Publish</button>
        <button type="submit" name="status" value="draft" class="btn btn-secondary">Save to Draft</button>
    </div>
</form>


<?= $this->endSection() ?>

Sekarang kita sudah punya view yang dibutuhkan untuk halaman admin news.

file view admin news

Uji Coba..

Jika tidak ada error, seharusnya sudah bisa dicoba.

Silakan buka localhost:8080/admin/news untuk melakukan uji coba.

admin list news

Selanjutnya, coba buat artikel baru di localhost:8080/admin/news/new.

admin create news

Hasilnya, artikel berhasil disimpan. 🎉

percobaan-insert-data

Coba juga untuk melakukan edit dan hapus data.

percobaan hapus data

Jika tidak ada yang error..

Selamat! 🥳

Kamu sudah menyelesaikan tutorial ini.

Tapi jika masih ada error, jangan menyerah. Coba diskusikan error-nya di kolom komentar, siapa tau dapat solusi.

Apa Selanjutnya?

Oke.. Sampai di sini dulu tutorial membuat CRUD di Codeigniter 4. Selanjutnya kita harus membuat halaman login untuk Admin.

Soalnya, di tahap ini.. semua orang bisa mengakses route /admin/.

Selanjutnya:

  • Tutorial CI 4 (Part #10): Login dan Register (Coming soon)

Untuk tutorial Codeigniter yang lainnya, cek di 📚 List Tutorial Codeigniter