Cora's Validation class

The Validate class is for checking that data matches a set of restrictions. For instance, if you have a form for users to submit and want to require that they fill out the 'email' field and enter something that at least looks like a valid email, Validate can help with that. It's main usage will typically be for validating form submissions, but it can be used to validate any data you pass in.

Note that the Validate class must be called from a Controller as any errors returned will be loaded into that controller's "$this->data->errors" data member!

Front-end vs. Back-end Validation:

If you are unfamiliar with form validation, it's worth mentioning that front-end Javascript validators are easier to setup and can save you that tiny bit of server processing power if efficiency is important. The main drawbacks of front-end validation is that it can be bypassed (important to know if you didn't already know that) and you have to setup a special API in order to do things like check if a Username is already taken, etc. For this reason, for validation that is even remotely important, you should either use back-end validation like this Validation class provides, or use both a front-end validator and this class on the backend (in-case a user bypasses the front-end validation code).

Example Usage

// This is a method within a controller.
public function createPOST()
{
    // Load Validate
    $this->load->library('Validate', $this, true);  

    // Define validation rules for form inputs.
    $this->Validate->rule('username', 'required|max_length[55]|trim');
    $this->Validate->rule('email', 'required|valid_email');
    $this->Validate->rule('password', 'required');
    $this->Validate->rule('password2', 'required|matches[password]');

    // Initiate validation
    if ($this->Validate->run()) {        
        // Form validation was successful! Do stuff with data.
    }
    else {      
        // The form validation failed!
        // Redisplay the form to the user so they can fix the errors.
        $this->create();
    }
}

If you are using the Cora demo project, you can find an example form being used at:

/controllers/articles/controller.News.php

Which can be navigated to in your web browser by going to:

localhost/myProject/articles/news/create/

Typical Usage Steps

Usage typically includes the following steps:

  1. Load the validation class.
  2. Define any custom validation checks you need.
  3. Apply validation checks to pieces of data by defining the rules that data must obey.
  4. Run the validation checker.
  5. Display any errors to the user and repopulate the form they submitted if necessary.

Loading

Although you can certainly load Validate like any other class, the recommended way of loading it into your controller is to use the Load class. The load class handles some references stuff for you automatically which I'll explain later. To use the Load class to get Validate, add the following to your controller:

// Recommended way of setup
$this->load->library('Validate', $this, true);

The fact that we're specifying that we want to load the Validate class as the first parameter should make sense. What you're probably wondering about is what the other two parameters do. For the 2nd parameter we're passing a reference to the current controller; Validate uses this reference to load any validation errors generated into that controller's "$this->data->errors" data member. The third parameter being true tells the Load class to create a reference in the calling controller to Validate for you. In other words it does the equivalent of this:

$this->data->Validate = new \Validate($this);

Ok... but why do you need a reference to Validate in the controller like that? Because in order to use Validate's form repopulation methods within a View file, you need a reference to Validate in the data you pass to that view! If this doesn't make sense at the moment, don't worry about it. You might understand it better once you see usage examples below, and even if you don't, it's not important so long as you follow the recommended way of loading specified above.

Built-In Validation Checks

There are a few built-in validation checks for common concerns. They are:

'Check' Name Description
required Specifies that a value must be entered for this field (specifying form fields that MUST be filled out).
valid_email Specifies that the value must match a valid email pattern.
matches[name] Specifies that this field must match the one specified in the brackets (I.E. does 'password' match 'password2'?)
min_length[x] Specifies that this field must be at least X characters in length.
max_length[x] Specifies that this field must be at most X characters in length.
trim Trims whitespace from the beginning and end of the field. Doesn't ever fail, this is just a utility method.

However, while these work great for general purpose kinda validations, there might be times when you need to check something specific such as "Is this username already taken?" In those scenarios you will need to define your own validation "check" which can then be applied to a field just like the built-in ones.

Custom Validation Checks

