I had a case recently – the registration form with alternative email and secret question.
In this form user needed to enter alternative email OR/AND secret question for password reminder function – at least one field must be filled. So I used approach of adding form validators dynamically.
I found special validator for such OR-cases (sfValidatorOr) not so flexible for my needs so I decided to override form ‘bind’ method.
/**
* @param array $taintedValues
* @param array $taintedFiles
*/
public function bind(array $taintedValues = null, array $taintedFiles = null)
{
// Checking two important field for their presence
if (empty($taintedValues['question']) && empty($taintedValues['alt_email'])) {
// Here you can put validator on any of fields you're checking, I decided put it on first
$this->validatorSchema['alt_email'] = new sfValidatorString(array('required' => true), array('required' => 'Please enter alternative email or secret question'));
}
if ($taintedValues['question']) {
// String validator for questions could be any kind
$this->validatorSchema['question'] = new sfValidatorString();
// but when user entered a question then Answer become required
$this->validatorSchema['answer'] = new sfValidatorString(array('required' => true), array('required' => 'Please give us an answer on your secret question'));
}
// User can add alternative email too, so we're checking it
if ($taintedValues['alt_email']) {
$this->validatorSchema['alt_email'] = new sfValidatorAnd(array(
// Checking whether email is valid
new sfValidatorEmail(array('required' => false, 'trim' => true)),
new sfValidatorString(array('required' => false, 'max_length' => 255)),
// Checking for presence in our Database
new sfValidatorDoctrineUnique(
array('model' => 'sfGuardUserProfile', 'column' => 'alt_email'),
array('invalid' => 'This email is already used. Please choose another one.'))
),
array('required' => false), // This is important! After check above is passed the alt_email become not required
array('invalid' => 'Please enter correct email address')
);
}
// And, of course, move forward with all other validators we have
parent::bind($taintedValues, $taintedFiles);
}
Maybe someone has elegant solution with sfValidatorOr – would be very appreciated to have a look on it 🙂