From 318ba888af1db81a2eb950c7270f3443afe76bfe Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Wed, 2 Jan 2013 15:51:02 +0100 Subject: [PATCH 1/2] Added information about the new form(), form_start() and form_end() helpers --- book/forms.rst | 126 +++++++++++++++++------- cookbook/doctrine/file_uploads.rst | 26 ----- cookbook/doctrine/registration_form.rst | 14 +-- cookbook/form/form_collections.rst | 16 +-- cookbook/routing/method_parameters.rst | 29 +----- reference/forms/twig_reference.rst | 74 ++++++++++++++ reference/forms/types/collection.rst | 4 +- reference/forms/types/file.rst | 7 +- reference/twig_reference.rst | 10 ++ 9 files changed, 194 insertions(+), 112 deletions(-) diff --git a/book/forms.rst b/book/forms.rst index 272eae5e86e..cc288096151 100644 --- a/book/forms.rst +++ b/book/forms.rst @@ -145,35 +145,27 @@ helper functions: .. code-block:: html+jinja {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} -
- {{ form_widget(form) }} - - -
+ {{ form(form) }} .. code-block:: html+php -
enctype($form) ?> > - widget($form) ?> - - -
+ form($form) ?> .. image:: /images/book/form-simple.png :align: center .. note:: - This example assumes that you've created a route called ``task_new`` - that points to the ``AcmeTaskBundle:Default:new`` controller that - was created earlier. + This example assumes that you submit the form in a "POST" request and to + the same URL that it was displayed in. You will learn later how to + change the request method and the target URL of the form. -That's it! By printing ``form_widget(form)``, each field in the form is -rendered, along with a label and error message (if there is one). As easy -as this is, it's not very flexible (yet). Usually, you'll want to render each -form field individually so you can control how the form looks. You'll learn how -to do that in the ":ref:`form-rendering-template`" section. +That's it! By printing ``form(form)``, each field in the form is rendered, along +with a label and error message (if there is one). As easy as this is, it's not +very flexible (yet). Usually, you'll want to render each form field individually +so you can control how the form looks. You'll learn how to do that in the +":ref:`form-rendering-template`" section. Before moving on, notice how the rendered ``task`` input field has the value of the ``task`` property from the ``$task`` object (i.e. "Write a blog post"). @@ -605,35 +597,30 @@ of code. Of course, you'll usually need much more flexibility when rendering: .. code-block:: html+jinja {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} -
+ {{ form_start(form) }} {{ form_errors(form) }} {{ form_row(form.task) }} {{ form_row(form.dueDate) }} - {{ form_rest(form) }} - -
+ {{ form_end(form) }} .. code-block:: html+php -
enctype($form) ?>> + start($form) ?> errors($form) ?> row($form['task']) ?> row($form['dueDate']) ?> - rest($form) ?> - -
+ end($form) ?> Take a look at each part: -* ``form_enctype(form)`` - If at least one field is a file upload field, this - renders the obligatory ``enctype="multipart/form-data"``; +* ``form_start(form)`` - Renders the start tag of the form. * ``form_errors(form)`` - Renders any errors global to the whole form (field-specific errors are displayed next to each field); @@ -642,10 +629,8 @@ Take a look at each part: form widget for the given field (e.g. ``dueDate``) inside, by default, a ``div`` element; -* ``form_rest(form)`` - Renders any fields that have not yet been rendered. - It's usually a good idea to place a call to this helper at the bottom of - each form (in case you forgot to output a field or don't want to bother - manually rendering hidden fields). This helper is also useful for taking +* ``form_end()`` - Renders the end tag of the form and any fields that have not + yet been rendered. This is useful for rendering hidden fields and taking advantage of the automatic :ref:`CSRF Protection`. The majority of the work is done by the ``form_row`` helper, which renders @@ -740,7 +725,7 @@ field: .. code-block:: html+jinja - {{ form_widget(form.task, { 'attr': {'class': 'task_field'} }) }} + {{ form_widget(form.task, {'attr': {'class': 'task_field'}}) }} .. code-block:: html+php @@ -783,6 +768,75 @@ available in the :doc:`reference manual`. Read this to know everything about the helpers available and the options that can be used with each. +.. index:: + single: Forms; Changing the action and method + +.. _book-forms-changing-action-and-method: + +Changing the Action and Method of a Form +---------------------------------------- + +So far, we have used the ``form_start()`` helper to render the form's start tag +and assumed that each form is submitted to the same URL in a POST request. +Sometimes you want to change these parameters. You can do so in a few different +ways. If you build your form in the controller, you can use ``setAction()`` and +``setMethod()``:: + + $form = $this->createFormBuilder($task) + ->setAction($this->generateUrl('target_route')) + ->setMethod('GET') + ->add('task', 'text') + ->add('dueDate', 'date') + ->getForm(); + +.. note:: + + This example assumes that you've created a route called ``target_route`` + that points to the controller that processes the form. + +In :ref:`book-form-creating-form-classes` you will learn how to outsource the +form building code into separate classes. When using such a form class in the +controller, you can pass the action and method as form options:: + + $form = $this->createForm(new TaskType(), $task, array( + 'action' => $this->generateUrl('target_route'), + 'method' => 'GET', + )); + +At last, you can override the action and method in the template by passing them +to the ``form()`` or the ``form_start()`` helper: + +.. configuration-block:: + + .. code-block:: html+jinja + + {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} + {{ form(form, {'action': path('target_route'), 'method': 'GET'}) }} + + {{ form_start(form, {'action': path('target_route'), 'method': 'GET'}) }} + + .. code-block:: html+php + + + form($form, array( + 'action' => $view['router']->generate('target_route'), + 'method' => 'GET', + )) ?> + + start($form, array( + 'action' => $view['router']->generate('target_route'), + 'method' => 'GET', + )) ?> + +.. note:: + + If the form's method is not GET or POST, but PUT, PATCH or DELETE, Symfony2 + will insert a hidden field with the name "_method" that stores this method. + The form will be submitted in a normal POST request, but Symfony2's router + is capable of detecting the "_method" parameter and will interpret the + request as PUT, PATCH or DELETE request. Read the cookbook chapter + ":doc:`/cookbook/routing/method_parameters`" for more information. + .. index:: single: Forms; Creating form classes @@ -1143,7 +1197,7 @@ renders the form: {% form_theme form 'AcmeTaskBundle:Form:fields.html.twig' 'AcmeTaskBundle:Form:fields2.html.twig' %} -
+ {{ form(form) }} .. code-block:: html+php @@ -1152,7 +1206,7 @@ renders the form: setTheme($form, array('AcmeTaskBundle:Form', 'AcmeTaskBundle:Form')) ?> - + form($form) ?> The ``form_theme`` tag (in Twig) "imports" the fragments defined in the given template and uses them when rendering the form. In other words, when the @@ -1231,7 +1285,7 @@ are 4 possible *parts* of a form that can be rendered: .. note:: - There are actually 3 other *parts* - ``rows``, ``rest``, and ``enctype`` - + There are actually 2 other *parts* - ``rows`` and ``rest`` - but you should rarely if ever need to worry about overriding them. By knowing the field type (e.g. ``textarea``) and which part you want to diff --git a/cookbook/doctrine/file_uploads.rst b/cookbook/doctrine/file_uploads.rst index 34778c3c0aa..f3ca3a05624 100644 --- a/cookbook/doctrine/file_uploads.rst +++ b/cookbook/doctrine/file_uploads.rst @@ -251,32 +251,6 @@ The following controller shows you how to handle the entire process:: return array('form' => $form->createView()); } -.. note:: - - When writing the template, don't forget to set the ``enctype`` attribute: - - .. configuration-block:: - - .. code-block:: html+jinja - -

