18Apr/110
A post validator to define dependencies between fields
Today, I share a post validator that allows to define dependencies between fields. For example, it allows to define that the postal_code is only required if the country field value is FR.
So here is the class:
<?php
/**
* sfValidatorSchemaDependency allows to define dependency between fields
*/
class sfValidatorSchemaDependency extends sfValidatorSchema
{
/**
* Constructor.
*
* Available options:
*
* * affected_field: The field that is required or not
* * expected_values: A key/value array that represents the fields and their value
* that must be matched to set the affected_field as required
*
* @param string $affected_field The field that is required or not
* @param array $expected_values A key/value array that represents the fields and their value
* that must be matched to set the affected_field as required
* @param array $options An array of options
* @param array $messages An array of error messages
*
* @see sfValidatorBase
*/
public function __construct($affected_field, $expected_values, $options = array(), $messages = array())
{
$this->addOption('affected_field', $affected_field);
$this->addOption('expected_values', $expected_values);
parent::__construct(null, $options, $messages);
}
/**
* @see sfValidatorBase
*/
protected function doClean($values)
{
if (null === $values)
{
$values = array();
}
if (!is_array($values))
{
throw new InvalidArgumentException('You must pass an array parameter to the clean() method');
}
$affected_field = isset($values[$this->getOption('affected_field')]) ? $values[$this->getOption('affected_field')] : null;
$bAllValuesMatched = true;
foreach ($this->getOption('expected_values') as $field => $value)
{
// if a field has not the expected value
if (!isset($values[$field]) || $values[$field] != $value)
{
$bAllValuesMatched = false;
break;
}
}
// if every field has the expected value, and affected_field not defined
if ($bAllValuesMatched && !$affected_field)
{
// "affected_field is required" error
throw new sfValidatorErrorSchema($this, array(
$this->getOption('affected_field') => new sfValidatorError($this, 'required')
));
}
return $values;
}
}
And here is how to use it for our introduction example:
/**
* @see sfForm::configure()
*/
public function configure()
{
// ...
$this->mergePostValidator(new sfValidatorSchemaDependency('postal_code', array('country' => 'FR')));
}
Then, when the form will be validated, if the country field value is FR and if the postal_code field is empty, a required sfValidatorError will be attached to the postal_code field.
Note that you can define several dependencies, by passing several elements in the second parameter of the sfValidatorSchemaDependency constructor.