Skip to content

Commit babfe7e

Browse files
authored
Merge pull request #42 from sensiolabs/issue-10-form
split the Forms chapter
2 parents ebfa3b8 + bf90d1b commit babfe7e

22 files changed

+1329
-1301
lines changed

cache/form_csrf_caching.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ CSRF tokens are meant to be different for every user. This is why you
88
need to be cautious if you try to cache pages with forms including them.
99

1010
For more information about how CSRF protection works in Symfony, please
11-
check :ref:`CSRF Protection <forms-csrf>`.
11+
check :doc:`CSRF Protection </form/csrf_protection>`.
1212

1313
Why Caching Pages with a CSRF token is Problematic
1414
--------------------------------------------------

cache/varnish.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ If you know for sure that the backend never uses sessions or basic
7777
authentication, have Varnish remove the corresponding header from requests to
7878
prevent clients from bypassing the cache. In practice, you will need sessions
7979
at least for some parts of the site, e.g. when using forms with
80-
:ref:`CSRF Protection <forms-csrf>`. In this situation, make sure to
80+
:doc:`CSRF Protection </form/csrf_protection>`. In this situation, make sure to
8181
:doc:`only start a session when actually needed </session/avoid_session_start>`
8282
and clear the session when it is no longer needed. Alternatively, you can look
8383
into :doc:`/cache/form_csrf_caching`.

components/form.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ That's it! By printing ``form_widget(form)``, each field in the form is
498498
rendered, along with a label and error message (if there is one). As easy
499499
as this is, it's not very flexible (yet). Usually, you'll want to render each
500500
form field individually so you can control how the form looks. You'll learn how
501-
to do that in the ":ref:`form-rendering-template`" section.
501+
to do that in the ":doc:`/form/rendering`" section.
502502

503503
Changing a Form's Method and Action
504504
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