Custom validation checks allow you to call a method from whatever class you want within your app and pass that method the input value. Below is an example of us defining a custom check that calls a method named "isNameAvailable" within our User class, so that we can check if a username a person wants is available when they register. (Note: The 4th parameter is the error message if the name isn't available.)

Defining a custom validation check is easy. Here's an example:

// Define the check
$this->Validate->def('userNameAvailable', 'User','isNameAvailable', 'Username already taken.');

// Use the check in a rule
$this->Validate->rule('username', 'required|userNameAvailable');

The "def" method takes 4 required parameters, with the 5th and 6th being optional. Below is the function signature and a description of what each parameter does:

$this->Validate->def($checkName, $class, $method, $errorMessageOnFailure, $passingResponse, $arguments);
Parameter Name Description
$checkName This is the name of your new custom check. It's what you will include when defining your data rules.
$class The class within your app that we want to invoke for this custom check.
$method The method within that Class that we want to call and pass our input to.
$errorMessageOnFailure The message to display if this check does not pass.
$passingResponse [OPTIONAL] Custom check methods are expected to return a TRUE or FALSE response when given the form input. This specifies which response is the passing one! By default this is set to TRUE. See below for examples.
$arguments [OPTIONAL] The method you call will always receive as its first argument the value of the field being validated. However, there may be situations in which you need to pass along additional info. This parameter will get passed in as the 2nd argument to the custom check.

So the optional 5th parameter when defining a custom check needs a little explaining. Basically, whatever methods you call for custom checks are expected to return True or False when given a certain input. However, which response "passes" the check, depends on how the method is written - and is why this optional 5th parameter exists. See the examples below:

// Example 1 - A 'TRUE' value means the check passes.
// Check passes if 'isNameAvailable' returns TRUE.
$this->Validate->def('userNameAvailable', 'User','isNameAvailable', 'Username already taken.', TRUE);
$this->Validate->rule('username', 'required|userNameAvailable');

// Example 2 - A 'FALSE' value means the check passes.
// Check passes if 'isNameTaken' returns FALSE.
$this->Validate->def('userNameIsTaken', 'User','isNameTaken', 'Username already taken.', FALSE);
$this->Validate->rule('username', 'required|userNameIsTaken');

// Example 3 - A 'FALSE' value means the check passes. But we also need to pass along
// whether accounts are identified by username or by email.
// Check passes if 'accountExists' returns FALSE.
$validationType = 'email'; // As opposed to 'username'
$this->Validate->def('accountExists', 'Library\\Auth','accountExists', "An account with that $validationType already exists."", false, $validationType);
$this->Validate->rule('email', 'required|accountExists|trim');

// Then in the Auth Library:
public static function accountExists($authValue = false, $authField = false)
{
    // $authField is the field we are using for login validation, usually this is either 'username' or 'email'
    // $authValue is the form data that was passed in. If validating by email, then presumably it's be the user's email address.

    // Do stuff to figure out if an account exists, then return True or False.
}

Human Readable Field Names

If you have a form input that has a name which isn't super user friendly, you can replace the name of the input in any error messages with a custom specified name by specifying an optional 3rd parameter when making your rules:

$this->Validate->rule('password2', 'required|matches[password]', 'Password Confirmation');

This will result in the following error message if validation fails:
"Password Confirmation does not match password!"

Displaying errors

From within a View, the array of errors can be found within the "$errors" variable. They can be displayed by using the Load class' "repeat" method (this is the easiest way), or else you can manually iterate over the errors. Both methods are shown below:

Repeat Method:

// Parameter 1 = Array to iterate over.
// Parameter 2 = Tag to surround array items with.
// Parameter 3 = [OPTIONAL] CSS class to attach to each item.
// Parameter 4 = [OPTIONAL] Tag to wrap entire repeat block with.
// Parameter 5 = [OPTIONAL] CSS class to attach to wrapper.
<?= $this->repeat($errors, 'li', 'item', 'ul', 'list'); ?>

Generates:

<ul class="list">
    <li class="item">Error 1</li>
    <li class="item">Error 2</li>
    ...
</ul>

OR

Manual Method:

<?php if (isset($errors)) { ?>
    <ul>
        <?php foreach ($errors as $error) { ?>
            <li><?= $error; ?></li>
        <?php } ?>
    </ul>
<?php } ?>

Repopulating Forms

There's three methods in the Validate class that are designed to help you repopulate a form if validation fails.

// For repopulating text boxes and text areas.
$Validate->setField($fieldName, $defaultValue = '')

// For repopulating check boxes and ratio buttons.
$Validate->setCheckbox($fieldName, $fieldValue, $checkedByDefault = FALSE)

// For repopulating select boxes.
$Validate->setSelect($fieldName, $fieldValue, $selectedByDefault = FALSE)

These need to be echo'ed inside the HTML tag in question. See below for an example of a complete form with errors display and repopulation of the fields:

<h1>Create Article</h1>
<form method="POST">

    <?= $this->repeat($errors, 'li', 'item', 'ul', 'list'); ?>


    <div>
        <h3>Title:</h3>
        <input type="text" name="title" value="<?= $Validate->setField('title', 'test'); ?>">
    </div>
    <div>
        <h3>Content:</h3>
        <textarea name="content"><?= $Validate->setField('content'); ?></textarea>
    </div>
    <br>

    <div>
        Item 1:<input type="checkbox" name="mycheck[]" value="1" <?=$Validate->setCheckbox('mycheck', '1');?>>
        <br>
        Item 2:<input type="checkbox" name="mycheck[]" value="2" <?=$Validate->setCheckbox('mycheck', '2', true);?>>
    </div>
    <br>

    <div>
        <select name="myselect">
            <option value="Option One" <?= $Validate->setSelect('myselect', 'Option One'); ?> >One</option>
            <option value="Option Two" <?= $Validate->setSelect('myselect', 'Option Two', true); ?> >Two</option>
            <option value="Option Three" <?= $Validate->setSelect('myselect', 'Option Three'); ?> >Three</option>
        </select>
    </div>
    <br>

    <input type="submit" value="Submit">
</form>