Form Events
Warning: You are browsing the documentation for Symfony 3.x, which is no longer maintained.
Read the updated version of this page for Symfony 7.1 (the current stable version).
The Form component provides a structured process to let you customize your forms, by making use of the EventDispatcher component. Using form events, you may modify information or fields at different steps of the workflow: from the population of the form to the submission of the data from the request.
By utilizing the Symfony event system, event listeners can be registered to your forms.
For example, if you wish to register a function to the
FormEvents::PRE_SUBMIT
event, the following code lets you add a field,
depending on the request values:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// ...
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
$listener = function (FormEvent $event) {
// ...
};
$form = $formFactory->createBuilder()
// ... add form fields
->addEventListener(FormEvents::PRE_SUBMIT, $listener);
// ...
The Form Workflow
1) Pre-populating the Form (FormEvents::PRE_SET_DATA
and FormEvents::POST_SET_DATA
)
Two events are dispatched during pre-population of a form, when
Form::setData()
is called: FormEvents::PRE_SET_DATA
and FormEvents::POST_SET_DATA
.
A) The FormEvents::PRE_SET_DATA
Event
The FormEvents::PRE_SET_DATA
event is dispatched at the beginning of the
Form::setData()
method. It can be used to:
- Modify the data given during pre-population;
- Modify a form depending on the pre-populated data (adding or removing fields dynamically).
Data Type | Value |
---|---|
Model data | null |
Normalized data | null |
View data | null |
See also
See all form events at a glance in the Form Events Information Table.
Caution
During FormEvents::PRE_SET_DATA
,
Form::setData()
is locked and will throw an exception if used. If you wish to modify
data, you should use
FormEvent::setData()
instead.
FormEvents::PRE_SET_DATA
in the Form component
The Symfony
form type relies
on the Symfony
subscriber, listening to the FormEvents::PRE_SET_DATA
event in order
to reorder the form's fields depending on the data from the pre-populated
object, by removing and adding all form rows.
B) The FormEvents::POST_SET_DATA
Event
The FormEvents::POST_SET_DATA
event is dispatched at the end of the
Form::setData()
method. This event is mostly here for reading data after having pre-populated
the form.
Data Type | Value |
---|---|
Model data | Model data injected into setData() |
Normalized data | Model data transformed using a model transformer |
View data | Normalized data transformed using a view transformer |
See also
See all form events at a glance in the Form Events Information Table.
FormEvents::POST_SET_DATA
in the Form component
The Symfony
class is subscribed to listen to the FormEvents::POST_SET_DATA
event
in order to collect information about the forms from the denormalized
model and view data.
2) Submitting a Form (FormEvents::PRE_SUBMIT
, FormEvents::SUBMIT
and FormEvents::POST_SUBMIT
)
Three events are dispatched when
Form::handleRequest()
or Form::submit() are
called: FormEvents::PRE_SUBMIT
, FormEvents::SUBMIT
,
FormEvents::POST_SUBMIT
.
A) The FormEvents::PRE_SUBMIT
Event
The FormEvents::PRE_SUBMIT
event is dispatched at the beginning of the
Form::submit() method.
It can be used to:
- Change data from the request, before submitting the data to the form;
- Add or remove form fields, before submitting the data to the form.
Data Type | Value |
---|---|
Model data | Same as in FormEvents::POST_SET_DATA |
Normalized data | Same as in FormEvents::POST_SET_DATA |
View data | Same as in FormEvents::POST_SET_DATA |
See also
See all form events at a glance in the Form Events Information Table.
FormEvents::PRE_SUBMIT
in the Form component
The Symfony
subscriber subscribes to the FormEvents::PRE_SUBMIT
event in order to
trim the request's data (for string values).
The Symfony
subscriber subscribes to the FormEvents::PRE_SUBMIT
event in order to
validate the CSRF token.
B) The FormEvents::SUBMIT
Event
The FormEvents::SUBMIT
event is dispatched just before the
Form::submit() method
transforms back the normalized data to the model and view data.
It can be used to change data from the normalized representation of the data.
Data Type | Value |
---|---|
Model data | Same as in FormEvents::POST_SET_DATA |
Normalized data | Data from the request reverse-transformed from the request using a view transformer |
View data | Same as in FormEvents::POST_SET_DATA |
See also
See all form events at a glance in the Form Events Information Table.
Caution
At this point, you cannot add or remove fields to the form.
FormEvents::SUBMIT
in the Form component
The Symfony
subscribes to the FormEvents::SUBMIT
event in order to prepend a default
protocol to URL fields that were submitted without a protocol.
C) The FormEvents::POST_SUBMIT
Event
The FormEvents::POST_SUBMIT
event is dispatched after the
Form::submit() once the
model and view data have been denormalized.
It can be used to fetch data after denormalization.
Data Type | Value |
---|---|
Model data | Normalized data reverse-transformed using a model transformer |
Normalized data | Same as in FormEvents::SUBMIT |
View data | Normalized data transformed using a view transformer |
See also
See all form events at a glance in the Form Events Information Table.
Caution
At this point, you cannot add or remove fields to the current form and its children.
FormEvents::POST_SUBMIT
in the Form component
The Symfony
subscribes to the FormEvents::POST_SUBMIT
event in order to collect
information about the forms.
The Symfony
subscribes to the FormEvents::POST_SUBMIT
event in order to
automatically validate the denormalized object.
Registering Event Listeners or Event Subscribers
In order to be able to use Form events, you need to create an event listener or an event subscriber and register it to an event.
The name of each of the "form" events is defined as a constant on the FormEvents class. Additionally, each event callback (listener or subscriber method) is passed a single argument, which is an instance of FormEvent. The event object contains a reference to the current state of the form and the current data being processed.
Name | FormEvents Constant |
Event's Data |
---|---|---|
form.pre_set_data |
FormEvents::PRE_SET_DATA |
Model data |
form.post_set_data |
FormEvents::POST_SET_DATA |
Model data |
form.pre_bind |
FormEvents::PRE_SUBMIT |
Request data |
form.bind |
FormEvents::SUBMIT |
Normalized data |
form.post_bind |
FormEvents::POST_SUBMIT |
View data |
Event Listeners
An event listener may be any type of valid callable.
Creating and binding an event listener to the form:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
// ...
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
$form = $formFactory->createBuilder()
->add('username', TextType::class)
->add('showEmail', CheckboxType::class)
->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$user = $event->getData();
$form = $event->getForm();
if (!$user) {
return;
}
// checks whether the user has chosen to display their email or not.
// If the data was submitted previously, the additional value that is
// included in the request variables needs to be removed.
if (isset($user['showEmail']) && $user['showEmail']) {
$form->add('email', EmailType::class);
} else {
unset($user['email']);
$event->setData($user);
}
})
->getForm();
// ...
When you have created a form type class, you can use one of its methods as a callback for better readability:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
// src/AppBundle/Form/SubscriptionType.php
namespace AppBundle\Form;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
// ...
class SubscriptionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', TextType::class)
->add('showEmail', CheckboxType::class)
->addEventListener(
FormEvents::PRE_SET_DATA,
[$this, 'onPreSetData']
)
;
}
public function onPreSetData(FormEvent $event)
{
// ...
}
}
Event Subscribers
Event subscribers have different uses:
- Improving readability;
- Listening to multiple events;
- Regrouping multiple listeners inside a single class.
Consider the following example of a form event subscriber:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
// src/AppBundle/Form/EventListener/AddEmailFieldListener.php
namespace AppBundle\Form\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class AddEmailFieldListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
FormEvents::PRE_SET_DATA => 'onPreSetData',
FormEvents::PRE_SUBMIT => 'onPreSubmit',
];
}
public function onPreSetData(FormEvent $event)
{
$user = $event->getData();
$form = $event->getForm();
// checks whether the user from the initial data has chosen to
// display their email or not.
if (true === $user->isShowEmail()) {
$form->add('email', EmailType::class);
}
}
public function onPreSubmit(FormEvent $event)
{
$user = $event->getData();
$form = $event->getForm();
if (!$user) {
return;
}
// checks whether the user has chosen to display their email or not.
// If the data was submitted previously, the additional value that
// is included in the request variables needs to be removed.
if (isset($user['showEmail']) && $user['showEmail']) {
$form->add('email', EmailType::class);
} else {
unset($user['email']);
$event->setData($user);
}
}
}
To register the event subscriber, use the addEventSubscriber()
method:
1 2 3 4 5 6 7 8 9 10 11 12 13
use AppBundle\Form\EventListener\AddEmailFieldListener;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
// ...
$form = $formFactory->createBuilder()
->add('username', TextType::class)
->add('showEmail', CheckboxType::class)
->addEventSubscriber(new AddEmailFieldListener())
->getForm();
// ...