Symfonic Let’s talk about Symfony stuff!

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.

About Grégoire Marchal

Another Symfony developer...
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment


No trackbacks yet.