From 9e6b98d7c8e551ecfcff4e268e9c55c3480a0926 Mon Sep 17 00:00:00 2001 From: Philipp Rieber Date: Mon, 9 Dec 2013 07:59:49 +0100 Subject: [PATCH 1/4] [Cookbook][Dynamic Forms] Simplify first example --- cookbook/form/dynamic_form_modification.rst | 121 ++++++++++++++------ 1 file changed, 89 insertions(+), 32 deletions(-) diff --git a/cookbook/form/dynamic_form_modification.rst b/cookbook/form/dynamic_form_modification.rst index 68c5e98d663..fd6533a9efa 100644 --- a/cookbook/form/dynamic_form_modification.rst +++ b/cookbook/form/dynamic_form_modification.rst @@ -78,20 +78,20 @@ 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, let's delegate the +responsibility of creating that particular field 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 { @@ -99,26 +99,97 @@ to an event subscriber:: { $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: + // ... + 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 you didn't pass any data to the form, the data is "null". + // This should be considered a new "Product" + if (!$product || !$product->getId()) { + $form->add('name', 'text'); + } + }); + } .. versionadded:: 2.2 - The ability to pass a string into :method:`FormInterface::add ` + The ability to pass a string into + :method:`FormInterface::add ` 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 event +subscriber:: + + // 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 || !$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: From 9bca4d12d97059f5eaeb1dc9b62ef3aa992e633a Mon Sep 17 00:00:00 2001 From: Philipp Rieber Date: Fri, 13 Dec 2013 15:06:56 +0100 Subject: [PATCH 2/4] fix first person's view style --- cookbook/form/dynamic_form_modification.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/form/dynamic_form_modification.rst b/cookbook/form/dynamic_form_modification.rst index fd6533a9efa..4fb0de15011 100644 --- a/cookbook/form/dynamic_form_modification.rst +++ b/cookbook/form/dynamic_form_modification.rst @@ -83,8 +83,8 @@ flexibility to your forms. Adding an Event Listener to a Form Class ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -So, instead of directly adding that ``name`` widget, let's delegate the -responsibility of creating that particular field to an event listener:: +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; From 8944b33e8220f77fb04a703d1cc54cdfdb713951 Mon Sep 17 00:00:00 2001 From: Philipp Rieber Date: Sun, 15 Dec 2013 11:13:03 +0100 Subject: [PATCH 3/4] add event subscriber reference link --- cookbook/form/dynamic_form_modification.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/form/dynamic_form_modification.rst b/cookbook/form/dynamic_form_modification.rst index 4fb0de15011..b01d4a9f191 100644 --- a/cookbook/form/dynamic_form_modification.rst +++ b/cookbook/form/dynamic_form_modification.rst @@ -167,8 +167,8 @@ 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 event -subscriber:: +you can also move the logic for creating the ``name`` field to an +:ref:`event subscriber `:: // src/Acme/DemoBundle/Form/Type/ProductType.php namespace Acme\DemoBundle\Form\Type; From 34b486e250a651f9c78c1deb46c39eea377cd805 Mon Sep 17 00:00:00 2001 From: Philipp Rieber Date: Sun, 15 Dec 2013 15:47:07 +0100 Subject: [PATCH 4/4] Some updates after public review --- cookbook/form/dynamic_form_modification.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cookbook/form/dynamic_form_modification.rst b/cookbook/form/dynamic_form_modification.rst index b01d4a9f191..c03f451a786 100644 --- a/cookbook/form/dynamic_form_modification.rst +++ b/cookbook/form/dynamic_form_modification.rst @@ -100,7 +100,7 @@ creating that particular field is delegated to an event listener:: $builder->add('price'); $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) { - // adding the name field if needed + // ... adding the name field if needed }); } @@ -121,9 +121,9 @@ the event listener might look like the following:: $form = $event->getForm(); // check if the Product object is "new" - // If you didn't pass any data to the form, the data is "null". + // If no data is passed to the form, the data is "null". // This should be considered a new "Product" - if (!$product || !$product->getId()) { + if (!$product || null !== $product->getId()) { $form->add('name', 'text'); } }); @@ -212,7 +212,7 @@ class:: $product = $event->getData(); $form = $event->getForm(); - if (!$product || !$product->getId()) { + if (!$product || null !== $product->getId()) { $form->add('name', 'text'); } }