CRUD (Create Read Update Delete) in a CodeIgniter 4

Modern web applications often involve working with databases to store and manage data. CRUD operations (Create, Read, Update, Delete) form the foundation of interacting with a database.

These operations allow users to create new records, retrieve existing data, update information, and delete entries when necessary. In the context of web development, frameworks provide a structured approach to handle these operations efficiently.

This article is a compre­hensive guide on imple­menting CRUD operations in CodeIgnite­r 4. It covers how to perform Create­, Read, Update, and Dele­te operations using the frame­work’s conventions and components.

CRUD (Create Read Update Delete) in a CodeIgniter 4


Table of Content

  1. Database configuration
  2. Create a Table using migration
  3. Model Creation
  4. Routes Configuration
  5. Create a Controller
  6. Creating Views
  7. Run the project
  8. Output
  9. Conclusion

1. Database configuration

  • Open .env file which is available at the project root.

NOTE – If dot (.) not added at the start then rename the file to .env.

  • Remove # from start of database.default.hostnamedatabase.default.databasedatabase.default.usernamedatabase.default.passworddatabase.default.DBDriverdatabase.default.DBPrefix, and database.default.port.
  • Update the configuration and save it.
database.default.hostname = 127.0.0.1
database.default.database = codeigniterdb
database.default.username = root
database.default.password = root
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306

2. Create a Table using migration

  • Create subjects table by executing below command:
php spark migrate:create create_subjects_table
  • This will create a new file PHP file that ends with create_subjects_table.
  • Open the file to define table structure in the up() method.
  • Using the down() method delete subjects table which calls when undoing migration.
<?php namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class CreateSubjectsTable extends Migration
{
    public function up() {
        $this->forge->addField([
             'id' => [
                  'type' => 'INT',
                  'constraint' => 5,
                  'unsigned' => true,
                  'auto_increment' => true,
             ],
             'name' => [
                  'type' => 'VARCHAR',
                  'constraint' => '100',
             ],
             'description' => [
                  'type' => 'TEXT',
                  'null' => true,
             ],
        ]);
        $this->forge->addKey('id', true);
        $this->forge->createTable('subjects');
    }

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

    public function down() {
        $this->forge->dropTable('subjects');
    }
}
  • After defining table definition execute the below command to create the table in the database –
php spark migrate

3. Model Creation

  • Execute below command to create Subjects Model –
php spark make:model Subjects
  • Open app/Models/Subjects.php file.
  • In $allowedFields Array specify field names – ['name','description'] that can be set during insert and update.
<?php

namespace App\Models;

use CodeIgniter\Model;

class Subjects extends Model { 

   protected $DBGroup = 'default'; 
   protected $table = 'subjects'; 
   protected $primaryKey = 'id'; 
   protected $useAutoIncrement = true; 
   protected $insertID = 0; 
   protected $returnType = 'array'; 
   protected $useSoftDeletes = false; 
   protected $protectFields = true; 
   protected $allowedFields = ['name','description']; 

   // Dates 
   protected $useTimestamps = false; 
   protected $dateFormat = 'datetime'; 
   protected $createdField = 'created_at'; 
   protected $updatedField = 'updated_at'; 
   protected $deletedField = 'deleted_at'; 

   // Validation 
   protected $validationRules = []; 
   protected $validationMessages = []; 
   protected $skipValidation = false; 
   protected $cleanValidationRules = true; 

   // Callbacks 
   protected $allowCallbacks = true; 
   protected $beforeInsert = []; 
   protected $afterInsert = []; 
   protected $beforeUpdate = []; 
   protected $afterUpdate = []; 
   protected $beforeFind = []; 
   protected $afterFind = []; 
   protected $beforeDelete = []; 
   protected $afterDelete = []; 
}

4. Routes Configuration

  • Open app/Config/Routes.php file.
  • Define 6 routes –
    • / – Display subject list.
    • subjects/create – Open add subject view.
    • subjects/store – Submit subject form to insert a record.
    • subjects/edit/(:num) – Open edit subject view by id.
    • subjects/update/(:num) – Submit edit form to update a record by id.
    • subjects/delete/(:num) – Delete a subject by id.
$routes->get('/', 'SubjectsController::index');

