Symofny 1.4 form: add validator for alternative email or secret question

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 🙂