The symfony Cookbook

How to implement a conditional validator?

You are currently browsing
the website for symfony 1

Visit the Symfony2 website


About

You are currently reading "The symfony Cookbook" which is licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License license.

Master symfony

Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).
trainings.sensiolabs.com

Books on symfony

Learn more about symfony with the official guides.
books.sensiolabs.com

L'audit Qualité par SensioLabs

200 points de contrôle de votre applicatif web.
audit.sensiolabs.com
symfony training
Be trained by symfony experts
Feb 21: Köln (Getting Started with Symfony2 - English)
Feb 27: Köln (Mastering Symfony2 - English)
Mar 05: Köln (Web Development with Symfony2 - Deutsch)
Mar 05: Montreal (Web Development with Symfony2 - English)
Mar 05: Montreal (Getting Started with Symfony2 - English)
and more...

Search


powered by google
You are currently browsing "The symfony Cookbook" in English for the 1.2 version - Switch to version: - Switch to language:
Creative Commons License This work is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License.
Translation of this work into another language is explicitly allowed.
This version of symfony is not maintained anymore.
If some of your projects still use this version, consider upgrading as soon as possible.

A classic login form is composed of two fields: a username and a password.

The validation rules are quite straightforward:

Here is the first implementation of the login form:

class loginForm extends sfForm
{
  public function configure()
  {
    $this->setWidgets(array(
      'username'  => new sfWidgetFormInput(),
      'password'  => new sfWidgetFormInputPassword(),
    ));
 
    $this->setValidators(array(
      'username' => new sfValidatorString(array('required' => true)),
      'password' => new sfValidatorString(array('required' => true)),
    ));
 
    $this->widgetSchema->setNameFormat('login[%s]');
  }
}

This form enforces the requirements on the username and password fields but does not check the correctness of the password.

First implementation of the login form

The password can only be validated if you also have access to the username value. But as you might know, a validator attached to a field does not have access to the other values of the form.

When a validator relies on another submitted value, you need to create a post validator. A post validator is executed after all other validators and is given the whole array of cleaned up values.

To check the password, we will implement a simple callback validator to ensure that the submitted password is equal to the username. Of course, for his real project, you will have to call the model layer to do the actual work.

Here is the modified login form with the added post validator:

class loginForm extends sfForm
{
  public function configure()
  {
    $this->setWidgets(array(
      'username'  => new sfWidgetFormInput(),
      'password'  => new sfWidgetFormInputPassword(),
    ));
 
    $this->setValidators(array(
      'username' => new sfValidatorString(array('required' => true)),
      'password' => new sfValidatorString(array('required' => true)),
    ));
 
    $this->widgetSchema->setNameFormat('login[%s]');
 
    // add a post validator
    $this->validatorSchema->setPostValidator(
      new sfValidatorCallback(array('callback' => array($this, 'checkPassword')))
    );
  }
 
  public function checkPassword($validator, $values)
  {
    if ($values['password'] != $values['username'])
    {
      // password is not correct, throw an error
      throw new sfValidatorError($validator, 'Invalid password');
    }
 
    // password is correct, return the clean values
    return $values;
  }
}

Now, the form works as expected, but there is still one small problem: if you submit a random password without entering a username, you will have two error messages: a required error for the username and a global error for the wrong password.

Two error messages

But wait a minute, if the username is empty, we don't need to validate the password. Let's change the form to only validate the password if there is a username submitted. This is quite simple, as we just need to ensure that $values['username'] is not empty in the post validator callback:

public function checkPassword($validator, $values)
{
  // before validating the password, check that the username is not empty
  if (!empty($values['username']) && $values['password'] != $values['username'])
  {
    throw new sfValidatorError($validator, 'Invalid password');
  }
 
  return $values;
}

Instead of having a global error, we would rather have the 'Invalid password' error message just above the password field.

That's quite easy to accomplish by throwing an error bound to the password field instead of throwing a global error:

public function checkPassword($validator, $values)
{
  if (!empty($values['username']) && $values['password'] != $values['username'])
  {
    $error = new sfValidatorError($validator, 'Invalid password');
 
    // throw an error bound to the password field
    throw new sfValidatorErrorSchema($validator, array('password' => $error));
  }
 
  return $values;
}

Error message bound to a field

Questions & Feedback

If you find a typo or an error, please register and open a ticket.

If you need support or have a technical question, please post to the official user mailing-list.