I have a custom FormType, which needs to add itself to the parent Entity when the parent Form persists.
In Symfony < 2.3 this could be done 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 upgrading to Symfony 2.6 I've discovered that $builder->getParent()
has been removed. But now I can't listen to the parent being submitted.
So I added the listener to my builder and referenced the parent from within the Subscriber. But this doesn't really work, since I do a check on the parent form being valid - which it isn't, since it's not submitted yet:
function postSubmit(FormEvent $e)
{
if ($e->getForm()->getParent()->getRoot()->isValid()) {
//this gives 'false'
This false is caused by the next piece of code:
// Symfony\Component\Form\Form.php @ line 744
public function isValid()
{
if (!$this->submitted) {
return false;
}
And because the parent form first loops through all the childs and submits that, before setting $this->submitted = true
on itself... I'm not sure if the parent is valid.
TL;DR
How can I add an Eventlistener to my parent Form, without having to adjust my parent Form? I want my FooType be something I can add to all forms, without having to know/remember to do some logic for that FooType specific.
I needed the same functionality because I have a custom form field that needs the parent entity after all mapped fields have been updated. Unfortunately the POST_SUBMIT of child forms is called before SUBMIT on the parent is run.
I ended up passing the eventDispatcher to the child, and tying my listener there. I needed two listeners to get the job done: one to get the processed value, and one to update the main entity. passing $generatedPassword to the closure by reference allows you to share data from the child event to the parent.
$builder->add('generate_password', GeneratePasswordType::class, [
'event_dispatcher' => $builder->getEventDispatcher(),
]);
//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 custom field is a checkbox marked 'generate new password on save' for a user management module. It emails the user the generated password, which is why I need the latest email address from the main entity)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.