-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[Cookbook][Dynamic Forms] Simplify first example #3312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,47 +78,118 @@ system to analyze the data on the object and modify the form based on the | |
Product object's data. In this entry, you'll learn how to add this level of | ||
flexibility to your forms. | ||
|
||
.. _`cookbook-forms-event-subscriber`: | ||
.. _`cookbook-forms-event-listener`: | ||
|
||
Adding An Event Subscriber To A Form Class | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
Adding an Event Listener to a Form Class | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
So, instead of directly adding that "name" widget via your ``ProductType`` form | ||
class, let's delegate the responsibility of creating that particular field | ||
to an event subscriber:: | ||
So, instead of directly adding that ``name`` widget, the responsibility of | ||
creating that particular field is delegated to an event listener:: | ||
|
||
// src/Acme/DemoBundle/Form/Type/ProductType.php | ||
namespace Acme\DemoBundle\Form\Type; | ||
|
||
// ... | ||
use Acme\DemoBundle\Form\EventListener\AddNameFieldSubscriber; | ||
use Symfony\Component\Form\FormEvent; | ||
use Symfony\Component\Form\FormEvents; | ||
|
||
class ProductType extends AbstractType | ||
{ | ||
public function buildForm(FormBuilderInterface $builder, array $options) | ||
{ | ||
$builder->add('price'); | ||
|
||
$builder->addEventSubscriber(new AddNameFieldSubscriber()); | ||
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) { | ||
// ... adding the name field if needed | ||
}); | ||
} | ||
|
||
// ... | ||
} | ||
|
||
.. _`cookbook-forms-inside-subscriber-class`: | ||
|
||
Inside the Event Subscriber Class | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
The goal is to create a ``name`` field *only* if the underlying ``Product`` | ||
object is new (e.g. hasn't been persisted to the database). Based on that, | ||
the event listener might look like the following:: | ||
|
||
The goal is to create a "name" field *only* if the underlying Product object | ||
is new (e.g. hasn't been persisted to the database). Based on that, the subscriber | ||
might look like the following: | ||
// ... | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be a double colon: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the red code :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :) it turns out I'm not in a review mode today... |
||
public function buildForm(FormBuilderInterface $builder, array $options) | ||
{ | ||
// ... | ||
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){ | ||
$product = $event->getData(); | ||
$form = $event->getForm(); | ||
|
||
// check if the Product object is "new" | ||
// If no data is passed to the form, the data is "null". | ||
// This should be considered a new "Product" | ||
if (!$product || null !== $product->getId()) { | ||
$form->add('name', 'text'); | ||
} | ||
}); | ||
} | ||
|
||
.. versionadded:: 2.2 | ||
The ability to pass a string into :method:`FormInterface::add <Symfony\\Component\\Form\\FormInterface::add>` | ||
The ability to pass a string into | ||
:method:`FormInterface::add <Symfony\\Component\\Form\\FormInterface::add>` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not simply :method:`Symfony\\Component\\Form\\FormInterface` There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was copy&paste from the existing documentation. But this is about the parameter type for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. seems rather complicated to me to use a label here when it is the same to what would be displayed when omitting it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The classname would not be displayed when we remove thelabel text There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stupid me. You're right of course. |
||
was added in Symfony 2.2. | ||
|
||
.. code-block:: php | ||
.. note:: | ||
You can of course use any callback type instead of a closure, e.g. a method | ||
call on the ``ProductType`` object itself for better readability:: | ||
|
||
// ... | ||
class ProductType extends AbstractType | ||
{ | ||
public function buildForm(FormBuilderInterface $builder, array $options) | ||
{ | ||
// ... | ||
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData')); | ||
} | ||
|
||
public function onPreSetData(FormEvent $event){ | ||
// ... | ||
} | ||
} | ||
|
||
.. note:: | ||
|
||
The ``FormEvents::PRE_SET_DATA`` line actually resolves to the string | ||
``form.pre_set_data``. :class:`Symfony\\Component\\Form\\FormEvents` | ||
serves an organizational purpose. It is a centralized location in which | ||
you can find all of the various form events available. You can view the | ||
full list of form events via the | ||
:class:`Symfony\\Component\\Form\\FormEvents` class. | ||
|
||
.. _`cookbook-forms-event-subscriber`: | ||
|
||
Adding an Event Subscriber to a Form Class | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
For better reusability or if there is some heavy logic in your event listener, | ||
you can also move the logic for creating the ``name`` field to an | ||
:ref:`event subscriber <event_dispatcher-using-event-subscribers:ref:>`:: | ||
|
||
// src/Acme/DemoBundle/Form/Type/ProductType.php | ||
namespace Acme\DemoBundle\Form\Type; | ||
|
||
// ... | ||
use Acme\DemoBundle\Form\EventListener\AddNameFieldSubscriber; | ||
|
||
class ProductType extends AbstractType | ||
{ | ||
public function buildForm(FormBuilderInterface $builder, array $options) | ||
{ | ||
$builder->add('price'); | ||
|
||
$builder->addEventSubscriber(new AddNameFieldSubscriber()); | ||
} | ||
|
||
// ... | ||
} | ||
|
||
Now the logic for creating the ``name`` field resides in it own subscriber | ||
class:: | ||
|
||
// src/Acme/DemoBundle/Form/EventListener/AddNameFieldSubscriber.php | ||
namespace Acme\DemoBundle\Form\EventListener; | ||
|
@@ -138,29 +209,15 @@ might look like the following: | |
|
||
public function preSetData(FormEvent $event) | ||
{ | ||
$data = $event->getData(); | ||
$product = $event->getData(); | ||
$form = $event->getForm(); | ||
|
||
// check if the product object is "new" | ||
// If you didn't pass any data to the form, the data is "null". | ||
// This should be considered a new "Product" | ||
if (!$data || !$data->getId()) { | ||
if (!$product || null !== $product->getId()) { | ||
$form->add('name', 'text'); | ||
} | ||
} | ||
} | ||
|
||
.. tip:: | ||
|
||
The ``FormEvents::PRE_SET_DATA`` line actually resolves to the string | ||
``form.pre_set_data``. :class:`Symfony\\Component\\Form\\FormEvents` serves | ||
an organizational purpose. It is a centralized location in which you can | ||
find all of the various form events available. | ||
|
||
.. note:: | ||
|
||
You can view the full list of form events via the :class:`Symfony\\Component\\Form\\FormEvents` | ||
class. | ||
|
||
.. _cookbook-form-events-user-data: | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing empty line before this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stupid github diffs :)