Validate Data within A Model using CodeIgniter and MY_Model

CodeIgniter’s validation library is amazing out of the box and will save any developer an absolute ton of time. However, as CodeIgniter is an MVC framework it’s validation library does encourage data validation directly in controllers – which of course for the “MVC Nazis” out there is against strict MVC principals. So, data validation should strictly happen at the model layer, not in the controller. Moving data validation to the model has a few benefits  – it allows your application to follow to coveted “Fat Model, Skinny Controller” pattern and allows you to validate other data types (not just posted data). Again, you can technically keep things neat by saving your validation rules to a config file and keeping validation in the controller, but that still breaks the MVC principals.

In order to achieve this, I’ll assume you’re using Jamie Rumblelow’s truly epic base model, we have a generic Model that deals with “jobs” and your database is all setup. Validating data is mentioned on in passing a few times on the web, but there currently, doesn’t seem to be a definite guide explaining how to implement such functionality within your application. To keep things simple, I’ll have a basic form that contains 3 fields that are saved to a database – reference, title, owner.

Creating the Model

Now, create a blank model and make it extend the MY_Model class as normal and move the validation fields array (normal found in your controller) to the top of you model (I’ve kept the rules very simple, your rules can contain callbacks for example):

defined('BASEPATH') OR exit('No direct script access allowed');

class Job_m extends MY_Model {

public $validate = array(
        array(
            'field' => 'reference', 'label' => 'Job Reference', 'rules' => 'trim|required|max_length[15]|xss_clean'
        ),
        array(
            'field' => 'title', 'label' => 'Job Title', 'rules' => 'trim|required|max_length[95]|xss_clean'
        ),
        array(
            'field' => 'owner', 'label' => 'Owner Name', 'rules' => 'trim|required|max_length[500]|xss_clean'
        )
    );

}

You’ll notice that at the top of the MY_Model has the following variable set:

protected $validate = array();

So, we’re now simply passing this array to MY_Model when we attempt to insert data. As this model has some great support for this, there’s not a lot more to do – the majority of the code is written for us – you’ve just linked MY_Model to the native CodeIgniter validation class.

Create A Controller

Now, create the controller as follows – it will have a single “create” method that adds a new job to the database:

defined('BASEPATH') OR exit('No direct script access allowed');

class Job extends CI_Controller
{
public function create()
{
    if ($input = $this->input->post())
    {
        if ( $data = $this->job_m->insert( $input ) )
        {
            $this->session->set_flashdata('success', 'Job Added!');
            redirect('jobs/frontend');
        }

    }
    else
    {
        $the_job = array();
    }

    foreach ($this->job_m->fields() as $field)
	{
		$the_job[$field] = set_value($field);
	}

	$this->template
        ->set('job', $the_job)
        ->build('jobs/list', $this->data);

}
}

If you’re familiar with CodeIgniter (which I’m sure you are if reading this) this code is easy to follow – all the line number I refer are highlighted above.

Firstly in line 7, check to see if the user has posted the form, otherwise, create an empty array titled “the_job”. In line 9, attempt to insert the posted data in the database. If the data passes the validation rules set at the top of the Job model, from earlier redirect the user. If the user has failed validation, you;d be on line 16.

Updating MY_Model

In line 21 onwards, use the set_value method to populate the form fields in the view, jobs/list – as we are passing an array of values called $the_job to it! The only difference is a new method called “fields()” on line 21. This is simply a neater way to get all the validations rule field names (that of course map to our database field names) into an array. I originally found the code that follows on the Codeigniter forums a while ago, but have lost the thread unfortunately (I’ll try to find it, so I can reference the poster who had the idea). It’s not earth shattering as it’s simple loop that returns an array:

public function fields()
{
    $keys = array();
    if ($this->validate)
    {
    	foreach ($this->validate as $key)
    	{
    		$keys[] = $key['field'];
    	}
    }
    return $keys;
}

The poster recommends it goes in your own Model (E.g. our Jobs model), but as it will be useful to use this technique in other models, I’ve placed it in the MY_Model – keeping things nice and “DRY”.

The Resulting View

On line 26, we’re simply passing the “the_job” array to a view using Phil Sturgeon’s popular template library, that makes working with templates and layouts super silky (in my opinion of course). It means we can reference items in the view using the familiar $job[‘name’] syntax. So, the view would simply look as follows:

echo form_open($this->uri->uri_string());

echo form_fieldset('Job Info.');

echo form_label('Job Ref.', 'reference');
echo form_input('reference', $job['reference']);

echo form_label('Job Title', 'title');
echo form_input('title', $job['title']);

echo form_label('Job Owner', 'owner');
echo form_input('owner', $job['owner']);

echo form_fieldset_close();

echo form_close();
Bonus – Editing Records

That’s it, all the view is doing is re populating the form using the values from the job array. The above option applies to creating a new record, adapting this handle editing records could be easily applied by first fetching the record from the database. So, before the checks on line 7, you would have something along the lines of:

// $id would come from the URI
$the_job = $this->job_m->get( $id );

You’d also need to adjust the code within the loop and 21 to account for the fact that we want to set form values based upon data from the database (this means you can use the same view file and form to create and edit records), so the code to set each form value would be:

$the_job[$field] = set_value($field, $the_job[$field]);

You’ll also notice the methods to save and get a job in our model aren;t mentioned there at all. They simply come from the amazing MY_Model that is doing all the work for us.

If you haven’t already tried Jamie Rumblelow’s MY_Model, or base model get on it immediately.

Published by

Rob Allport

Web Developer based in Stoke-on-Trent Staffordshire Google+ - Twitter

5 thoughts on “Validate Data within A Model using CodeIgniter and MY_Model”

  1. how to use validation using callback, I have try this validation, but its return ‘Unable to access an error message corresponding to your field name.’

    thx

  2. I solve this with, just create callback in controller, and keep logic validation in model. 🙂

    Like this.
    In Model:
    function validate() {
    $this->form_validation->set_rules(‘sample1’, ‘Sample 1’, ‘callback_check_sample’);
    if ($this->form_validation->run()) {
    return TRUE;
    } else {
    return FALSE;
    }
    }

    function real_check_sample() {
    if($this->post->input(‘sample’) == ‘test’) {
    return TRUE;
    } else {
    return FALSE;
    }
    }

    ///// In Controller:
    function sample_form() {
    if($this->sample_model->validate()) {
    //ok
    } else {
    // not ok
    }
    }

    function check_sample() {
    return $this->sample_model->real_check_sample();
    }

  3. Really great article, i am just starting with Jamie’s MY_Model and practical examples like this help a lot, so thanks for taking the time to share it!

    How would you handle the validation rules in a situation where the same model needs to be used by different actions. For example a user_model could be used by the login action and the create user action, both having different forms and validation rules. Any advice on this is appreciated!

    Thanks again!

Leave a Reply

Your email address will not be published. Required fields are marked *