I have a Symfony 2.2 based application with a form that has a field that is only required based on another field in the form. I bound an EventListener to catch when the form is submitted so I can verify if the 'required' field is actually not needed when the form is submitted.
I've noticed that I can't set a FormError
inside the PRE_BIND
form event. Doing so doesn't show the error, but if I bind to the BIND
event listener then the form error is displayed properly but I don't want to wait until the BIND event to check for my errors (I don't want the potential of bad data being bound to my entity).
Can someone tell me why this is so?
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.'));
}
});
}
In this case you should use Validation Groups based on Submited Data. This method available since symfony 2.1.
And you don't need to pull events. Look here:
forms - http://symfony.com/doc/current/book/forms.html#groups-based-on-submitted-data
validation - http://symfony.com/doc/current/book/validation.html#validation-groups
Try this approach. And you should get code like this:
Entity script with validators: src/Acme/AcmeBundle/Entity/Url.php
Form script: src/Acme/AcmeBundle/Form/UrlType.php
Ok, I will try answer on your question in detail. For example. We have FormType like this:
You are right. If add errors in listeners for events: PRE_BIND, BIND, POST_BIND. You will get only errors from BIND and POST_BIND events. To understand why this is so you need to know 2 points.
First thing: Every element in form is also form. In our case our main form has children 'Name'(text element) which is also a form.
[MainForm]
-> [NameForm]
// there can be additional forms if your form has another elements
Second thing: When you bind request to a MainForm you invoke bind() function.
And this function invoke bind() function for every child of MainForm.
Answer for your question is in algorithm of this function. bind() function algorithm:
So based of our example programm flow will be:
I hope this explanation is helpful for you.