Skip to content

Commit 5047ff6

Browse files
committed
Merge pull request #3312 from bicpi/simplify_dynamic_form_modification
[Cookbook][Dynamic Forms] Simplify first example
2 parents 38612bc + 34b486e commit 5047ff6

File tree

1 file changed

+89
-32
lines changed

1 file changed

+89
-32
lines changed

cookbook/form/dynamic_form_modification.rst

+89-32
Original file line numberDiff line numberDiff line change
@@ -78,47 +78,118 @@ system to analyze the data on the object and modify the form based on the
7878
Product object's data. In this entry, you'll learn how to add this level of
7979
flexibility to your forms.
8080

81-
.. _`cookbook-forms-event-subscriber`:
81+
.. _`cookbook-forms-event-listener`:
8282

83-
Adding An Event Subscriber To A Form Class
84-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
83+
Adding an Event Listener to a Form Class
84+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8585

86-
So, instead of directly adding that "name" widget via your ``ProductType`` form
87-
class, let's delegate the responsibility of creating that particular field
88-
to an event subscriber::
86+
So, instead of directly adding that ``name`` widget, the responsibility of
87+
creating that particular field is delegated to an event listener::
8988

9089
// src/Acme/DemoBundle/Form/Type/ProductType.php
9190
namespace Acme\DemoBundle\Form\Type;
9291

9392
// ...
94-
use Acme\DemoBundle\Form\EventListener\AddNameFieldSubscriber;
93+
use Symfony\Component\Form\FormEvent;
94+
use Symfony\Component\Form\FormEvents;
9595

9696
class ProductType extends AbstractType
9797
{
9898
public function buildForm(FormBuilderInterface $builder, array $options)
9999
{
100100
$builder->add('price');
101101

102-
$builder->addEventSubscriber(new AddNameFieldSubscriber());
102+
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
103+
// ... adding the name field if needed
104+
});
103105
}
104106

105107
// ...
106108
}
107109

108-
.. _`cookbook-forms-inside-subscriber-class`:
109110

110-
Inside the Event Subscriber Class
111-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
111+
The goal is to create a ``name`` field *only* if the underlying ``Product``
112+
object is new (e.g. hasn't been persisted to the database). Based on that,
113+
the event listener might look like the following::
112114

113-
The goal is to create a "name" field *only* if the underlying Product object
114-
is new (e.g. hasn't been persisted to the database). Based on that, the subscriber
115-
might look like the following:
115+
// ...
116+
public function buildForm(FormBuilderInterface $builder, array $options)
117+
{
118+
// ...
119+
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
120+
$product = $event->getData();
121+
$form = $event->getForm();
122+
123+
// check if the Product object is "new"
124+
// If no data is passed to the form, the data is "null".
125+
// This should be considered a new "Product"
126+
if (!$product || null !== $product->getId()) {
127+
$form->add('name', 'text');
128+
}
129+
});
130+
}
116131

117132
.. versionadded:: 2.2
118-
The ability to pass a string into :method:`FormInterface::add <Symfony\\Component\\Form\\FormInterface::add>`
133+
The ability to pass a string into
134+
:method:`FormInterface::add <Symfony\\Component\\Form\\FormInterface::add>`
119135
was added in Symfony 2.2.
120136

121-
.. code-block:: php
137+
.. note::
138+
You can of course use any callback type instead of a closure, e.g. a method
139+
call on the ``ProductType`` object itself for better readability::
140+
141+
// ...
142+
class ProductType extends AbstractType
143+
{
144+
public function buildForm(FormBuilderInterface $builder, array $options)
145+
{
146+
// ...
147+
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
148+
}
149+
150+
public function onPreSetData(FormEvent $event){
151+
// ...
152+
}
153+
}
154+
155+
.. note::
156+
157+
The ``FormEvents::PRE_SET_DATA`` line actually resolves to the string
158+
``form.pre_set_data``. :class:`Symfony\\Component\\Form\\FormEvents`
159+
serves an organizational purpose. It is a centralized location in which
160+
you can find all of the various form events available. You can view the
161+
full list of form events via the
162+
:class:`Symfony\\Component\\Form\\FormEvents` class.
163+
164+
.. _`cookbook-forms-event-subscriber`:
165+
166+
Adding an Event Subscriber to a Form Class
167+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
168+
169+
For better reusability or if there is some heavy logic in your event listener,
170+
you can also move the logic for creating the ``name`` field to an
171+
:ref:`event subscriber <event_dispatcher-using-event-subscribers:ref:>`::
172+
173+
// src/Acme/DemoBundle/Form/Type/ProductType.php
174+
namespace Acme\DemoBundle\Form\Type;
175+
176+
// ...
177+
use Acme\DemoBundle\Form\EventListener\AddNameFieldSubscriber;
178+
179+
class ProductType extends AbstractType
180+
{
181+
public function buildForm(FormBuilderInterface $builder, array $options)
182+
{
183+
$builder->add('price');
184+
185+
$builder->addEventSubscriber(new AddNameFieldSubscriber());
186+
}
187+
188+
// ...
189+
}
190+
191+
Now the logic for creating the ``name`` field resides in it own subscriber
192+
class::
122193

123194
// src/Acme/DemoBundle/Form/EventListener/AddNameFieldSubscriber.php
124195
namespace Acme\DemoBundle\Form\EventListener;
@@ -138,29 +209,15 @@ might look like the following:
138209

139210
public function preSetData(FormEvent $event)
140211
{
141-
$data = $event->getData();
212+
$product = $event->getData();
142213
$form = $event->getForm();
143214

144-
// check if the product object is "new"
145-
// If you didn't pass any data to the form, the data is "null".
146-
// This should be considered a new "Product"
147-
if (!$data || !$data->getId()) {
215+
if (!$product || null !== $product->getId()) {
148216
$form->add('name', 'text');
149217
}
150218
}
151219
}
152220

153-
.. tip::
154-
155-
The ``FormEvents::PRE_SET_DATA`` line actually resolves to the string
156-
``form.pre_set_data``. :class:`Symfony\\Component\\Form\\FormEvents` serves
157-
an organizational purpose. It is a centralized location in which you can
158-
find all of the various form events available.
159-
160-
.. note::
161-
162-
You can view the full list of form events via the :class:`Symfony\\Component\\Form\\FormEvents`
163-
class.
164221

165222
.. _cookbook-form-events-user-data:
166223

0 commit comments

Comments
 (0)