10000 Merge branch '2.3' · symfony/symfony-docs@f1ab2ad · GitHub
[go: up one dir, main page]

Skip to content

Commit f1ab2ad

Browse files
committed
Merge branch '2.3'
2 parents 7ed82a0 + da1a8a3 commit f1ab2ad

File tree

5 files changed

+108
-202
lines changed

5 files changed

+108
-202
lines changed

contributing/documentation/format.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ also specify alternative text for the link:
141141

142142
.. code-block:: rst
143143
144-
:doc:`Spooling Email</cookbook/email/spool>`
144+
:doc:`Spooling Email </cookbook/email/spool>`
145145
146146
You can also add links to the API documentation:
147147

cookbook/form/direct_submit.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
How to use the submit() Function to handle Form Submissions
55
===========================================================
66

7-
.. versionadded::
8-
Before Symfony 2.3, the ``submit`` method was known as ``bind``.
7+
.. versionadded:: 2.3
8+
The ``handleRequest()`` method was added in Symfony 2.3.
99

1010
In Symfony 2.3, a new :method:`Symfony\Component\Form\FormInterface::handleRequest`
1111
method was added, which makes handling form submissions easier than ever::
@@ -39,6 +39,9 @@ method was added, which makes handling form submissions easier than ever::
3939
Calling Form::submit() manually
4040
-------------------------------
4141

42+
.. versionadded:: 2.3
43+
Before Symfony 2.3, the ``submit()`` method was known as ``bind()``.
44+
4245
In some cases, you want better control over when exactly your form is submitted
4346
and what data is passed to it. Instead of using the
4447
:method:`Symfony\Component\Form\FormInterface::handleRequest`

cookbook/form/dynamic_form_modification.rst

Lines changed: 65 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -270,11 +270,9 @@ and fill in the listener logic::
270270
);
271271
}
272272

273-
$factory = $builder->getFormFactory();
274-
275273
$builder->addEventListener(
276274
FormEvents::PRE_SET_DATA,
277-
function(FormEvent $event) use($user, $factory){
275+
function(FormEvent $event) use ($user) {
278276
$form = $event->getForm();
279277

280278
$formOptions = array(
@@ -289,7 +287,7 @@ and fill in the listener logic::
289287

290288
// create the field, this is similar the $builder->add()
291289
// field name, field type, data, options
292-
$form->add($factory->createNamed('friend', 'entity', null, $formOptions));
290+
$form->add('friend', 'entity', $formOptions);
293291
}
294292
);
295293
}
@@ -372,16 +370,22 @@ it with :ref:`dic-tags-form-type`.
372370
If you wish to create it from within a controller or any other service that has
373371
access to the form factory, you then use::
374372

375-
class FriendMessageController extends Controller
373+
use Symfony\Component\DependencyInjection\ContainerAware;
374+
375+
class FriendMessageController extends ContainerAware
376376
{
377377
public function newAction(Request $request)
378378
{
379-
$form = $this->createForm('acme_friend_message');
379+
$form = $this->get('form.factory')->create('acme_friend_message');
380380

381381
// ...
382382
}
383383
}
384384

385+
If you extend the ``Symfony\Bundle\FrameworkBundle\Controller\Controller`` class, you can simply call::
386+
387+
$form = $this->createForm('acme_friend_message');
388+
385389
You can also easily embed the form type into another form::
386390

387391
// inside some other "form type" class
@@ -400,40 +404,39 @@ the data that was submitted by the user. For example, imagine you have a registr
400404
form for sports gatherings. Some events will allow you to specify your preferred
401405
position on the field. This would be a ``choice`` field for example. However the
402406
possible choices will depend on each sport. Football will have attack, defense,
403-
goalkeeper etc... Baseball will have a pitcher but will not have goalkeeper. You
404-
will need the correct options to be set in order for validation to pass.
407+
goalkeeper etc... Baseball will have a pitcher but will not have a goalkeeper. You
408+
will need the correct options in order for validation to pass.
405409

406-
The meetup is passed as an entity hidden field to the form. So we can access each
410+
The meetup is passed as an entity field to the form. So we can access each
407411
sport like this::
408412

409413
// src/Acme/DemoBundle/Form/Type/SportMeetupType.php
410414
namespace Acme\DemoBundle\Form\Type;
411-
415+
412416
use Symfony\Component\Form\FormBuilderInterface;
413417
use Symfony\Component\Form\FormEvent;
414418
use Symfony\Component\Form\FormEvents;
415-
419+
// ...
420+
416421
class SportMeetupType extends AbstractType
417422
{
418423
public function buildForm(FormBuilderInterface $builder, array $options)
419424
{
420425
$builder
421-
->add('number_of_people', 'text')
422-
->add('discount_coupon', 'text')
426+
->add('sport', 'entity', array(...))
423427
;
424-
$factory = $builder->getFormFactory();
425428

426429
$builder->addEventListener(
427430
FormEvents::PRE_SET_DATA,
428-
function(FormEvent $event) use ($factory){
431+
function(FormEvent $event) {
429432
$form = $event->getForm();
430433

431434
// this would be your entity, i.e. SportMeetup
432435
$data = $event->getData();
433436

434437
$positions = $data->getSport()->getAvailablePositions();
435438

436-
// ... proceed with customizing the form based on available positions
439+
$form->add('position', 'entity', array('choices' => $positions));
437440
}
438441
);
439442
}
@@ -458,173 +461,71 @@ On a form, we can usually listen to the following events:
458461
The events ``PRE_SUBMIT``, ``SUBMIT`` and ``POST_SUBMIT`` were added in
459462
Symfony 2.3. Before, they were named ``PRE_BIND``, ``BIND`` and ``POST_BIND``.
460463

461-
When listening to ``SUBMIT`` and ``POST_SUBMIT``, it's already "too late" to make
462-
changes to the form. Fortunately, ``PRE_SUBMIT`` is perfect for this. There
463-
is, however, a big difference in what ``$event->getData()`` returns for each
464-
of these events. Specifically, in ``PRE_SUBMIT``, ``$event->getData()`` returns
465-
the raw data submitted by the user.
464+
.. versionadded:: 2.2.6
466465

467-
This can be used to get the ``SportMeetup`` id and retrieve it from the database,
468-
given you have a reference to the object manager (if using doctrine). In
469-
the end, you have an event subscriber that listens to two different events,
470-
requires some external services and customizes the form. In such a situation,
471-
it's probably better to define this as a service rather than using an anonymous
472-
function as the event listener callback.
466+
The behavior of the ``POST_SUBMIT`` changed slightly in 2.2.6, which the
467+
below example uses.
473468

474-
The subscriber would now look like::
469+
The key is to add a ``POST_SUBMIT`` listener to the field that your new field
470+
depends on. If you add a ``POST_SUBMIT`` listener to a form child (e.g. ``sport`),
471+
and add new children to the parent form, the Form component will detect the
472+
new field automatically and map it to the submitted client data.
475473
476-
// src/Acme/DemoBundle/Form/EventListener/RegistrationSportListener.php
477-
namespace Acme\DemoBundle\Form\EventListener;
474+
The type would now look like::
478475
479-
use Symfony\Component\Form\FormFactoryInterface;
480-
use Doctrine\ORM\EntityManager;
481-
use Symfony\Component\Form\FormEvent;
482-
use Symfony\Component\Form\FormEvents;
483-
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
476+
// src/Acme/DemoBundle/Form/Type/SportMeetupType.php
477+
namespace Acme\DemoBundle\Form\Type;
484478
485-
class RegistrationSportListener implements EventSubscriberInterface
486-
{
487-
/**
488-
* @var FormFactoryInterface
489-
*/
490-
private $factory;
491-
492-
/**
493-
* @var EntityManager
494-
*/
495-
private $em;
496-
497-
/**
498-
* @param factory FormFactoryInterface
499-
*/
500-
public function __construct(FormFactoryInterface $factory, EntityManager $em)
501-
{
502-
$this->factory = $factory;
503-
$this->em = $em;
504-
}
479+
// ...
480+
Acme\DemoBundle\Entity\Sport;
481+
Symfony\Component\Form\FormInterface;
505482
506-
public static function getSubscribedEvents()
483+
class SportMeetupType extends AbstractType
484+
{
485+
public function buildForm(FormBuilderInterface $builder, array $options)
507486
{
508-
return array(
509-
FormEvents::PRE_SUBMIT => 'preSubmit',
510-
FormEvents::PRE_SET_DATA => 'preSetData',
511-
);
512-
}
487+
$builder
488+
->add('sport', 'entity', array(...))
489+
;
513490
514-
/**
515-
* @param event FormEvent
516-
*/
517-
public function preSetData(FormEvent $event)
518-
{
519-
$meetup = $event->getData()->getMeetup();
491+
$formModifier = function(FormInterface $form, Sport $sport) {
492+
$positions = $data->getSport()->getAvailablePositions();
520493
521-
// Before SUBMITing the form, the "meetup" will be null
522-
if (null === $meetup) {
523-
return;
494+
$form->add('position', 'entity', array('choices' => $positions));
524495
}
525496
526-
$form = $event->getForm();
527-
$positions = $meetup->getSport()->getPositions();
497+
$builder->addEventListener(
498+
FormEvents::PRE_SET_DATA,
499+
function(FormEvent $event) {
500+
$form = $event->getForm();
528501
529-
$this->customizeForm($form, $positions);
530-
}
502+
// this would be your entity, i.e. SportMeetup
503+
$data = $event->getData();
531504
532-
public function preSubmit(FormEvent $event)
533-
{
534-
$data = $event->getData();
535-
$id = $data['event'];
536-
$meetup = $this->em
537-
->getRepository('AcmeDemoBundle:SportMeetup')
538-
->find($id);
539-
540-
if ($meetup === null) {
541-
$msg = 'The event %s could not be found for your registration';
542-
throw new \Exception(sprintf($msg, $id));
543-
}
544-
$form = $event->getForm();
545-
$positions = $meetup->getSport()->getPositions();
505+
$formModifier($event->getForm(), $sport);
506+
}
507+
);
546508
547-
$this->customizeForm($form, $positions);
548-
}
509+
$builder->get('sport')->addEventListener(
510+
FormEvents::POST_SUBMIT,
511+
function(FormEvent $event) use ($formModifier) {
512+
// It's important here to fetch $event->getForm()->getData(), as
513+
// $event->getData() will get you the client data (this is, the ID)
514+
$sport = $event->getForm()->getData();
549515
550-
protected function customizeForm($form, $positions)
551-
{
552-
// ... customize the form according to the positions
516+
$positions = $sport->getAvailablePositions();
517+
518+
// since we've added the listener to the child, we'll have to pass on
519+
// the parent to the callback functions!
520+
$formModifier($event->getForm()->getParent(), $sport);
521+
}
522+
);
553523
}
554524
}
555525
556526
You can see that you need to listen on these two events and have different callbacks
557-
only because in two different scenarios, the data that you can use is given in a
558-
different format. Other than that, this class always performs exactly the same
559-
things on a given form.
560-
561-
Now that you have that setup, register your form and the listener as services:
562-
563-
.. configuration-block::
564-
565-
.. code-block:: yaml
566-
567-
# app/config/config.yml
568-
acme.form.sport_meetup:
569-
class: Acme\SportBundle\Form\Type\SportMeetupType
570-
arguments: [@acme.form.meetup_registration_listener]
571-
tags:
572-
- { name: form.type, alias: acme_meetup_registration }
573-
acme.form.meetup_registration_listener
574-
class: Acme\SportBundle\Form\EventListener\RegistrationSportListener
575-
arguments: [@form.factory, @doctrine.orm.entity_manager]
576-
577-
.. code-block:: xml
578-
579-
<!-- app/config/config.xml -->
580-
<services>
581-
<service id="acme.form.sport_meetup" class="Acme\SportBundle\FormType\SportMeetupType">
582-
<argument type="service" id="acme.form.meetup_registration_listener" />
583-
<tag name="form.type" alias="acme_meetup_registration" />
584-
</service>
585-
<service id="acme.form.meetup_registration_listener" class="Acme\SportBundle\Form\EventListener\RegistrationSportListener">
586-
<argument type="service" id="form.factory" />
587-
<argument type="service" id="doctrine.orm.entity_manager" />
588-
</service>
589-
</services>
590-
591-
.. code-block:: php
592-
593-
// app/config/config.php
594-
$definition = new Definition('Acme\SportBundle\Form\Type\SportMeetupType');
595-
$definition->addTag('form.type', array('alias' => 'acme_meetup_registration'));
596-
$container->setDefinition(
597-
'acme.form.meetup_registration_listener',
598-
$definition,
599-
array('security.context')
600-
);
601-
$definition = new Definition('Acme\SportBundle\Form\EventListener\RegistrationSportListener');
602-
$container->setDefinition(
603-
'acme.form.meetup_registration_listener',
604-
$definition,
605-
array('form.factory', 'doctrine.orm.entity_manager')
606-
);
607-
608-
In this setup, the ``RegistrationSportListener`` will be a constructor argument
609-
to ``SportMeetupType``. You can then register it as an event subscriber on
610-
your form::
611-
612-
private $registrationSportListener;
613-
614-
public function __construct(RegistrationSportListener $registrationSportListener)
615-
{
616-
$this->registrationSportListener = $registrationSportListener;
617-
}
618-
619-
public function buildForm(FormBuilderInterface $builder, array $options)
620-
{
621-
// ...
622-
$builder->addEventSubscriber($this->registrationSportListener);
623-
}
624-
625-
And this should tie everything together. You can now retrieve your form from the
626-
controller, display it to a user, and validate it with the right choice options
627-
set for every possible kind of sport that our users are registering for.
527+
only because in two different scenarios, the data that you can use is available in different events.
528+
Other than that, the listeners always perform exactly the same things on a given form.
628529
629530
One piece that may still be missing is the client-side updating of your form
630531
after the sport is selected. This should be handled by making an AJAX call

cookbook/routing/redirect_in_config.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Your configuration will look like this:
2323
path: /
2424
defaults:
2525
_controller: FrameworkBundle:Redirect:urlRedirect
26-
path: /app
26+
route: /app
2727
permanent: true
2828
2929
In this example, you configure a route for the ``/`` path and let :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\RedirectController`

0 commit comments

Comments
 (0)
0