Form Validation in CakePHP

Form Validation in CakePHP Image 1

Form Validation is an essential task in any online application, its also an incredibly dull, tedious and repetitive task but with CakePHP you can cut down the time and effort you spend validating your form data. In a standard PHP application you will normally display the form for user input, try to validate the data, if errors exist redisplay the form showing the errors whilst keeping the data that was already submitted and go through the process again until the data successfully validates.

In this article I'm going to through the basics of creating a Model, baking a sample application and explain how you can use CakePHP to automatically validate your data.

SQL, Model and Baking

For simplicity I am going to use the 'posts' table from my previous articles, if your starting from scratch the SQL statement for that table is shown below:

CREATE TABLE `posts` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`title` VARCHAR( 255 ) NOT NULL ,
`slug` VARCHAR( 255 ) NOT NULL ,
`text` TEXT NOT NULL ,
`created` DATETIME NOT NULL ,
`modified` DATETIME NOT NULL ,
`status` TINYINT( 1 ) NOT NULL DEFAULT '1'
);

Next up is the 'post' model file, CakePHP works by defining validation rules in the Model file, if you have a look at the manual you will see that CakePHP has a number of preset validation rules which include VALID_NOT_EMPTY, VALID_NUMBER, VALID_EMAIL and VALID_YEAR. These are self explanatory and are used in the model like so:

// file: /app/models/post.php
class Post extends AppModel {
    // name of model, good practice to include
    var $name = 'Post';
    // validation rules
    var $validate = array(
        'title'=>VALID_NOT_EMPTY,
        'slug'=>VALID_NOT_EMPTY,
        'text'=>VALID_NOT_EMPTY
    );
}

An array is created called $validate which contains the name of the database field which requires validation and a rule that will be used to validate it. You can also use your own regular expressions but for the time being we will just use the preset ones. In this example the title, slug and text fields will need to contain information before the form will be successfully submitted.

Once the Model file is complete, bake the 'posts_controller.php' file and the view files. If you dont know how to do this then please read my previous article on using the Bake script. Check that everything is working by going to "http://cakephp/posts/add" and try to submit the form without entering anything. The form will be redisplayed with error messages that correspond to the validation rules that are defined in the model.

Validation

To make use of this automatic validation you need to use the "HTML" helper to create your forms, keeping with conventions you create a form input field using the $html->input('Model/fieldname', 'attributes') method and directly below use the $html->tagErrorMsg('Model/fieldname', 'error message to display') to display an error message if the form does not validate.

// file: /app/views/posts/add.thtml
// form input helper
echo $html->input('Post/title', array('size' => '60'));
// display an error message if data doesn't validate
echo $html->tagErrorMsg('Post/title', 'Please enter the Title.');

When calling the Model->save() method on your submitted data, CakePHP will automatically check your Model file and try to validate the data, if it validates the form data will be inserted into your database, a flash message is set and you will be redirected to the index page. If the data does not validate a flash message is set and the form is redisplayed and because you have used the html helper to build your forms, data that was submitted will re-populate the form.

// file: /app/controllers/posts_controller.php
// try to save the data, returns false if it doesn't validate
if ($this->Post->save($this->data)) {
    // set success message
    $this->Session->setFlash('The Post has been saved');
    // redirect the user
    $this->redirect('/posts/index');
} else {
    // set error message
    $this->Session->setFlash('Please correct errors below.');
}
Form Validation in CakePHP Image 2

Custom Validation

You can also use custom validation to do more extensive checks, for example i want to check that the post slug i have entered is not already in the database. If a post exists with the same slug name i want to redisplay the form with a custom error message. The code for doing this is as follows:

// file: /app/controllers/posts_controller.php
function add() {
	// default slug error message
	$this->set('slug_error', 'Please enter the Slug');
	
	// if form is not empty
	if (!empty($this->data)) {
		// post is currently valid
		$postValid = TRUE;
		//if the post is not empty
		if(!empty($this->data['Post']['slug'])) {
			// try finding a post in the database with the slug name
			$post = $this->Post->findBySlug($this->data['Post']['slug']);
			// if a post has been found
			if(!empty($post)) {
				// invalidate the slug, this will enable the error msg in the view
				$this->Post->invalidate('slug');
				// set the slug error message
				$this->set('slug_error', 'A Post with this slug already exists');
				// invalidate the post
				$postValid = FALSE;
			}
		}
		
		// only continue if the post is valid
		if($postValid) {
			// try saving the post, will check validation rules in model
			if($this->Post->save($this->data)) {
				$this->Session->setFlash('The Post has been saved');
				$this->redirect('/posts/index');
			}
		}
	}
}

// file: /app/views/posts/add.thtml
// display the error message that was set in the controller
echo $html->tagErrorMsg('Post/slug', $slug_error);

Below is a screen shot of the custom error message in action:

Form Validation in CakePHP Image 3

When using custom validation you use the $this->Model->invalidate('fieldname') method to enable the error message in the view. Be careful when going down this route because when you use invalidate() it does not stop the save operation and so thats why i have used a boolean variable above to determine whether or not i can save the data. For example this will NOT work:

// if title is empty
if(empty($this->data['Post']['title'])) {
    // invalidate field
    $this->Post->invalidate('title');
}

// the save operation will go ahead regardless of the above invalidate()
if($this->Post->save($this->data)) {
    // success
} else {
    // error
}

Wrapping Up

This has been a pretty quick look at form validation in CakePHP but as you can see its very powerful and easy to use. Simply setup all your validation rules in the $validate array of each of your Model files and use the html helpers to generate error messages in your views and CakePHP will take care of the rest. If you want more complex validation rules you can build up your own regular expressions to validate the data or you can use your own custom validation in the controller to make checks e.g. in user registration making sure a username is not already taken in the database.

Copy of my CakePHP app directory with all the files in this article.

Posted on 14th March 2008
6 years, 8 months, 1 week, 1 day ago

comments powered by Disqus