Добавление ошибки формы в EventListener

У меня есть приложение на основе Symfony 2.2 с формой, которая имеет поле, которое требуется только на основании другого поля в форме. Я связал EventListener, чтобы поймать, когда форма отправлена, поэтому я могу проверить, действительно ли поле «обязательно» не требуется при отправке формы.

Я заметил, что я не могу установить FormError внутри PRE_BIND формы PRE_BIND . Это не показывает ошибку, но если я привязываюсь к прослушивателю событий BIND ошибка формы отображается правильно, но я не хочу ждать, пока событие BIND не проверит мои ошибки (я не хочу, чтобы потенциальный плохих данных, привязанных к моей сущности).

Может кто-нибудь сказать мне, почему это так?

 public function buildForm(FormBuilderInterface $builder, array $options) { // snip ... $builder->addEventListener(FormEvents::PRE_BIND, function(FormEvent $event) use ($options) { $data = $event->getData(); $form = $event->getForm(); if ($data === null) { return; } // yes, this is definitely called; If I remove the if() and just // and just add the formError it still doesn't work. if ($data['type'] == 'port' and empty($data['protocol'])) { $form->get('protocol')->addError(new FormError('A valid protocol must be selected.')); } }); } 

Solutions Collecting From Web of "Добавление ошибки формы в EventListener"

В этом случае вы должны использовать группы проверки на основе отправленных данных. Этот метод доступен с Symfony 2.1.

И вам не нужно тянуть события. Смотри сюда:

формы – http://symfony.com/doc/current/book/forms.html#groups-based-on-submitted-data

валидация – http://symfony.com/doc/current/book/validation.html#validation-groups

Попробуйте этот подход. И вы должны получить код следующим образом:

Скрипт сущности с валидаторами: src / Acme / AcmeBundle / Entity / Url.php

 use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; ... /** * @ORM\Column(name="port", type="integer") * @Assert\NotBlank(groups={"validation_partial", "validation_full"}) */ private $port; /** * @ORM\Column(name="protocol", type="string", length=10) * @Assert\NotBlank(groups={"validation_full"}) */ private $protocol; ... 

Сценарий формы: src / Acme / AcmeBundle / Form / UrlType.php

 use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; ... public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'validation_groups' => function(FormInterface $form) { $data = $form->getData(); if ('port' == $data->getType()) { return array('validation_full'); } else { return array('validation_partial'); } }, )); } 

Хорошо, я постараюсь ответить на ваш вопрос подробно. Например. У нас есть FormType:

 public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name') // Some text field 'Name' ; $builder->addEventListener(FormEvents::PRE_BIND, function(FormEvent $event) use ($options) { $event->getForm()->get('name')->addError(new FormError('*** ERROR PRE_BIND')); }); $builder->addEventListener(FormEvents::BIND, function(FormEvent $event) use ($options) { $event->getForm()->get('name')->addError(new FormError('*** ERROR BIND')); }); $builder->addEventListener(FormEvents::POST_BIND, function(FormEvent $event) use ($options) { $event->getForm()->get('name')->addError(new FormError('*** ERROR POST_BIND')); }); } 

Ты прав. Если вы добавляете ошибки в прослушиватели для событий: PRE_BIND, BIND, POST_BIND. Вы получите только ошибки от событий BIND и POST_BIND. Чтобы понять, почему это так, вам нужно знать 2 очка.

Первое: каждый элемент в форме также является формой. В нашем случае наша основная форма имеет дочернее имя (текстовый элемент), которое также является формой.

[MainForm]

-> [NameForm]

// могут быть дополнительные формы, если ваша форма имеет другие элементы

Второе: когда вы связываете запрос с MainForm, вы вызываете функцию bind ().

И эта функция вызывает функцию bind () для каждого дочернего элемента MainForm.

Ответ на ваш вопрос есть в алгоритме этой функции. bind ():

 function bind($submittedData) { 1) clear all errors 2) dispatch event PRE_BIND 3) invoke bind() function for children 4) dispatch event BIND 5) dispatch event POST_BIND } 

Таким образом, на основе нашего примера поток программ будет:

 Invoke bind() function for MainForm 1) MainForm - clear all errors 2) MainForm - dispatch event PRE_BIND // there our listener add error for child NameForm. 3) MainForm - invoke bind() function for child NameForm: 1) NameForm - clear all errors // is the answer for your question, error from event MainForm:PRE_BIND cleared!!! 2) NameForm - dispatch event PRE_BIND // no changes 3) NameForm - invoke bind() for children // this form does not have children, so will be passed 4) NameForm - dispatch event BIND // no changes 5) NameForm - dispatch event POST_BIND // no changes 4) MainForm - dispatch event BIND // there our listener add error to child NameForm 5) MainForm - dispatch event POST_BIND // there our listener add another error to child NameForm. 

Надеюсь, это объяснение поможет вам.