PersistentValidation - keeping your validation data after redirects

This article is also available in the following languages:
By binarycrafts
I decided to wrap this functionality in a component because when you have several forms in a view and each one relates to a different controller it's much easier to point the form to it's controller respective action and redirect back to the originating view.
But the validations don't persist. Here we use Session to persist them.
The main issue would be if you go back to the edit form of the ModelA your validated ModelB belongsTo. The chances are that after a ModelA->read() in the $this->data[ModelB] there already are some records. In this case you'll get a debug message:
"persistent data written in data[ModelB]. Find records moved to data[ModelBRecords]"
so that the forms are refilled correctly from the expected data[ModelB] value.
So thi sis basically a way to have a UserHobbyAdd form in a UserEdit view :) May sound twisted but I need this to add user related stuff in a user profile edit page...

This works but if someone finds a glitch please drop a comment.

Important note: the line "if (in_array($k, $controller->modelNames)" makes it mandatory for the User Controller to have the Hobby model in the $uses property!

Component Class:

<?php 
/*
 * Created on Oct 7, 2009
 * Created by Cosmin Cimpoi <cosmin@binarycrafts.com>
 */

class PersistentValidationComponent extends Object {
    var 
$components = array('Session');

    
//called before Controller::beforeFilter()
    
function initialize(&$controller$settings = array()) {
        
$this->controller =& $controller;
    }

    
//called after Controller::beforeRender()
    
function beforeRender(&$controller) {
        
$validations $this->Session->read('PersistentValidation');
        if (empty(
$validations)) return;
        foreach (
$validations as $k=>$v) {
            if (
in_array($k$controller->modelNames)) {
                if (empty(
$controller->data))  $controller->data = array();
                if (
array_key_exists($k$controller->data) && array_key_exists('0'$controller->data[$k])) {
                    
//    there's data for this model from an associaton query
                        
$controller->data[$k'Records'] = $controller->data[$k];
                }
                
$controller->data[$k] = $v['data'];
                
$controller->$k->validationErrors $v['errors'];
                
$this->Session->delete('PersistentValidation.'$k);
            }
        }
    }

    
//called before Controller::redirect()
    
function beforeRedirect(&$controller$url$status=null$exit=true) {
        foreach (
$this->controller->modelNames as $mn) {
            if (
count($controller->$mn->validationErrors)) {
                
$this->Session->write('PersistentValidation.'$mn'.data'$controller->$mn->data[$mn]);
                
$this->Session->write('PersistentValidation.'$mn'.errors'$controller->$mn->validationErrors);
            }
        }
    }
}

?>

Comments

  • Posted 08/01/11 02:06:31 PM
    I think you can even do this without using var $uses if redirecting to the controller of another model.

    If you change this line:

    $controller->$k->validationErrors = $v['errors'];

    to this:

    ClassRegistry::init($k)->validationErrors = $v['errors'];

    You also need to remove the next condition:

    if (in_array($k, $controller->modelNames)) { }, since it's no longer needed.
  • Posted 02/04/10 06:21:47 PM
    Would you be willing to provide more details about how to use this for less experienced Cake developers like myself? I think this would help me, but I'm not using beforeFilter or beforeRender in my controller, and am not sure where all the pieces go. A fleshed out example of how to use this would be very helpful.
  • Posted 01/06/10 07:29:58 AM
    It's not twisted. I have to do the same thing and I was just about to give up and do a multi-page form instead. If this works for me I'll be your best friend.

Comments are closed for articles over a year old