Upload File

- - - {{ form_widget(form) }} - - -
- - .. code-block:: html+php - -

Upload File

- -
enctype($form) ?>> - widget($form) ?> - - -
- The previous controller will automatically persist the ``Document`` entity with the submitted name, but it will do nothing about the file and the ``path`` property will be blank. diff --git a/cookbook/doctrine/registration_form.rst b/cookbook/doctrine/registration_form.rst index 9e735ee877a..a0665cba206 100644 --- a/cookbook/doctrine/registration_form.rst +++ b/cookbook/doctrine/registration_form.rst @@ -232,10 +232,10 @@ controller for displaying the registration form:: { public function registerAction() { - $form = $this->createForm( - new RegistrationType(), - new Registration() - ); + $registration = new Registration(); + $form = $this->createForm(new RegistrationType(), $registration, array( + 'action' => $this->generateUrl('create'), + )); return $this->render( 'AcmeAccountBundle:Account:register.html.twig', @@ -249,11 +249,7 @@ and its template: .. code-block:: html+jinja {# src/Acme/AccountBundle/Resources/views/Account/register.html.twig #} -
- {{ form_widget(form) }} - - -
+ {{ form(form) }} Finally, create the controller which handles the form submission. This performs the validation and saves the data into the database:: diff --git a/cookbook/form/form_collections.rst b/cookbook/form/form_collections.rst index be64bb969b7..92dfbabf04a 100755 --- a/cookbook/form/form_collections.rst +++ b/cookbook/form/form_collections.rst @@ -205,7 +205,7 @@ zero tags when first created). {# ... #} -
+ {{ form_start(form) }} {# render the task's only field: description #} {{ form_row(form.description) }} @@ -216,10 +216,9 @@ zero tags when first created).
  • {{ form_row(tag.name) }}
  • {% endfor %} + {{ form_end(form) }} - {{ form_rest(form) }} - {# ... #} -
    + {# ... #} .. code-block:: html+php @@ -227,16 +226,17 @@ zero tags when first created). -
    + start($form) ?> + + row($form['description']) ?> +

    Tags

    • row($tag['name']) ?>
    - - rest($form) ?> -
    + end($form) ?> diff --git a/cookbook/routing/method_parameters.rst b/cookbook/routing/method_parameters.rst index f0360e7e87f..ecf152ecc47 100644 --- a/cookbook/routing/method_parameters.rst +++ b/cookbook/routing/method_parameters.rst @@ -86,28 +86,7 @@ Unfortunately, life isn't quite this simple, since most browsers do not support sending PUT and DELETE requests. Fortunately Symfony2 provides you with a simple way of working around this limitation. By including a ``_method`` parameter in the query string or parameters of an HTTP request, Symfony2 will -use this as the method when matching routes. This can be done easily in forms -with a hidden field. Suppose you have a form for editing a blog post: - -.. code-block:: html+jinja - -
    - - {{ form_widget(form) }} - -
    - -The submitted request will now match the ``blog_update`` route and the ``updateAction`` -will be used to process the form. - -Likewise the delete form could be changed to look like this: - -.. code-block:: html+jinja - -
    - - {{ form_widget(delete_form) }} - -
    - -It will then match the ``blog_delete`` route. +use this as the method when matching routes. Forms automatically include a +hidden field for this parameter if their submission method is not GET or POST. +See :ref:`the related chapter in the forms documentation` +for more information. diff --git a/reference/forms/twig_reference.rst b/reference/forms/twig_reference.rst index 7022dbf19be..6ad0aa55347 100644 --- a/reference/forms/twig_reference.rst +++ b/reference/forms/twig_reference.rst @@ -24,6 +24,75 @@ rendering forms. There are several different functions available, and each is responsible for rendering a different part of a form (e.g. labels, errors, widgets, etc). +.. _reference-forms-twig-form: + +form(view, variables) +--------------------- + +Renders the HTML of a complete form. + +.. code-block:: jinja + + {# render the form and change the submission method #} + {{ form(form, {'method': 'GET'}) }} + +You will mostly use this helper for prototyping and if you use custom form +themes. If you need more flexibility in rendering the form, you should use +the other helpers to render individual parts of the form instead: + +.. code-block:: jinja + + {{ form_start(form) }} + {{ form_errors(form) }} + + {{ form_row(form.name) }} + {{ form_row(form.dueDate) }} + + + {{ form_end(form) }} + +See ":ref:`twig-reference-form-variables`" to learn more about the ``variables`` +argument. + +.. _reference-forms-twig-start: + +form_start(view, variables) +--------------------------- + +Renders the start tag of a form. This helper takes care of printing the +configured method and target action of the form. It will also include the +correct ``enctype`` property if the form contains upload fields. + +.. code-block:: jinja + + {# render the start tag and change the submission method #} + {{ form_start(form, {'method': 'GET'}) }} + +See ":ref:`twig-reference-form-variables`" to learn more about the ``variables`` +argument. + +.. _reference-forms-twig-end: + +form_end(view, variables) +------------------------- + +Renders the end tag of a form. + +.. code-block:: jinja + + {{ form_end(form) }} + +This helper also outputs ``form_rest()`` unless you set ``render_rest`` to +false: + +.. code-block:: jinja + + {# don't render unrendered fields #} + {{ form_end(form, {'render_rest': false}) }} + +See ":ref:`twig-reference-form-variables`" to learn more about the ``variables`` +argument. + .. _reference-forms-twig-label: form_label(view, label, variables) @@ -119,6 +188,11 @@ obvious (since it'll render the field for you). form_enctype(view) ------------------ +.. note:: + + This helper was deprecated in Symfony 2.3 and will be removed in Symfony 3.0. + You should use ``form_start()`` instead. + If the form contains at least one file upload field, this will render the required ``enctype="multipart/form-data"`` form attribute. It's always a good idea to include this in your form tag: diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst index ce4e438001f..b394e8bbb5a 100644 --- a/reference/forms/types/collection.rst +++ b/reference/forms/types/collection.rst @@ -151,7 +151,7 @@ you need is the JavaScript: .. code-block:: html+jinja -
    + {{ form_start(form) }} {# ... #} {# store the prototype on the data-prototype attribute #} @@ -167,7 +167,7 @@ you need is the JavaScript: Add another email {# ... #} -
    + {{ form_end(form) }}