Symfony2 (> = 2.3): How to listen to a parent form event from a child?

I have my own FormType that needs to be added to the parent Entity when the parent form is saved.

In Symfony <2.3, you can do this by doing the following:

class FooType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { parent::buildForm($builder, $options); ... $builder->getParent()->addEventSubscriber(new FooSubscriber) } } class FooSubscriber implements EventSubscriberInterface { static function getSubscribedEvents() { return array( FormEvents::POST_SUBMIT => 'postSubmit' ); } } 

But after migrating to Symfony 2.6, I found that $builder->getParent() was removed. But now I can’t listen to the submitted parent.

So, I added a listener to my builder and referred to the parent from the Subscriber. But actually this does not work, since I check the parent form as valid, which it is not, since it has not yet been submitted:

 function postSubmit(FormEvent $e) { if ($e->getForm()->getParent()->getRoot()->isValid()) { //this gives 'false' 

This false is caused by the following piece of code:

 // Symfony\Component\Form\Form.php @ line 744 public function isValid() { if (!$this->submitted) { return false; } 

And since the parent form first iterates over all the children and submits it, before setting $this->submitted = true to itself ... I'm not sure if the parent is valid.


TL DR

How to add Eventenerener to the parent form without the need to adjust the parent form? I want my FooType to be something that I can add to all forms without knowing / don't remember, to make some logic for this particular FooType.

+5
source share
1 answer

I needed the same functionality because I have a custom form field that requires a parent after all the displayed fields have been updated. Unfortunately, POST_SUBMIT of child forms is called before running SUBMIT in parent mode.

I ended up passing eventDispatcher to the child and binding my listener to it. I needed two listeners to complete the task: one to get the processed value, and one to update the main object. passing $ generatedPassword to the loopback by reference allows you to exchange data with the child event with the parent.

Parent :: buildForm

 $builder->add('generate_password', GeneratePasswordType::class, [ 'event_dispatcher' => $builder->getEventDispatcher(), ]); 

Child :: buildForm

 //first listed to submit even to get current field value $generateNewPassword = false; $builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) use (&generateNewPassword) { $generateNewPassword = null !== $event->getData(); }); //then run updater after parent entity has been updated $parentDispatcher = $options['event_dispatcher']; $parentDispatcher->addListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use (&$generateNewPassword) { $user = $event->getData(); if(true === $generateNewPassword){ //update password & email user new credentials } } 

(The user field is the “generate new password when saving” checkbox for the user management module. It sends the password to the user generated password, so I need the last email address from the main object)

0
source

Source: https://habr.com/ru/post/1210903/


All Articles