Jonathon Snook wrote about multiple validation sets in CakePHP and it reminded me how often we require rather different sets of validation rules for a single model. I have always enjoyed learning how others approached similar problems so I think I shall share mine too.
A very relevant example is the User model where we usually have multiple forms associated. E.g. sign up, profile updates, password reset, etc. Each form have a different set of fields while some share the same fields. My approach is to select a different set of fields for each “action” and modify the rules if required. This means I’ll keep a master set of rules for all the User model fields and call setValidate() for each “action”.
/**
* Set the default validation rules here.
*
* @var array
*/
protected $_validate = array(
'username' => array(
'empty' => array(
'required' => true,
'rule' => VALID_NOT_EMPTY,
'last' => true
),
'invalid' => array(
'rule' => '/^[\w]{3,30}$/',
'last' => true,
'on' => 'create'
),
'exists' => array(
'rule' => 'validateUniqueUsername',
'last' => true,
'on' => 'create'
)
),
'password' => array(
'empty' => array(
'required' => true,
'rule' => VALID_NOT_EMPTY,
'last' => true
),
'invalid' => array(
'required' => true,
'rule' => '/^.{6,30}$/',
'last' => true
)
),
...
);
/**
* Sets just enough fields for validation.
*
* @param array $fields List of field names to validate against. If no param
* passed, all fields will be included.
* @author Derick
*/
function setValidate($fields = null) {
if ($fields === null) {
$this->validate = $this->_validate;
} else {
$this->validate = array();
foreach ($fields as $f) {
if (isset($this->_validate[$f])) {
$this->validate[$f] = $this->_validate[$f];
}
}
}
}
This is a simplified example in my User model where I have the register() function to validate only the fields required for sign up and the updateProfile() function which uses another set of fields with slight different requirement.
function register($data) {
$fields = array('username', 'password', ...);
$this->setValidate($fields);
$this->save($data, true, $fields);
}
function updateProfile($data) {
$fields = array('password', ...);
$this->setValidate($fields);
// derick: allow user to left password field empty
unset($this->validate['password']['empty']);
$this->validate['password']['invalid']['allowEmpty'] = true;
$this->save($data, true, $fields);
// derick: you can also call this again to "reset" to the default set of
// rules but usually we don't need this
$this->setValidate();
}
In other words, I only update the $validate array in the model when required. Some might think it is dangerous since there is a chance of saving data without validation but this works for me. What do the rest of you do?