$routes->get('subjects/create', 'SubjectsController::create');
$routes->post('subjects/store', 'SubjectsController::store');

$routes->get('subjects/edit/(:num)', 'SubjectsController::edit/$1');
$routes->post('subjects/update/(:num)', 'SubjectsController::update/$1');

$routes->get('subjects/delete/(:num)', 'SubjectsController::delete/$1');

5. Create a Controller

  • Create SubjectsController Controller –
php spark make:controller SubjectsController
  • Open app/Controllers/SubjectsController.php file.
  • Import Subjects Model that we created earlier.
  • Create 6 methods –
    • index() – Select all records from the subjects table and assign in $data['subjects']. Load subjects/index view and pass $data.
    • create() – With this method load subjects/create view for adding a new subject.
    • store() – With this method insert a new record in the subjects table.

Read POST values. If 'submit' is POST then define validation. If values are not validated then return to the subjects/create view with the error response.

If values are validated then insert a record in the subjects table. If a record is successfully inserted then store the success message in session()->setFlashdata('message') and class name in session()->setFlashdata('alert-class') and return to the subjects/create route.

Similarly, if a record is not inserted then store the failed message in session()->setFlashdata('message') and class name in session()->setFlashdata('alert-class') and return to the subjects/create route.

    • edit() – With this method load edit subject view. Select a record from the subjects table by $id and assign in $data['subject']. Load subjects/edit view and pass $data.
    • update() – With this method update a record in the subjects table.

Read POST values. If 'submit' is POST then define validation. If values are not validated then return to the edit view with the error response.

If values are not validated then redirect to the edit view with the error response. Select a record from the subjects table by $id and assign in $subject.

If values are validated then update a record by $id. If a record is successfully inserted then store the success message in session()->setFlashdata('message') and class name in session()->setFlashdata('alert-class') and return to the /route.

Similarly, if a record is not inserted then store the failed message in session()->setFlashdata('message') and class name in session()->setFlashdata('alert-class') and return to the subjects/edit route.

    • delete() – With this method delete a record from the subjects table by $id.

Check $id record exists in the subjects table. If exists then delete the record by $id and store the success message in session()->setFlashdata('message') and class name in session()->setFlashdata('alert-class'),

Similarly, if a record is not deleted then store the failed message in session()->setFlashdata('message') and class name in session()->setFlashdata('alert-class') .

Return to the / route.

<?php namespace App\Controllers;

use App\Controllers\BaseController;
use App\Models\Subjects;

class SubjectsController extends BaseController
{

   public function index(){
      $subjects = new Subjects();

      ## Fetch all records
      $data['subjects'] = $subjects->findAll();
      return view('subjects/index',$data);
   }

   public function create(){
      return view('subjects/create');
   }

   public function store(){
      $request = service('request');
      $postData = $request->getPost();

      if(isset($postData['submit'])){

         ## Validation
         $input = $this->validate([
            'name' => 'required|min_length[3]',
            'description' => 'required'
         ]);

         if (!$input) {
            return redirect()->route('subjects/create')->withInput()->with('validation',$this->validator); 
         } else {

            $subjects = new Subjects();

            $data = [
               'name' => $postData['name'],
               'description' => $postData['description']
            ];

            ## Insert Record
            if($subjects->insert($data)){
               session()->setFlashdata('message', 'Added Successfully!');
               session()->setFlashdata('alert-class', 'alert-success');

               return redirect()->route('subjects/create'); 
            }else{
               session()->setFlashdata('message', 'Data not saved!');
               session()->setFlashdata('alert-class', 'alert-danger');

               return redirect()->route('subjects/create')->withInput(); 
            }

         }
      }

   }

   public function edit($id = 0){

      ## Select record by id
      $subjects = new Subjects();
      $subject = $subjects->find($id);

      $data['subject'] = $subject;
      return view('subjects/edit',$data);

   }

   public function update($id = 0){
      $request = service('request');
      $postData = $request->getPost();

      if(isset($postData['submit'])){

        ## Validation
        $input = $this->validate([
          'name' => 'required|min_length[3]',
          'description' => 'required'
        ]);

        if (!$input) {
           return redirect()->route('subjects/edit/'.$id)->withInput()->with('validation',$this->validator); 
        } else {

           $subjects = new Subjects();

           $data = [
              'name' => $postData['name'],
              'description' => $postData['description']
           ];

           ## Update record
           if($subjects->update($id,$data)){
              session()->setFlashdata('message', 'Updated Successfully!');
              session()->setFlashdata('alert-class', 'alert-success');

              return redirect()->route('/'); 
           }else{
              session()->setFlashdata('message', 'Data not saved!');
              session()->setFlashdata('alert-class', 'alert-danger');

              return redirect()->route('subjects/edit/'.$id)->withInput(); 
           }

        }
      }

   }

   public function delete($id=0){

      $subjects = new Subjects();

      ## Check record
      if($subjects->find($id)){

         ## Delete record
         $subjects->delete($id);

         session()->setFlashdata('message', 'Deleted Successfully!');
         session()->setFlashdata('alert-class', 'alert-success');
      }else{
         session()->setFlashdata('message', 'Record not found!');
         session()->setFlashdata('alert-class', 'alert-danger');
      }

      return redirect()->route('/');

   }
}

6. Creating Views

Create a layouts and subjects folder at app/Views/.

Create the following files in the folders –

  • layouts
    • layout.php
  • subjects
    • index.php
    • create.php
    • edit.php

layouts/layout.php

Creating a layout. Included bootstrap CSS in the <head > section and added some CSS.

Define 'content' section.

<!doctype html>
<html>
<head>
    <title>CRUD (Create Read Update Delete) in a CodeIgniter 4</title>

    <link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

    <style type="text/css">
    .mb20{
         margin-bottom: 20px;
    }
    .actionbutton{
         width: 100%;
         height: 55px;
    }
    .errors{
         color: red;
    }
    </style>
</head>
<body>
    <div class="container">
         <div class="row">
              <div class="col-md-12">
                   <?= $this->renderSection('content') ?>
              </div>
         </div>
    </div>
</body>
</html>

subjects/index.php

Extend 'layouts.layout' and add content between $this->section('content') and $this->endSection().

Add <a > element to open Add subject form. Pass <?=site_url('subjects/create')?> in href attribute.

Display bootstrap alert message if 'message' Session exists. Also, set alert class using 'alert-class' Session.

Create <table > to list records.

Loop on the $subjects and create a row. In the last column added edit and delete links.

Set edit <a > route to <?= site_url('subjects/edit/'.$subject['id']) ?> and delete <a > route to <?= site_url('subjects/delete/'.$subject['id']) ?>.

<?= $this->extend('layouts/layout') ?>

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

<div class="actionbutton mt-2">
    <a class="btn btn-info float-right mb20" href="<?=site_url('subjects/create')?>">Add Subject</a>
</div>

<?php 
// Display Response
if(session()->has('message')){
?>
    <div class="alert <?= session()->getFlashdata('alert-class') ?>">
         <?= session()->getFlashdata('message') ?>
    </div>
<?php
}
?>

<!-- Subject List -->
<table width="100%" border="1" style="border-collapse: collapse;">
    <thead>
         <tr>
             <th width="10%">ID</th>
             <th width="30%">Name</th>
             <th width="45%">Description</th>
             <th width="15%">&nbsp;</th>
         </tr>
    </thead>
    <tbody>
    <?php 
    if(count($subjects) > 0){

         foreach($subjects as $subject){
    ?>
         <tr>
              <td><?= $subject['id'] ?></td>
              <td><?= $subject['name'] ?></td>
              <td><?= $subject['description'] ?></td>
              <td align="center">
                   <a class="btn btn-sm btn-info" href="<?= site_url('subjects/edit/'.$subject['id']) ?>">Edit</a>
                   <a class="btn btn-sm btn-danger" href="<?= site_url('subjects/delete/'.$subject['id']) ?>">Delete</a>
              </td>
         </tr>
    <?php
         }

    }else{
    ?>
         <tr>
             <td colspan="4">No data found.</td>
         </tr>
    <?php
    }
    ?>
    </tbody>
</table>
<?= $this->endSection() ?>

subjects/create.php

Extend 'layouts.layout' and add content between $this->section('content') and $this->endSection().

Add <a > element to open List of subjects. Pass <?=site_url('/')?> in href attribute.

Display bootstrap alert message if 'message' Session exists. Also, set alert class using 'alert-class' Session.

