Создание Symfony 2 Custom Validator, использующего несколько полей - программирование
Подтвердить что ты не робот

Создание Symfony 2 Custom Validator, использующего несколько полей

Я создаю специальный валидатор, который должен проверять значение из полей формы TWO в db, чтобы получить это ограничение.

Мой вопрос таков: метод проверки 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
  }
}

Здесь приведен пример класса формы с некоторыми проверками:

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
    );
  }  
}
4b9b3361

Ответ 1

Любой пользовательский валидатор, который расширяет ConstraintValidator, имеет доступ к свойству $context. $context - это экземпляр ExecutionContext, который дает вам доступ к предоставленным данным:

Пример:

<?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();
        /* ... */
    }
}

Ответ 2

Вам нужно использовать CLASS_CONSTRAINT, как описано в кулинарных книгах. Затем вы передаете весь класс и можете использовать любое свойство этого класса. В приведенном выше примере это означает, что вместо $value, имеющего одну строку/целое число, это будет весь объект, который вы хотите проверить.

Единственное, что вам нужно изменить, это getTargets() функции, которые должны возвращать self::CLASS_CONSTRAINT.

Также убедитесь, что вы определили свой валидатор на уровне класса, а не на уровне свойства. Если вы используете аннотации, это означает, что валидатор должен быть описан выше класса defnition, а не выше определенного определения атрибута:

/**
  * @MyValidator\SomeValidator
  */
class MyClass {

}