I'm building a custom validator that needs to validate the value from TWO form fields in the db in order to get this constraint to pass.
My question is this: the ContractValidator's validate method only has one $value in it's signature so how do I get access to the values from more than just a single field to do the validation?
Here is a typical custom validator:
namespace Acme\WebsiteBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class MyCustomValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
// check $value and return an error
// but in my case, i want the value from more than one form field to do a validation
// why? i'm checking that two pieces of information (ssn + dob year) match
// the account the user is registering for
}
}
Here's an example of a form class with some validations set:
namespace ACME\WebsiteBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Validator\Constraints\Collection;
use Symfony\Component\Validator\Constraints\MinLength;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Regex;
use ACME\WebsiteBundle\Validator\Constraints\UsernameAvailable;
class AccountRegistration extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('ssn', 'number', array(
'max_length' => 9,
'required' => true,
'error_bubbling' => true)
);
$builder->add('year_of_birth', 'choice', array(
'choices' => range(date("Y") - 100, date("Y")),
'required' => true,
'empty_value' => 'Select ...',
'label' => 'Year of Birth',
'error_bubbling' => true)
);
$builder->add('username', 'text', array(
'required' => true,
'error_bubbling' => true)
);
$builder->add('password', 'password', array(
'max_length' => 25,
'required' => true,
'error_bubbling' => true)
);
$builder->add('security_question', 'choice', array(
'empty_value' => 'Select ...',
'choices' => array(),
'label' => 'Security Question',
'required' => true,
'error_bubbling' => true)
);
$builder->add('security_question_answer', 'text', array(
'label' => 'Answer',
'required' => true,
'error_bubbling' => true)
);
}
public function getName()
{
return 'account_registration';
}
public function getDefaultOptions(array $options)
{
$collectionConstraint = new Collection(array(
'allowExtraFields' => true,
'fields' => array(
'ssn' => array(new MinLength(array('limit' => 9, 'message' => 'too short.')), new NotBlank()),
'year_of_birth' => array(new NotBlank()),
'username' => array(new NotBlank(), new UsernameAvailable()),
'password' => array(new NotBlank(), new Regex(array(
'message' => 'password must be min 8 chars, contain at least 1 digit',
'pattern' => "((?=.*\d)(?=.*[a-z]).{8,25})"))
),
'security_question' => array(new NotBlank()),
'security_question_answer' => array(new NotBlank()))
)
);
return array(
'csrf_protection' => true,
'csrf_field_name' => '_token',
'intention' => 'account_registration',
'validation_constraint' => $collectionConstraint
);
}
}
Any custom validator that extends ConstraintValidator
has access to the $context
property. $context
is an instance of ExecutionContext
that gives you access to submitted data:
Example:
<?php
namespace My\Bundle\MyBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class AppointorRoleValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
$values = $this->context->getRoot()->getData();
/* ... */
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With