2011-05-29

Multiples validaciones desde el Model y Form con CakePHP

In CakePHP, you define how your data should be validated by setting parameters on the validate property of your model. In version 1.2, there is an on option that can be set on a specific rule that, when set, is either create or update. This allows you to define different rules depending on the type of action being performed. That, in combination with the required and allowEmpty properties, give you a fair amount of control over different validation rules.
Despite that, I developed a slightly different approach that allows for different validation sets to be specified and to be cleanly separated from each other.
I override the validates method within a custom AppModel (stored in /app/app_model.php). The validates method is called when a save call is made or it can be called manually. This custom method can perform in one of two ways:

Method One: Action-specific Validation Sets

It'll first look to see if you have a validation set specified for the current controller action. For example, if you were in the edit action, it'd look for a property in the model called validateEdit. If it doesn't exist, it'll default back to using the normal validate property.
class User extends AppModel {
   // performs normal validation
   var $validate = array( ... ); 
   // used in an edit action like /users/edit/1
   var $validateEdit = array( ... ); 
   // used in a forgotpassword action like /users/forgotpassword
   var $validateForgotpassword = array( ... );
}
In that Forgot Password example, this would allow you to avoid performing your own checks for even basic calls and keep the logic tucked away in the Model.
class UsersController extends AppController {
   function forgotpassword() {
      $this->User->set($this->data);
      if ($this->User->validates()) {
         // send email to reset password and show success message
      }
   }
}
The thing I like about this is that the error messaging is handled by the validation and the FormHelper. (Although, a more noticable flash message near the top of the page is also helpful.)

Method Two: Custom Validation Sets

Alternatively, you may wish to specify a validation set manually before calling save or validates on a model. To do this, just specify a validationSet property on the model right before your call. The property will be unset immediately afterwards allowing normal validation rules to be applied.
Here's an alternate approach to the forgotten password example:
class User extends AppModel {
   var $validateForgotpassword = array( ... );
}

class UsersController extends AppController {
   function forgot() {
      $this->User->set($this->data);
      $this->User->validationSet = 'forgotpassword';
      if ($this->User->validates()) {
         // send email to reset password and show success message
      }
   }
}

The Code

Here is the custom validates method that pulls this all off:
function validates($options = array()) {
    // copy the data over from a custom var, otherwise
    $actionSet = 'validate' . Inflector::camelize(Router::getParam('action'));
    if (isset($this->validationSet)) {
        $temp = $this->validate;
        $param = 'validate' . $validationSet;
        $this->validate = $this->{$param};
    } elseif (isset($this->{$actionSet})) {
        $temp = $this->validate;
        $param = $actionSet;
        $this->validate = $this->{$param};
    } 
    
    $errors = $this->invalidFields($options);

    // copy it back
    if (isset($temp)) {
        $this->validate = $temp;
        unset($this->validationSet);
    }
    
    if (is_array($errors)) {
        return count($errors) === 0;
    }
    return $errors;
}

Link de la fuente

No hay comentarios: