CRUD (Create Read Update Delete) in a CodeIgniter 4

CRUD (Create, Read, Update, and Delete) is a basic requirement when working with database data.

In this tutorial, I show how you can select, insert, update, and delete a record from the MySQL database in the CodeIgniter 4 project.

In the example, I am creating a page to add a new subject and list subjects with the edit and delete buttons.

CRUD (Create Read Update Delete) in a CodeIgniter 4


Contents

  1. Database configuration
  2. Create Table
  3. Model
  4. Route
  5. Controller
  6. View
  7. Run
  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.hostname, database.default.database, database.default.username, database.default.password, and database.default.DBDriver.
  • Update the configuration and save it.
database.default.hostname = 127.0.0.1
database.default.database = testdb
database.default.username = root
database.default.password = 
database.default.DBDriver = MySQLi

2. Create Table

  • Create a new table subjects using migration.
php spark migrate:create create_subjects_table
  • Now, navigate to app/Database/Migrations/ folder from the project root.
  • Find a PHP file that ends with create_subjects_table and open it.
  • Define the 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');
    }
}
  • Run the migration –
php spark migrate

3. Model

  • Create Subjects.php file in app/Models/ folder.
  • Open the file.
  • Specify table name "subjects" in $table variable, primary key "id" in $primaryKey, Return type "array" in $returnType.
  • In $allowedFields Array specify field names – ['name', 'description'] that can be set during insert and update.

Completed Code

<?php 
namespace App\Models;

use CodeIgniter\Model;

class Subjects extends Model
{
    protected $table = 'subjects'; 
    protected $primaryKey = 'id';

    protected $returnType = 'array';

    protected $allowedFields = ['name', 'description'];
    protected $useTimestamps = false;

    protected $validationRules = [];
    protected $validationMessages = [];
    protected $skipValidation = false;

}

4. Route

  • 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.

Completed Code

$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. Controller

  • Create SubjectsController.php file in app/Controllers/ folder.
  • Open the file.
  • Import Subjects Model.
  • 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.

Completed Code

<?php namespace App\Controllers;

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. View

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.

Completed Code

<!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']) ?>.

Completed Code

<?= $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.

Completed Code

<?= $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.

Completed Code

<?= $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

  • 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


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.

4 thoughts on “CRUD (Create Read Update Delete) in a CodeIgniter 4”

  1. Thank you for you great post. I was looking for help in building a News section for a website I do volunteer work for. I’m new to CI 4 and I used your code and modified it to suite my needs. Your code also taught me a lot about how to structure CI 4 code, validation and much more.

    Thank you!!

    Reply
  2. Hi Yogesh:

    Thank you for a great and easy to follow tutorial.
    I am getting errors on the redirect in the SubjectsController Controller especially in the
    store function.
    return redirect()->route(‘subjects/create’)
    I have tried changing to subjectscontroller/create but get errors.
    Now I have it set to ‘/’
    Watching your project on your video works like a charm. Not sure what has changed in the code as I copied it exactly as you typed.
    Appreciate your help.
    Ali

    Reply

Leave a Comment