Load validation service \Config\Services::validation() and assign it in $validation.

Create <form method="post">. Set its action="<?=site_url('subjects/store')?>".

Create a text and textarea element for entering the subject name and description. Display error in <span > if not validated. Also, create a submit button.

<?= $this->extend('layouts/layout') ?>

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

<div class="actionbutton mt-2">
  <a class="btn btn-info float-right mb20" href="<?=site_url('/')?>">List</a>
</div>

<div class="row">
  <h2>Add Subject</h2>
</div>

<?php 
// Display Response
if(session()->has('message')){
?>
   <div class="alert <?= session()->getFlashdata('alert-class') ?>">
     <?= session()->getFlashdata('message') ?>
   </div>
<?php
}
?>

<?php $validation = \Config\Services::validation(); ?>
<div class="row">
  <div class="col-md-12">
    <form action="<?=site_url('subjects/store')?>" method="post">
      <div class="form-group">
        <label for="email">Name:</label>
        <input type="text" class="form-control" name="name" required value="<?= old('name') ?>">

        <!-- Error -->
        <?php if( $validation->getError('name') ) {?>
           <div class='alert alert-danger mt-2'>
             <?= $error = $validation->getError('name'); ?>
           </div>
        <?php }?>
      </div>
      <div class="form-group">
        <label for="pwd">Description:</label>
        <textarea class="form-control" name="description" required><?= old('description') ?></textarea>

        <!-- Error -->
        <?php if($validation->getError('description')) {?>
          <div class='alert alert-danger mt-2'>
            <?= $error = $validation->getError('description'); ?>
          </div>
        <?php }?>

      </div>

      <button type="submit" class="btn btn-success" name="submit">Submit</button>
    </form>
  </div>

</div>

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

subjects/edit.php

Extend 'layouts.layout' and add content between $this->section('content') and $this->endSection().

Add <a > element to open List of subjects. Pass <?=site_url('/')?> in href attribute.

Display bootstrap alert message if 'message' Session exists. Also, set alert class using 'alert-class' Session.

Load validation service \Config\Services::validation() and assign it in $validation.

Create <form method="post">. Set its action="<?=site_url('subjects/update/'.$subject['id'])?>".

Create a text element and store $subject->name in value attribute. Similarly, create textarea element and store $subject->description. Display error in <span > is not validated. Also, create a submit button.

<?= $this->extend('layouts/layout') ?>

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

<div class="actionbutton mt-2">
  <a class="btn btn-info float-right mb20" href="<?=site_url('/')?>">List</a>
</div>

<div class="row">
  <h2>Edit Subject</h2>
</div>

<?php
// Display Response 
if(session()->has('message')){
?>
   <div class="alert <?= session()->getFlashdata('alert-class') ?>">
      <?= session()->getFlashdata('message') ?>
   </div>
<?php
}

?>

<?php $validation = \Config\Services::validation(); ?>
<div class="row">
  <div class="col-md-12">
    <form action="<?=site_url('subjects/update/'.$subject['id'])?>" method="post">
      <div class="form-group">
        <label for="email">Name:</label>
        <input type="text" class="form-control" name="name" required value="<?= old('name',$subject['name']) ?>">

        <!-- Error -->
        <?php if( $validation->getError('name') ) {?>
        <div class='alert alert-danger mt-2'>
          <?= $error = $validation->getError('name'); ?>
        </div>
        <?php }?>
      </div>
      <div class="form-group">
         <label for="pwd">Description:</label>
         <textarea class="form-control" name="description" required><?= old('description',$subject['description']) ?></textarea>

         <!-- Error -->
         <?php if($validation->getError('description')) {?>
         <div class='alert alert-danger mt-2'>
           <?= $error = $validation->getError('description'); ?>
         </div>
         <?php }?>

      </div>

      <button type="submit" class="btn btn-success" name="submit">Submit</button>
    </form>
  </div>

</div>

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

7. Run the project

  • Navigate to the project using Command Prompt if you are on Windows or terminal if you are on Mac or Linux, and
  • Execute “php spark serve” command.
php spark serve
  • Run http://localhost:8080 in the web browser.

8. Output

View Output


9. Conclusion

I hope this tutorial, helps you to implement CRUD in your project.

If you found this tutorial helpful then don't forget to share.