4
votes

I'm trying to create a form that change the validation of a field based on the select option from the html form field.

Ex: if user select a option 1 from drop down field "options", I want the field "metric" to validate as sfValidatorInteger. If user select option 2 from field "options", I want the field "metric" to validate as sfValidatorEmail, etc.

So inside the public function configure() { I have the switch statement to capture the value of "options", and create the validator based on that value returned from the "options".

1.) How do I capture the value of "options" ? I've tried:

$this->getObject()->options
$this->getTaintedValues()

The only thing that's currently working for me is but it's not really MVC:

$params = sfcontext::getInstance()->getRequest()->getParameter('options');

2.) Once I've captured that information, how can I assign the value of "metric" to a different field? ("metric" is not a real column in db). So I need to assign the value of "metric" to different field such as "email", "age" ... Currently I'm handling this at the post validator like this, just wondering if I can assign value within the configure():

$this->validatorSchema->setPostValidator(new sfValidatorCallback(array('callback' => array($this, 'checkMetric'))));

public function checkMetric($validator, $values) {

}

Thanks!

3

3 Answers

6
votes

You want to use a post validator. Try doing something like this in your form:

public function configure()
{
  $choices = array('email', 'integer');
  $this->setWidget('option', new sfWidgetFormChoice(array('choices' => $choices))); //option determines how field "dynamic_validation" is validated
  $this->setValidator('option', new sfValidatorChoice(array('choices' => array_keys($choices)));
  $this->setValidator('dynamic_validation', new sfValidatorPass()); //we're doing validation in the post validator
  $this->mergePostValidator(new sfValidatorCallback(array(
    'callback' => array($this, 'postValidatorCallback')
  )));
}

public function postValidatorCallback($validator, $values, $arguments)
{
   if ($values['option'] == 'email')
   {
     $validator = new sfValidatorEmail();
   }
   else //we know it's one of email or integer at this point because it was already validated
   {
     $validator = new sfValidatorInteger();
   }
   $values['dynamic_validation'] = $validator->clean($values['dynamic_validation']); //clean will throw exception if not valid
   return $values;
}
0
votes

1) In a post validator, values can be accessed by using the $values parameter. Just use $values['options'] and it should be fine... or did you want to access this values from another part of you code? $this->getObject()->widgetSchema['options'] should work too I think, once your form is bound to an object.

2) The configure() method is called at the end of the form constructor, so values are not bound nor accessible yet, unless you are initializing your form with an object from the db (which does not require any validation). But if you want to initialize your form from $_POST, a post validator is definitely the way to go IMHO.

0
votes

I got the validation error to appear alongside the field by throwing a sfValidatorErrorSchema instead of a sfValidatorError.

$values['dynamic_validation'] = $validator->clean($values['dynamic_validation']);

…becomes…

try
{
    $values['dynamic_validation'] = $validator->clean($values['dynamic_validation']);
}
catch(sfValidatorError $e)
{
    $this->getErrorSchema()->addError($e, 'dynamic_validation');
    throw $this->getErrorSchema();
}

Not sure if this is the best way to get this result, but it seems to be working for me at the moment.