AjaxHandler

The Ajax Handler is a CakePHP Component that processes and handles AJAX requests. It determines what action should be dealt as an AJAX call, applies the appropriate filters, prepares the data for a response and responds with the appropriate headers.

Displaying form errors as a list in CakePHP

Tuesday, January 6th 2009, 2:11am
Topics: Tutorials, CakePHP
Tags: CakePHP, Tutorial, Errors, Request Handler, Validation, Model
Comments: 12
Permalink - Tinylink

When a form is submitted in CakePHP, any errors that fail the model validation are displayed after each respective input field. But if you're like me and really dislike that structure and output, and would rather have your errors displayed in a list above the form (an example would be my contact form), then this is how you would achieve it. In the example we will be doing a login for the Users controller (do note that I am not using the Auth component, this is just a rough example). Lets begin by creating a file called errors.ctp and placing it in your views/elements/ folder.

<?php // views/elements/errors.ctp
if (!empty($errors)) { ?>
<div class="errors">
    <h3>There are <?php echo count($errors); ?> error(s) in your submission:</h3>
    
    <ul>
        <?php foreach ($errors as $field => $error) { ?>
        <li><?php echo $error; ?></li>
        <?php } ?>
    </ul>
</div>
<?php } ?>


Validation in the Model
For any form validation to work, we must declare a validation scheme within the respective model, in our case its the User model. Since this is a login form, the only validation we will need is for a username and password. The rules we will be applying is that both the username and password must not be empty. Once we have the validation setup, the next step is to setup the Users controller.

<?php
class User extends AppModel {

	var $validate = array(
		'username' => array(
			'notEmpty' => array(
				'rule' => 'notEmpty',
				'message' => 'Your username is required'
		)),
		'password' => array(
			'notEmpty' => array(
				'rule' => 'notEmpty',
				'message' => 'Your password is required'
		)),
	);
	
}
?>


Setting up the Controller
In the login action we will be using the RequestHandler component to check for a form submission (this is a better approach then doing isset/!empty on $this->data). If a post is successful, we will save the form data to the User model to run it against the validation. Lastly, we need to be able to display the errors in the view, so we will set() them to $errors by calling the $this->User->validationErrors. The $errors variable is then passed to the errors.ctp element template, which in turn displays all the errors found.

<?php // controllers/users_controller.php
function login() {
    if ($this->RequestHandler->isPost()) {
        $this->User->set($this->data);
    
        if ($this->User->validates()) {
        	if ($this->User->verifyLogin($this->data)) {
				// Process information
			}
        } else {
			// Didn't validate
		}
    }

    $this->set('errors', $this->User->validationErrors);
}

// models/user.php
function verifyLogin($data) {
	$user = $this->find('first', array(
		'conditions' => array(
			'User.username' => $data['User']['username'],
			'User.password' => md5($data['User']['password'])
		)
	));
	
	if (!empty($user)) {
		return $user;
	} else {
		$this->invalidate('', 'No user was found with those login credentials');
	}
	
	return false;
} ?>


The two most important things to note is $validationErrors and the invalidate() method. The $validationErrors property is a list of all the error messages in the form for the corresponding input fields; it's called from each respective model. The method invalidate() is used to trigger a custom error that is not part of the $validate scheme for the model. Now lets look back at the controller where the verifyLogin() method is called. If that method fails (returns false), the login fails and no processing is made. On the other hand if the method returns true, lets continue and log them in.

Displaying my errors in the View
Now that we have the validation set, the errors template created and the form processing complete, the last task is to display the errors in the view. Since the controller is already setting the errors into the view, we just need to include the element, and to do that we will use the $this->element() method within the view. Just place this element in the location you want your errors to display.

<?php echo $this->element('errors', array('errors' => $errors)); ?>


Now if you have tested the form, you will notice that the errors are still showing up after the input field. To fix this, we have to disable the errors on the input by setting it to false.

<?php echo $form->input('username', array('error' => false)); ?>


Conclusion
This was a bit more lengthy then I expected, but I hope it enlightened you on how to use and display form errors. You also received a bit more knowledge on how the invalidate() and invalidFields() method work (hopefully ;)). If you have any questions please comment or send me an email, or take a gander at the CakePHP API and Cookbook.
Related Entries:

12 Comments

10 / 2 = ?
Allowed: [code] [b] [i] [u]
  • k00k
    twitter.com/k00k
    Jan 27th 2009, 16:41
    1 Thanks so much, this is exactly what I needed. Errors can be a bit voodoo if you haven't really played with them.
  • Roland
    Feb 12th 2009, 19:42
    2 thanks!

    Also great to use with AJAX to send all the validation errors as xml or json!
  • Rahil Sondhi
    rahil.ca
    Apr 28th 2009, 10:28
    3 Thanks Miles, this is just what I needed!
  • How I Lost Thirty Pounds in Thirty Days
    jpweightlossblog.com
    May 3rd 2009, 19:50
    4 Hi, good post. I have been pondering this issue,so thanks for sharing. I'll definitely be subscribing to your blog.
  • Saliem
    Aug 6th 2009, 21:10
    5 thanks for the explanation. grouping all of the errors together is a much better idea. i also didnt know about the validationerrors property. that will be useful.

    thanks again.
  • Daniel
    theworldofdan.co.uk
    Nov 7th 2009, 10:10
    6 Thank you thank you thank you - this is fantastic and just what I need.

    Not only does it solve a usability problem, but it also means that I'm not going to have to have lots of empty $form->error() elements scattered all over my page.
  • Alex in San Diego
    teamaguilar.com
    Feb 16th 2010, 12:37
    7 Error management in cake is bit weird.
  • Christopher Vrooman
    Feb 17th 2010, 12:14
    8 Miles,

    how do you handle validation when you're using two or models in the form? I've run into the situation where only the first model's errors show up. Then, once they all validate properly, the next model's errors appear and so on. It would be nice to see all the errors at once to avoid having to keep resubmitting the form over and over.
  • Stepas
    itworks.lt/blog
    Oct 14th 2010, 01:00
    9 @Christopher Vrooman,

    you should use $model->saveAll($this->data, array('validate' => 'first',));

    This way all the models are validated prior to saving them one-by-one. Of course, you must be using $model->invalidate(); correctly.

    If you don't want to use saveAll(), I guess you will have to play with $this->model->validationErrors. But that's nasty :)
  • Marius
    Apr 6th 2011, 13:31
    10 You can also incorporate it with AuthComponanet.
    Just set this ctp as flash element and using Session->setFlash() with $params pass all the listed items.

    Works nice for me. :)
  • Taxi Torrevieja
    taxisamba.com
    Dec 6th 2011, 02:22
    11 Excellent, that's what I was looking for and spent days until I found this! Thanks, Mimi