form/action_method.rst

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
.. index::
2+
single: Forms; Changing the action and method
3+
4+
How to Change the Action and Method of a Form
5+
=============================================
6+
7+
By default, a form will be submitted via an HTTP POST request to the same
8+
URL under which the form was rendered. Sometimes you want to change these
9+
parameters. You can do so in a few different ways.
10+
11+
If you use the :class:`Symfony\\Component\\Form\\FormBuilder` to build your
12+
form, you can use ``setAction()`` and ``setMethod()``::
13+
14+
$form = $this->createFormBuilder($task)
15+
->setAction($this->generateUrl('target_route'))
16+
->setMethod('GET')
17+
->add('task', 'text')
18+
->add('dueDate', 'date')
19+
->add('save', 'submit')
20+
->getForm();
21+
22+
.. note::
23+
24+
This example assumes that you've created a route called ``target_route``
25+
that points to the controller that processes the form.
26+
27+
When using a form type class, you can pass the action and method as form
28+
options::
29+
30+
use AppBundle\Form\TaskType;
31+
// ...
32+
33+
$form = $this->createForm(new TaskType(), $task, array(
34+
'action' => $this->generateUrl('target_route'),
35+
'method' => 'GET',
36+
));
37+
38+
Finally, you can override the action and method in the template by passing them
39+
to the ``form()`` or the ``form_start()`` helper functions:
40+
41+
.. configuration-block::
42+
43+
.. code-block:: html+twig
44+
45+
{# app/Resources/views/default/new.html.twig #}
46+
{{ form_start(form, {'action': path('target_route'), 'method': 'GET'}) }}
47+
48+
.. code-block:: html+php
49+
50+
<!-- app/Resources/views/default/newAction.html.php -->
51+
<?php echo $view['form']->start($form, array(
52+
'action' => $view['router']->generate('target_route'),
53+
'method' => 'GET',
54+
)) ?>
55+
56+
.. note::
57+
58+
If the form's method is not GET or POST, but PUT, PATCH or DELETE, Symfony
59+
will insert a hidden field with the name ``_method`` that stores this method.
60+
The form will be submitted in a normal POST request, but Symfony's router
61+
is capable of detecting the ``_method`` parameter and will interpret it as
62+
a PUT, PATCH or DELETE request. Read the cookbook chapter
63+
":doc:`/routing/method_parameters`" for more information.

form/button_based_validation.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
.. index::
2+
single: Forms; Validation groups based on clicked button
3+
4+
How to Choose Validation Groups Based on the Clicked Button
5+
===========================================================
6+
7+
.. versionadded:: 2.3
8+
Support for buttons in forms was introduced in Symfony 2.3.
9+
10+
When your form contains multiple submit buttons, you can change the validation
11+
group depending on which button is used to submit the form. For example,
12+
consider a form in a wizard that lets you advance to the next step or go back
13+
to the previous step. Also assume that when returning to the previous step,
14+
the data of the form should be saved, but not validated.
15+
16+
First, we need to add the two buttons to the form::
17+
18+
$form = $this->createFormBuilder($task)
19+
// ...
20+
->add('nextStep', 'submit')
21+
->add('previousStep', 'submit')
22+
->getForm();
23+
24+
Then, we configure the button for returning to the previous step to run
25+
specific validation groups. In this example, we want it to suppress validation,
26+
so we set its ``validation_groups`` option to false::
27+
28+
$form = $this->createFormBuilder($task)
29+
// ...
30+
->add('previousStep', 'submit', array(
31+
'validation_groups' => false,
32+
))
33+
->getForm();
34+
35+
Now the form will skip your validation constraints. It will still validate
36+
basic integrity constraints, such as checking whether an uploaded file was too
37+
large or whether you tried to submit text in a number field.
38+
39+
.. seealso::
40+
41+
To see how to use a service to resolve ``validation_groups`` dynamically
42+
read the :doc:`/validation/group_service_resolver`
43+
chapter in the cookbook.

form/csrf_protection.rst

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
.. index::
2+
single: Forms; CSRF protection
3+
4+
How to Implement CSRF Protection
5+
================================
6+
7+
CSRF - or `Cross-site request forgery`_ - is a method by which a malicious
8+
user attempts to make your legitimate users unknowingly submit data that
9+
they don't intend to submit. Fortunately, CSRF attacks can be prevented by
10+
using a CSRF token inside your forms.
11+
12+
The good news is that, by default, Symfony embeds and validates CSRF tokens
13+
automatically for you. This means that you can take advantage of the CSRF
14+
protection without doing anything. In fact, every form in this chapter has
15+
taken advantage of the CSRF protection!
16+
17+
CSRF protection works by adding a hidden field to your form - called ``_token``
18+
by default - that contains a value that only you and your user knows. This
19+
ensures that the user - not some other entity - is submitting the given data.
20+
Symfony automatically validates the presence and accuracy of this token.
21+
22+
The ``_token`` field is a hidden field and will be automatically rendered
23+
if you include the ``form_end()`` function in your template, which ensures
24+
that all un-rendered fields are output.
25+
26+
.. caution::
27+
28+
Since the token is stored in the session, a session is started automatically
29+
as soon as you render a form with CSRF protection.
30+
31+
The CSRF token can be customized on a form-by-form basis. For example::
32+
33+
use Symfony\Component\OptionsResolver\OptionsResolver;
34+
35+
class TaskType extends AbstractType
36+
{
37+
// ...
38+
39+
public function configureOptions(OptionsResolver $resolver)
40+
{
41+
$resolver->setDefaults(array(
42+
'data_class' => 'AppBundle\Entity\Task',
43+
'csrf_protection' => true,
44+
'csrf_field_name' => '_token',
45+
// a unique key to help generate the secret token
46+
'csrf_token_id' => 'task_item',
47+
));
48+
}
49+
50+
// ...
51+
}
52+
53+
.. _form-disable-csrf:
54+
55+
To disable CSRF protection, set the ``csrf_protection`` option to false.
56+
Customizations can also be made globally in your project. For more information,
57+
see the :ref:`form configuration reference <reference-framework-form>`
58+
section.
59+
60+
.. note::
61+
62+
The ``csrf_token_id`` option is optional but greatly enhances the security
63+
of the generated token by making it different for each form.
64+
65+
.. caution::
66+
67+
CSRF tokens are meant to be different for every user. This is why you
68+
need to be cautious if you try to cache pages with forms including this
69+
kind of protection. For more information, see
70+
:doc:`/cache/form_csrf_caching`.
71+
72+
.. _`Cross-site request forgery`: http://en.wikipedia.org/wiki/Cross-site_request_forgery

form/data_based_validation.rst

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
.. index::
2+
single: Forms; Validation groups based on submitted data
3+
4+
How to Choose Validation Groups Based on the Submitted Data
5+
===========================================================
6+
7+
If you need some advanced logic to determine the validation groups (e.g.
8+
based on submitted data), you can set the ``validation_groups`` option
9+
to an array callback::
10+
11+
use Symfony\Component\OptionsResolver\OptionsResolver;
12+
13+
// ...
14+
public function configureOptions(OptionsResolver $resolver)
15+
{
16+
$resolver->setDefaults(array(
17+
'validation_groups' => array(
18+
'AppBundle\Entity\Client',
19+
'determineValidationGroups',
20+
),
21+
));
22+
}
23+
24+
This will call the static method ``determineValidationGroups()`` on the
25+
``Client`` class after the form is submitted, but before validation is executed.
26+
The Form object is passed as an argument to that method (see next example).
27+
You can also define whole logic inline by using a ``Closure``::
28+
29+
use AppBundle\Entity\Client;
30+
use Symfony\Component\Form\FormInterface;
31+
use Symfony\Component\OptionsResolver\OptionsResolver;
32+
33+
// ...
34+
public function configureOptions(OptionsResolver $resolver)
35+
{
36+
$resolver->setDefaults(array(
37+
'validation_groups' => function (FormInterface $form) {
38+
$data = $form->getData();
39+
40+
if (Client::TYPE_PERSON == $data->getType()) {
41+
return array('person');
42+
}
43+
44+
return array('company');
45+
},
46+
));
47+
}
48+
49+
Using the ``validation_groups`` option overrides the default validation
50+
group which is being used. If you want to validate the default constraints
51+
of the entity as well you have to adjust the option as follows::
52+
53+
use AppBundle\Entity\Client;
54+
use Symfony\Component\Form\FormInterface;
55+
use Symfony\Component\OptionsResolver\OptionsResolver;
56+
57+
// ...
58+
public function configureOptions(OptionsResolver $resolver)
59+
{
60+
$resolver->setDefaults(array(
61+
'validation_groups' => function (FormInterface $form) {
62+
$data = $form->getData();
63+
64+
if (Client::TYPE_PERSON == $data->getType()) {
65+
return array('Default', 'person');
66+
}
67+
68+
return array('Default', 'company');
69+
},
70+
));
71+
}
72+
73+
You can find more information about how the validation groups and the default constraints
74+
work in the book section about :doc:`validation groups </validation/groups>`.

form/data_transformers.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ Now, when you create your ``TaskType``, you'll need to pass in the entity manage
289289
.. note::
290290

291291
To make this step easier (especially if ``TaskType`` is embedded into other
292-
form type classes), you might choose to :ref:`register your form type as a service <form-as-services>`.
292+
form type classes), you might choose to :doc:`register your form type as a service </form/form_dependencies>`.
293293

294294
Cool, you're done! Your user will be able to enter an issue number into the
295295
text field and it will be transformed back into an Issue object. This means

form/disabling_validation.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
.. index::
2+
single: Forms; Disabling validation
3+
4+
How to Disable the Validation of Submitted Data
5+
===============================================
6+
7+
.. versionadded:: 2.3
8+
The ability to set ``validation_groups`` to false was introduced in Symfony 2.3.
9+
10+
Sometimes it is useful to suppress the validation of a form altogether. For
11+
these cases you can set the ``validation_groups`` option to ``false``::
12+
13+
use Symfony\Component\OptionsResolver\OptionsResolver;
14+
15+
public function configureOptions(OptionsResolver $resolver)
16+
{
17+
$resolver->setDefaults(array(
18+
'validation_groups' => false,
19+
));
20+
}
21+
22+
Note that when you do that, the form will still run basic integrity checks,
23+
for example whether an uploaded file was too large or whether non-existing
24+
fields were submitted. If you want to suppress validation, you can use the
25+
:ref:`POST_SUBMIT event <cookbook-dynamic-form-modification-suppressing-form-validation>`.

0 commit comments

Comments
 (0)