The CodeIgniter 4 is launched with the updated features over the CodeIgniter 3. Now, it is a little bit similar to the Laravel framework. You can create the database schema using the migrations in CodeIgniter 4. It will work like version control of the database schema. Every time, when you will update the schema, you will have to migrate it. The migration will drop out all the existing tables and schema and then recreate it. So, it is pretty easy to use and manage in CodeIgniter 4 application. Also, you can create a Model, Migration, and Controller file using the command line. These features were not available in the previous version. Today, in this post, I will create a CRUD application in CodeIgniter 4. The CRUD operation in CodeIgniter 4 will contain the CREATE, READ, UPDATE and DELETE on the basis of data.
In this CodeIgniter 4 series, I have started from very scratch. So, that it will be helpful for beginners to grab and implement it. Hence, I am starting from the CRUD in CodeIgniter 4. So, let’s continue to the post.
Prerequisites
For creating this project in CodeIgniter 4, your system must have the following configurations.
- PHP >= 7.3
- MySQL (version > 5)
- Apache/Nginx Server
- VS Code Editor
- Composer
Create a New App For CRUD in CodeIgniter 4
For creating the CodeIgniter 4 application, I will be using the composer. If you are new to CodeIgniter 4 then I must tell you one thing. Now you can create the CodeIgniter 4 application using the command line with the help of composer.
composer create-project codeigniter4/appstarter blog
In the above command, the composer will start creating the project. The CodeIgniter 4 app starter repository holds a skeleton application, with a composer dependency. Here the project name is blog. So, it will create a new folder with the name blog, and install the files of CodeIgniter 4 inside it.
After creating the project, we will create a database in MySQL. For performing the CRUD operation in CodeIgniter 4 we will have to connect the application with the database.
How to Install CodeIgniter 4 in Windows and Linux
Create Database For CodeIgniter 4
For the database, I am using the command line. You can use phpMyAdmin or MySQL Workbench too. It is totally up to you that how you will manage it.
CREATE DATABASE ci4_blog;
I have created the database using the above command. Now, you can see, currently, there is no any table in my database. We will create using the migration in the upcoming steps.
Now, open the created project in the editor.
Configure Database in CodeIgniter 4
We have already created the database. Now, it required to connect it with the application. So, firstly, I have opened the project in the VS Code editor. Just look for the env file and rename it to .env. Then open the renamed .env file. By default, all the environment configurations are commented on inside the .env file.
So, firstly, you have to uncomment CI_ENVIRONMENT and change the production to development. Actually, we are going to create the CRUD in CodeIgniter 4, so it is in development mode. In the development mode, you will be able to debug and find out the errors in your application. But, if you are in the production mode then you will not be able to show any errors In your application.
After that, we will configure the database credentials. So, in the same file, just look out for the database. Here, under the database default configuration, we will configure our database credentials. So, just uncomment these lines and put the details as showing below.
database.default.hostname = localhost
database.default.database = ci4_blog
database.default.username = root
database.default.password = root
database.default.DBDriver = MySQLi
You can see in the below result, I have configured the database details.
Now, we are good to go for the CRUD operation in CodeIgniter 4 application.
Laravel 8 CRUD Application Tutorial From Scratch
Create Migration in CodeIgniter 4
As I told you at very first, in CodeIgniter 4 we can create the migration file for the table. This migration file will contain the schema for the table. One interesting thing is CodeIgniter 4 provides spark for the CLI. It is similar to artisan in Laravel framework.
Before creating the migration using the spark, you can checkout the help for more details.
php spark --help
The above command will show you the list of available commands to use in CodeIgniter 4.
Here, you will see the make:migration
under the Generators section. You can also checkout the help for specific command. Here, if we want to see the details of make:migration then you can use the below command.
php spark help make:migration
It will list out the description, usage and the available flags for this command,
Create Migration for Post Table
Now, let’s create a migration for the post. Actually, we have created the blog application that’s why will create a post table. I defined the table name in the plural so, here the table name will be posts.
php spark make:migration posts --table
The above command will create a new file inside the app/Database/Migrations. Here, I have
You can see the below result. Here the post table migration is created. By default there are two functions
- up() and
- down()
We have to define the schema for the post table in the up() function. When we will migrate the table, it will generate the schema using the up command. In the down() function, we will set the code to drop this table. So, let’s see one by one.
In the below snippet, I have added the schema for the post table. You can simply paste the below code there.
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class Posts extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'auto_increment' => true
],
'title' => [
'type' => 'VARCHAR',
'constraint' => '100'
],
'description' => [
'type' => 'TEXT'
],
'created_at datetime default current_timestamp',
'updated_at datetime default current_timestamp on update current_timestamp'
]);
$this->forge->addKey('id', true);
$this->forge->createTable('posts');
}
public function down()
{
$this->forge->dropTable('posts');
}
}
After adding the schema in the migration file, it will require to migrate.
php spark migrate
The above command will migrate the tables. Here, we have only one migration file, so it will create the table for it.
After the successful migration, you can checkout the database. Here, the post table has been created. You can see the schema of the post table has been generated.
Now, we will move to the next step for creating CRUD in CodeIgniter 4.
Create Model in CodeIgniter 4
To manage and perform the CRUD operation in CodeIgniter 4, we will use Model. The model will synchronize with the database.
php spark make:model Post
The above command will create a model named Post.php. Also, it will generate some default codes inside this. Like table name, primary field, allowed fields, and many more.
<?php
namespace App\Models;
use CodeIgniter\Model;
class Post extends Model
{
protected $DBGroup = 'default';
protected $table = 'posts';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $insertID = 0;
protected $returnType = 'array';
protected $protectFields = true;
protected $allowedFields = ['title', 'description'];
// Dates
protected $useTimestamps = true;
protected $dateFormat = 'datetime';
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
}
We had already created the table name in plural, so it doesn’t need to specify the table name. It will we okay for this. I just passed the allowedFields which will be inserted into the table.
Create Controller For CRUD in CodeIgniter 4
In CodeIgniter 4, you can create a controller file using the spark command. Now, no need to create controller manually and creating the functions inside it. Everything will be auto generated.
If you want to generate the CRUD methods by default then you can put the --restful
flag after the controller name. This is a very awesome feature here.
php spark make:controller PostController --restful
Here, the controller has been created. You can take a look at the controller file.
When you will open this file, you will find out some methods inside it. Take a look at the below code.
<?php
namespace App\Controllers;
use CodeIgniter\RESTful\ResourceController;
class PostController extends ResourceController
{
/**
* Return an array of resource objects, themselves in array format
*
* @return mixed
*/
public function index()
{
//
}
/**
* Return the properties of a resource object
*
* @return mixed
*/
public function show($id = null)
{
//
}
/**
* Return a new resource object, with default properties
*
* @return mixed
*/
public function new()
{
//
}
/**
* Create a new resource object, from "posted" parameters
*
* @return mixed
*/
public function create()
{
//
}
/**
* Return the editable properties of a resource object
*
* @return mixed
*/
public function edit($id = null)
{
//
}
/**
* Add or update a model resource, from "posted" properties
*
* @return mixed
*/
public function update($id = null)
{
//
}
/**
* Delete the designated resource object from the model
*
* @return mixed
*/
public function delete($id = null)
{
//
}
}
Here, all the possible methods are generated by default for CRUD in CodeIgniter 4. Now, we have to put the functionalities for the CRUD operation in CodeIgniter.
Create CRUD Operation in CodeIgniter 4
Inside the PostController.php
file, simply paste the below code.
<?php
namespace App\Controllers;
use App\Models\Post;
use CodeIgniter\RESTful\ResourceController;
class PostController extends ResourceController
{
private $post;
public function __construct()
{
helper(['form', 'url', 'session']);
$this->session = \Config\Services::session();
$this->post = new Post;
}
/**
* Return an array of resource objects, themselves in array format
*
* @return mixed
*/
public function index()
{
$posts = $this->post->orderBy('id', 'desc')->findAll();
return view('posts/index', compact('posts'));
}
/**
* Return the properties of a resource object
*
* @return mixed
*/
public function show($id = null)
{
$post = $this->post->find($id);
if($post) {
return view('posts/show', compact('post'));
}
else {
return redirect()->to('/posts');
}
}
/**
* Return a new resource object, with default properties
*
* @return mixed
*/
public function new()
{
return view('posts/create');
}
/**
* Create a new resource object, from "posted" parameters
*
* @return mixed
*/
public function create()
{
$inputs = $this->validate([
'title' => 'required|min_length[5]',
'description' => 'required|min_length[5]',
]);
if (!$inputs) {
return view('posts/create', [
'validation' => $this->validator
]);
}
$this->post->save([
'title' => $this->request->getVar('title'),
'description' => $this->request->getVar('description')
]);
session()->setFlashdata('success', 'Success! post created.');
return redirect()->to(site_url('/posts'));
}
/**
* Return the editable properties of a resource object
*
* @return mixed
*/
public function edit($id = null)
{
$post = $this->post->find($id);
if($post) {
return view('posts/edit', compact('post'));
}
else {
session()->setFlashdata('failed', 'Alert! no post found.');
return redirect()->to('/posts');
}
}
/**
* Add or update a model resource, from "posted" properties
*
* @return mixed
*/
public function update($id = null)
{
$inputs = $this->validate([
'title' => 'required|min_length[5]',
'description' => 'required|min_length[5]',
]);
if (!$inputs) {
return view('posts/create', [
'validation' => $this->validator
]);
}
$this->post->save([
'id' => $id,
'title' => $this->request->getVar('title'),
'description' => $this->request->getVar('description')
]);
session()->setFlashdata('success', 'Success! post updated.');
return redirect()->to(base_url('/posts'));
}
/**
* Delete the designated resource object from the model
*
* @return mixed
*/
public function delete($id = null)
{
$this->post->delete($id);
session()->setFlashdata('success', 'Success! post deleted.');
return redirect()->to(base_url('/posts'));
}
}
Let me explain each and every functions used inside this controller.
Explanation of PostController
Namespace
- At very first, in the space area, I have imported the Post model and the ResourceController.
- In the next line, the controller class extended the
ResourceController
. In this class, all the CRUD methods are defined.
Constructor
- Next, I have declared a private variable and called it inside the constructor method. Here, in the constructor, I have used the helper functions to use it. Like form helper is used here for the form-related operations like validation, etc. Similarly, the URL and session helper for creating URL and populating flash message. Also, I created the object of the Post model. So, that we can use it further and it will not require to instantiate again.
CRUD Methods
- In the index() method, I fetched all the posts using the Post model and returned the data to the index view. (We will create this view in the next step).
- The show() method is used to fetch the single post on the basis of the post id. If the post will found then it will return to the show view.
- The new() method is just for loading the create post view.
- In the create() method, firstly, I have set the validation rules to check the title and description of the post. If the data is not validated it will return to the same view with the validation error message. In the view, we will display this validation error message. If the inputs are validated, then using the model instance, I have stored it in the table and set the success message to the session flash data. After that redirected to the posts listing.
- The edit() method is used to get the post on the basis of post id and will return to the edit view. If the post will not found, it will redirect to the posts listing with the flash message.
- In the update() method, I used the same validation as I did in the create() method. After the validation success, I have updated the post on the basis of post id. After the update, it will set a flash message in the session and return to the posts listing.
- Lastly, the delete() function is used to delete the post on the basis of the post id. If the post deleted, it will set the flash message and return to the posts listing.
That’s all for the CRUD methods in the PostController.
Create Routes For CRUD in CodeIgniter 4
For creating the routes in CodeIgniter, you have to navigate to the Config/routes.php file. Just put the below routes in the route definitions section.
$routes->get('posts', 'PostController::index');
$routes->get('posts/new', 'PostController::new');
$routes->post('posts', 'PostController::create');
$routes->get('posts/(:num)', 'PostController::show/$1');
$routes->get('posts/edit/(:num)', 'PostController::edit/$1');
$routes->put('posts/(:num)', 'PostController::update/$1');
$routes->delete('posts/(:num)', 'PostController::delete/$1');
After creating the routes, we will create the views.
Create Views For Crud Application in CodeIgniter 4
Go to the app/Views directory and create two sub-directories there.
- layouts
- posts
Now, inside the layouts folder, create a view named master.php. Actually, I am going to use Bootstrap 5 for some basic design. So, I will use here the master view concept to extend the same layout in every views. It will save our time and code.
After that inside the posts directory create these views-
- create.php
- edit.php
- index.php
- show.php
Your views structure should look like this.
- layouts
- master.php
- posts
- create.php
- edit.php
- index.php
- show.php
You can see in the below screenshot.
Render Data on View in CodeIgniter 4
We will start from the master view. So, just add the below code there.
Master View
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CodeIgniter 4 CRUD Application | <?= $this->renderSection('title') ?></title>
<!-- bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.4.1/font/bootstrap-icons.css">
</head>
<body>
<div class="container-fluid py-4">
<h4 class="text-center fw-bold">CodeIgniter 4 CRUD Application - Programming Fields</h4>
<?= $this->renderSection('content') ?>
</div>
<!-- bootstrap 5 bundle JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script>
</body>
</html>
In the master view, I have used the renderSection() function. It will create a placeholder for putting content dynamically in the view.
Create Post View
<?= $this->extend('layouts/master');
$this->section('title') ?> Create Post <?= $this->endSection() ?>
<?= $this->section('content') ?>
<div class="container">
<?php $validation = \Config\Services::validation(); ?>
<div class="row py-4">
<div class="col-xl-12 text-end">
<a href="<?= base_url('posts') ?>" class="btn btn-primary">Back to Posts</a>
</div>
</div>
<div class="row">
<div class="col-xl-6 m-auto">
<form method="POST" action="<?= base_url('posts') ?>">
<?= csrf_field() ?>
<div class="card shadow">
<div class="card-header">
<h5 class="card-title">Create Post</h5>
</div>
<div class="card-body p-4">
<div class="form-group mb-3 has-validation">
<label class="form-label">Post Title</label>
<input type="text" class="form-control <?php if($validation->getError('title')): ?>is-invalid<?php endif ?>" name="title" placeholder="Post Title" value="<?php echo set_value('title'); ?> "/>
<?php if ($validation->getError('title')): ?>
<div class="invalid-feedback">
<?= $validation->getError('title') ?>
</div>
<?php endif; ?>
</div>
<div class="form-group">
<label class="form-label">Description</label>
<textarea class="form-control <?php if($validation->getError('description')): ?>is-invalid<?php endif ?>" name="description" placeholder="Description"><?php echo set_value('description'); ?></textarea>
<?php if ($validation->getError('description')): ?>
<div class="invalid-feedback">
<?= $validation->getError('description') ?>
</div>
<?php endif; ?>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-success">Save</button>
</div>
</div>
</form>
</div>
</div>
</div>
<?= $this->endSection() ?>
In the create view, I populated the form validation error message and created the form to submit the post.
Post Edit View
<?= $this->extend('layouts/master');
$this->section('title') ?> Create Post <?= $this->endSection() ?>
<?= $this->section('content') ?>
<div class="container">
<?php $validation = \Config\Services::validation(); ?>
<div class="row py-4">
<div class="col-xl-12 text-end">
<a href="<?= base_url('posts') ?>" class="btn btn-primary">Back to Posts</a>
</div>
</div>
<div class="row">
<div class="col-xl-6 m-auto">
<form method="POST" action="<?= base_url('posts/'.$post['id']) ?>">
<?= csrf_field() ?>
<input type="hidden" name="_method" value="PUT"/>
<div class="card shadow">
<div class="card-header">
<h5 class="card-title">Update Post</h5>
</div>
<div class="card-body p-4">
<div class="form-group mb-3 has-validation">
<label class="form-label">Post Title</label>
<input type="text" class="form-control <?php if($validation->getError('title')): ?>is-invalid<?php endif ?>" name="title" placeholder="Post Title" value="<?php if($post['title']): echo $post['title']; else: set_value('title'); endif ?>"/>
<?php if ($validation->getError('title')): ?>
<div class="invalid-feedback">
<?= $validation->getError('title') ?>
</div>
<?php endif; ?>
</div>
<div class="form-group">
<label class="form-label">Description</label>
<textarea class="form-control <?php if($validation->getError('description')): ?>is-invalid<?php endif ?>" name="description" placeholder="Description"><?php if($post['description']): echo $post['description']; else: set_value('description'); endif ?></textarea>
<?php if ($validation->getError('description')): ?>
<div class="invalid-feedback">
<?= $validation->getError('description') ?>
</div>
<?php endif; ?>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-success">Update</button>
</div>
</div>
</form>
</div>
</div>
</div>
<?= $this->endSection() ?>
Index view to display all posts
<?= $this->extend('layouts/master');
$this->section('title') ?> Posts <?= $this->endSection() ?>
<?= $this->section('content'); ?>
<div class="container">
<div class="row py-4">
<div class="col-xl-12 text-end">
<a href="<?= base_url('posts/new') ?>" class="btn btn-primary">Add Post</a>
</div>
</div>
<div class="row py-2">
<div class="col-xl-12">
<?php
if(session()->getFlashdata('success')):?>
<div class="alert alert-success alert-dismissible">
<button type="button" class="btn-close" data-bs-dismiss="alert">×</button>
<?php echo session()->getFlashdata('success') ?>
</div>
<?php elseif(session()->getFlashdata('failed')):?>
<div class="alert alert-danger alert-dismissible">
<button type="button" class="btn-close" data-bs-dismiss="alert">×</button>
<?php echo session()->getFlashdata('failed') ?>
</div>
<?php endif; ?>
<div class="card">
<div class="card-header">
<h5 class="card-title">Posts</h5>
</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>Id</th>
<th>Title</th>
<th>Description</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php
if (count($posts) > 0):
foreach ($posts as $post): ?>
<tr>
<td><?= $post['id'] ?></td>
<td><?= $post['title'] ?></td>
<td><?= $post['description'] ?></td>
<td class="d-flex">
<a href="<?= base_url('posts/'.$post['id']) ?>" class="btn btn-sm btn-info mx-1" title="Show"><i class="bi bi-info-square"></i></a>
<a href="<?= base_url('posts/edit/'.$post['id']) ?>" class="btn btn-sm btn-success mx-1" title="Edit"><i class="bi bi-pencil-square"></i></a>
<form class="display-none" method="post" action="<?= base_url('posts/'.$post['id'])?>" id="postDeleteForm<?=$post['id']?>">
<input type="hidden" name="_method" value="DELETE"/>
<a href="javascript:void(0)" onclick="deletePost('postDeleteForm<?=$post['id']?>')" class="btn btn-sm btn-danger" title="Delete"><i class="bi bi-trash"></i></a>
</form>
</td>
</tr>
<?php endforeach;
else: ?>
<tr rowspan="1">
<td colspan="4">
<h6 class="text-danger text-center">No post found</h6>
</td>
</tr>
<?php endif ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script>
function deletePost(formId) {
var confirm = window.confirm('Do you want to delete this post?');
if(confirm == true) {
document.getElementById(formId).submit();
}
}
</script>
<?= $this->endSection(); ?>
Show Post View
<?= $this->extend('layouts/master');
$this->section('title') ?> Show Post <?= $this->endSection() ?>
<?= $this->section('content') ?>
<div class="container">
<div class="row py-4">
<div class="col-xl-12 text-end">
<a href="<?= base_url('posts') ?>" class="btn btn-primary">Back to Posts</a>
</div>
</div>
<div class="row">
<div class="col-xl-6 m-auto">
<div class="card shadow">
<div class="card-header">
<h5 class="card-title">Show Post</h5>
</div>
<div class="card-body p-4">
<div class="form-group mb-3 has-validation">
<label class="form-label">Post Title</label>
<input type="text" class="form-control" disabled placeholder="Post Title" value="<?php echo trim($post['title']);?>"/>
</div>
<div class="form-group">
<label class="form-label">Description</label>
<textarea class="form-control" disabled name="description" placeholder="Description"><?php echo trim($post['description']);?></textarea>
</div>
</div>
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
CRUD Operation Results
Now, it’s time to see the results for the CRUD operations. So, run the application using the command line using the php spark.
php spark serve
Open the browser, and hit the above URL that is – http://localhost:8080
to see the result.
So, let’s navigate to the posts.
Posts Listing
Currently, we have no posts in the table. So, firstly, we will create a post. Just click on Add Post button.
It will open a new page to create a post.
Create New Post
As, we used the form validation, so you will see the validation error message.
After creating the post, you will be redirected to the post listing with a success message. Because we used session flash data to set the message. Here, I created few posts so that you can see the list.
Display Single Post Result
When you will click on show post action, it will open the new view with the post detail. This is just to show the post, so the form is disabled.
Edit/Update Post Result
When you will click on the edit action, it will redirect you to the edit post. Here, the form validation is already set so you will see the validation error message.
After updating the post, you will be redirected back to the lists with message.
Delete Post Result
When you will click on the delete post option, it will ask you the confirmation. I have used the javascript for it.
After confirmation, it will delete the post.
TakayukiI says
Your tutorial is the best for me! Thank you,a lot!!
Varshil Code81 says
Really Thank you so much
Cem Sönmez says
I am newbie about php and codeigniter. I have following error. What should I do to fix the error?
$severity 2
$message Undefined property: App\Controllers\PostController::$post
$file C:\XAMPP\htdocs\my-blog\app\Controllers\PostController.php
$line 16
https://imgur.com/a/MIzzdOH
Umesh Rana says
Have you created an object of the Post model class? If not then please create it in the constructor.
private $post;
public function __construct()
{
helper(['form', 'url', 'session']);
$this->session = \Config\Services::session();
$this->post = new Post;
}
Please follow this one.
Cem Sönmez says
Thank you, problem is solved.