Joseph Hallenbeck


November 25, 2013

Improving Upon CodeIgniter’s Validation

Filed under: Software Development — Tags: , , , — Joseph @ 9:49 am

Flattr this!

In this article I plan on addressing CodeIgniter’s shortfalls as a framework for validating objects and introduce a method for improving the validator classes re-usability.

When To Validate?

The answer to this question is simple: whenever we are dealing with input. The (incorrect) assumption that CodeIgniter and many web-applications make is that user input comes in the form of GET and POST variables and a considerable amount of effort goes into validating inputs via these routes. However, GET and POST are not the only sources for user input. User input can come via external sources such as tying into a remote API, an RSS feed, or from the database itself. From each of these sources we could get an invalid state. In the case of the remote API or RSS feed this is easy to understand. The API could change, or the RSS feed could be malformed. In the case of the database the issue typically appears when data is stored into the database under one context but is then accessed with a different expectation.

Take for example a database with the following table:

CREATE TABLE IF NOT EXISTS `persons` (
  `id` int(10) NOT NULL AUTO_INCREMENT,  
  `name` varchar(256) NOT NULL,
  `birthdate` DATE NOT NULL,  
PRIMARY KEY (`id`) ) ;

Now say that we inserted a person with name “Bob” and birthdate “1975-01-01.” This passes the validator going into the database, but later on we pull this row from the database and use it to construct a plain PHP object with properties id, name, and birthdate which we pass onto the view and attempt to output the birthdate with the following line:

echo date('Y-m-d', $person->birthdate);

This is going to cause an error. Why? Because the date function is expecting the second parameter to be a UNIX timestamp, but birthdate is already a formatted date string. Now, we could solve this by changing the schema of the database or changing the schema of the person object, but it is important to note that even if we did fix the disparity between the two we would still not fix the issue that it is possible for the person object to exist in an invalid state.

So my answer is to when should validation occur is during object instantiation and setting. The properties of the object should not be able to be set to a value that the object cannot accept. This places validation clearly into the realm of the “M” in “MVC.”

Form Validation in CodeIgniter

CodeIgniter’s documentation offers a form validation class that makes the above mistake very clearly. It can only validate the POST super global and doesn’t really offer much of a solution towards validation of objects themselves. Furthermore, their example controller oddly mixes the issue of object validation, and thus business logic, inside the controller which tends to create in many CI application fairly bloated controllers:

public function index()
{
  $this->load->helper(array('form', 'url'));
  $this->load->library('form_validation');

  $this->form_validation->set_rules('username', 'Username', 'callback_username_check');
  $this->form_validation->set_rules('password', 'Password', 'required');
  $this->form_validation->set_rules('passconf', 'Password Confirmation', 'required');
  $this->form_validation->set_rules('email', 'Email', 'required|is_unique[users.email]');

  if ($this->form_validation->run() == FALSE) {
    $this->load->view('myform');
  } else {
    $this->load->view('formsuccess');
  }
}

I cannot offer a solution towards adapting the validation class to be fully object operating without a heavy rewrite of the class, but we can move this obtuse validation into a distinct model that encapsulates this behavior away from the controller.

Introducing the Abstract Validator Class

We can get the validation logic out of the controller by moving it into a Validator class. We begin with an abstract base class since each form will need their own validator classes:

abstract class Validator extends CI_Model 
{ 
  protected $rules = array(); 
  protected $fields = array();

  # Get keys of fields.
  public function getStructure()
  {
    return array_keys( $this->fields );
  }

  # Validate $_POST against the rules and fields.
  public function validate()
  {
    foreach( $this->rules as $key => $rule )
    {
      $this->form_validation->set_rules( $key, $this->fields[$key], $rule );
    }

    return $this->form_validation->run( $this );
  }   
}

We take advantage of the fact that the CI god to access the form_validation object inside the Validator instance to create the validate method which merely sets the validation rules and then runs them. The Validator has two properties $rules and $fields which we will use in sub-classes to provide the CI_Validator rules and fields strings. We can transform the above controller into the following subclass:

class LoginValidator extends Validator
{
  protected $rules = array(
                       'username' => 'callback_username_check',
                       'password' => 'required',
                       'passconf' => 'required',
                       'email' => 'required|is_unique[users.email]');
  protected $fields = array(
                        'username' => 'User Name',
                        'password' => 'Password',
                        'passconf' => 'Password Confirmation',
                        'email' => 'E-Mail');

  public function username_check( $name )
  {
    return $this->users->check_username( $name );
  }
}

Here we can see how the rules and fields are used as well as how we can extend the Validator class to add additional unique callback validations. This simplifies the controller significantly:

public function index() { 
  $this->load->library('form_validation');
  $this->load->model('loginvalidator');

  if ( $this->loginvalidator->validate() ) {
    $this->load->view('myform');
  } else {
    $this->load->view('formsuccess');
  }
}

The business logic is now gone and the controller is back to focusing on what it’s supposed to be doing — load resources and running paths.


November 19, 2013

Building Pecunia – Introduction

Filed under: Software Development — Tags: , , , — Joseph @ 9:49 pm

Flattr this!

What is Pecunia?

I have been keeping my own personal accounts for some time in a progressively growing spreadsheet that after one decade of use, multiple files, and dozens of worksheets. The entire thing is quite a mess. My solution? Build an app for it! Pecunia will be a simple budgeting application designed from the ground up for keeping track of monthly budgets, annual budgets, and keeping a ledger of individual expenses. With a little bit of work, I should be able to turn it into a multi-user application to launch as an extension on Kynda.net for public use as well as an open source repository on Bitbucket.

This also gives me an excuse for a long series of posts going through the steps necessary to take a spread sheet, abstract it’s logic into models, and implement it’s functionality into a useful application.

Resources

Pecunia will be built using the following resources:

  • PHP 5.4
  • Apache 2.2
  • MySQL 5.5
  • Silex Laraval 4

Update: January 22, 2014

After some consideration, I am opting away from Silex towards using Laraval 4. It is not that I have suddenly found a dislike for Silex, rather I love working with it, but that I would like to try my hands at the “latest and greatest” to see what the big deal is about and to add another tool to my retinue.




Copyright 2011 - 2017 Joseph Hallenbeck Powered by WordPress