Create custom validation rule in Codeigniter4

CI4 provides different methods to validate form inputs.
We will look at an example with a custom rule for validation, which will validate the an input email and check whether it already exists in the backend database or not.

  1. Let us first create a TABLE with some dummy records in it.
CREATE TABLE `user` (
  `id` mediumint(8) unsigned NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `email` varchar(255) default NULL,
  `country` varchar(100) default NULL,
  `region` varchar(50) default NULL,
  `postalZip` varchar(10) default NULL,
  `phone` varchar(100) default NULL,
  PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;


INSERT INTO `user` (`name`,`email`,`country`,`region`,`postalZip`,`phone`)
VALUES
  ("Quamar Avila","nonummy.ac@aol.org","Germany","Bình Phước","57238","1-668-477-3499"),
  ("Yoko Clarke","nunc.nulla.vulputate@outlook.ca","South Africa","Niger","B3C 2H2","1-526-636-1356"),
  ("Garrison Barron","dui.augue@icloud.couk","Peru","Sląskie","455183","(124) 327-5046"),
  ("Noah Newman","nullam.vitae@outlook.com","Brazil","Niger","01765","(534) 524-8743"),
  ("Cruz Vaughn","eu.accumsan@yahoo.net","Colombia","UK","82-96","(466) 908-3438");

2. We will create a Controller Form.php under App\Controllers

<?php 
namespace App\Controllers;

use CodeIgniter\Controller;
class Form extends Controller
{
    function __construct()
	{
        $this->validation = \Config\Services::validation();
        $this->input = \Config\Services::request();
	} 
    public function index(){
        $data = array();
        $data['validation'] = $this->validation; //Capture validation errors
        $data['input'] = $this->input->getPost();
        if($this->input->getPost('register')) {
             //set validation Rules
            $this->validation->setRule('username', 'User Name', 'required');

            //custom error message set
            $this->validation->setRule('email', 'Email',['required','valid_email','check_user_exists[email]'],['check_user_exists'=>'User already exists.']);
            $this->validation->setRule('password', 'Password', 'required');

            //Run validation rule
            if($this->validation->run($this->input->getPost()) ){
                echo "Validation successful";
                print_r($this->input->getPost());
                exit;
                //Proceed to process the record and redirect
            }
        }
        echo view("App\Views\client",$data);
    }

}

In the above example we see that we have set 3 rules for the email field.
a. required : The input is mandatory
b. valid_email: This is an inbuilt codeigniter validator that checks for a valid email address.
c. check_user_exists[email] is a custom function that we will write for validation. It takes the email field input as parameter.

We have also given a custom error message for the custom function rule in the last parameter to setRule function.

3. Create a model file UserModel.php under App\Models folder. This model will connect to the database and query to validate the input.

<?php namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model{
    protected $table = "user";
    protected $primaryKey = 'id';

    public function checkUniqueEmail($email){
        $response = $this->query("Select u.id from user u where u.email = '".$email."'");
        if (count($response->getResultArray()) == 0){
            return true; //Email exists already
        }
        return false; //Email does not exist
    }
}

4. We will write the CustomRule in a separate namespace, under app\Validation folder. You can create the folder “Validation” under app folder.
Create a new file CustomRule.php with code as below.

<?php
namespace App\Validation;
use App\Models\UserModel;

class CustomRules{
    public function check_user_exists($post_string){
        $user = new UserModel();
        $isExists = $user->checkUniqueEmail($post_string);
        return $isExists;
    }  
}

5. We will have to add the new CustomRule class under app/Config/Validation.php file.

namespace Config;

//Add below line
use App\Validation\CustomRules;

class Validation extends BaseConfig
{
    // --------------------------------------------------------------------
    // Setup
    // --------------------------------------------------------------------

    /**
     * Stores the classes that contain the
     * rules that are available.
     *
     * @var string[]
     */
    public array $ruleSets = [
        
        //Add below line
        CustomRules::class,
    ];

6. Finally we create the View file client.php under App/Views folder.

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<div class="container">
<div class="content">

<form class="form-horizontal" action='' method="POST">
  <fieldset>
    <div id="legend">
      <legend class="">Register</legend>
    </div>
    <div class="control-group">
      <label class="control-label"  for="username">Username</label>
      <div class="controls">
        <input type="text" id="username" name="username" value="<?=isset($input['username']) ? $input['username'] : ""?>" placeholder="" class="input-xlarge">
        <p class="alert-danger"><?php echo $validation->getError('username');?></p>
      </div>
    </div>
 
    <div class="control-group">
      <label class="control-label" for="email">E-mail</label>
      <div class="controls">
        <input type="text" id="email" name="email" value="<?=isset($input['email']) ? $input['email'] : ""?>" placeholder="" class="input-xlarge">
        <p class="alert-danger"><?php echo $validation->getError('email');?></p>
      </div>
    </div>
 
    <div class="control-group">
      <label class="control-label" for="password">Password</label>
      <div class="controls">
        <input type="password" id="password" value="<?=isset($input['password']) ? $input['password'] : ""?>" name="password" placeholder="" class="input-xlarge">
        <p class="alert-danger"><?php echo $validation->getError('password');?></p>
      </div>
    </div>
 
    <div class="control-group">
      <!-- Button -->
      <div class="controls">
        <button class="btn btn-success" value="register" name="register">Register</button>
      </div>
    </div>
  </fieldset>
</form>
</div>
</div>

7. We add the routes to app/Config/Routes.php to view the final result in browser.

$routes->get('customvalidation/form', 'Form::index');
$routes->post('customvalidation/form', 'Form::index');

We will be able to see the final results as below with the custom error message and successful validation.

Code output

Leave a Reply