mirror of
https://github.com/symfony/symfony-docs.git
synced 2026-03-24 00:32:14 +01:00
785 lines
27 KiB
ReStructuredText
785 lines
27 KiB
ReStructuredText
The Form Component
|
|
==================
|
|
|
|
The Form component allows you to create, process and reuse forms.
|
|
|
|
The Form component is a tool to help you solve the problem of allowing end-users
|
|
to interact with the data and modify the data in your application. And though
|
|
traditionally this has been through HTML forms, the component focuses on
|
|
processing data to and from your client and application, whether that data
|
|
be from a normal form post or from an API.
|
|
|
|
Installation
|
|
------------
|
|
|
|
.. code-block:: terminal
|
|
|
|
$ composer require symfony/form
|
|
|
|
.. include:: /components/require_autoload.rst.inc
|
|
|
|
Configuration
|
|
-------------
|
|
|
|
.. seealso::
|
|
|
|
This article explains how to use the Form features as an independent
|
|
component in any PHP application. Read the :doc:`/forms` article to learn
|
|
about how to use it in Symfony applications.
|
|
|
|
In Symfony, forms are represented by objects and these objects are built
|
|
by using a *form factory*. Building a form factory is done with the factory
|
|
method ``Forms::createFormFactory``::
|
|
|
|
use Symfony\Component\Form\Forms;
|
|
|
|
$formFactory = Forms::createFormFactory();
|
|
|
|
This factory can already be used to create basic forms, but it is lacking
|
|
support for very important features:
|
|
|
|
* **Request Handling:** Support for request handling and file uploads;
|
|
* **CSRF Protection:** Support for protection against Cross-Site-Request-Forgery
|
|
(CSRF) attacks;
|
|
* **Templating:** Integration with a templating layer that allows you to reuse
|
|
HTML fragments when rendering a form;
|
|
* **Translation:** Support for translating error messages, field labels and
|
|
other strings;
|
|
* **Validation:** Integration with a validation library to generate error
|
|
messages for submitted data.
|
|
|
|
The Symfony Form component relies on other libraries to solve these problems.
|
|
Most of the time you will use Twig and the Symfony
|
|
:doc:`HttpFoundation </components/http_foundation>`,
|
|
:doc:`Translation </translation>` and :doc:`Validator </components/validator>`
|
|
components, but you can replace any of these with a different library of your choice.
|
|
|
|
The following sections explain how to plug these libraries into the form
|
|
factory.
|
|
|
|
.. tip::
|
|
|
|
For a working example, see https://github.com/webmozart/standalone-forms
|
|
|
|
Request Handling
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
To process form data, you'll need to call the :method:`Symfony\\Component\\Form\\Form::handleRequest`
|
|
method::
|
|
|
|
$form->handleRequest();
|
|
|
|
Internally, this uses a :class:`Symfony\\Component\\Form\\NativeRequestHandler`
|
|
object to read data off of the correct PHP superglobals (i.e. ``$_POST`` or
|
|
``$_GET``) based on the HTTP method configured on the form (POST is default).
|
|
|
|
.. seealso::
|
|
|
|
If you need more control over exactly when your form is submitted or which
|
|
data is passed to it,
|
|
:ref:`use the submit() method to handle form submissions <processing-forms-submit-method>`.
|
|
|
|
.. sidebar:: Integration with the HttpFoundation Component
|
|
|
|
If you use the HttpFoundation component, then you should add the
|
|
:class:`Symfony\\Component\\Form\\Extension\\HttpFoundation\\HttpFoundationExtension`
|
|
to your form factory::
|
|
|
|
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension;
|
|
use Symfony\Component\Form\Forms;
|
|
|
|
$formFactory = Forms::createFormFactoryBuilder()
|
|
->addExtension(new HttpFoundationExtension())
|
|
->getFormFactory();
|
|
|
|
Now, when you process a form, you can pass the :class:`Symfony\\Component\\HttpFoundation\\Request`
|
|
object to :method:`Symfony\\Component\\Form\\Form::handleRequest`::
|
|
|
|
$form->handleRequest($request);
|
|
|
|
.. note::
|
|
|
|
For more information about the HttpFoundation component or how to
|
|
install it, see :doc:`/components/http_foundation`.
|
|
|
|
CSRF Protection
|
|
~~~~~~~~~~~~~~~
|
|
|
|
Protection against CSRF attacks is built into the Form component, but you need
|
|
to explicitly enable it or replace it with a custom solution. If you want to
|
|
use the built-in support, first install the Security CSRF component:
|
|
|
|
.. code-block:: terminal
|
|
|
|
$ composer require symfony/security-csrf
|
|
|
|
The following snippet adds CSRF protection to the form factory::
|
|
|
|
use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
|
|
use Symfony\Component\Form\Forms;
|
|
use Symfony\Component\HttpFoundation\RequestStack;
|
|
use Symfony\Component\Security\Csrf\CsrfTokenManager;
|
|
use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator;
|
|
use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;
|
|
|
|
// creates a RequestStack object using the current request
|
|
$requestStack = new RequestStack([$request]);
|
|
|
|
$csrfGenerator = new UriSafeTokenGenerator();
|
|
$csrfStorage = new SessionTokenStorage($requestStack);
|
|
$csrfManager = new CsrfTokenManager($csrfGenerator, $csrfStorage);
|
|
|
|
$formFactory = Forms::createFormFactoryBuilder()
|
|
// ...
|
|
->addExtension(new CsrfExtension($csrfManager))
|
|
->getFormFactory();
|
|
|
|
.. versionadded:: 7.2
|
|
|
|
Support for passing requests to the constructor of the ``RequestStack``
|
|
class was introduced in Symfony 7.2.
|
|
|
|
Internally, this extension will automatically add a hidden field to every
|
|
form (called ``_token`` by default) whose value is automatically generated by
|
|
the CSRF generator and validated when binding the form.
|
|
|
|
.. tip::
|
|
|
|
If you're not using the HttpFoundation component, you can use
|
|
:class:`Symfony\\Component\\Security\\Csrf\\TokenStorage\\NativeSessionTokenStorage`
|
|
instead, which relies on PHP's native session handling::
|
|
|
|
use Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage;
|
|
|
|
$csrfStorage = new NativeSessionTokenStorage();
|
|
// ...
|
|
|
|
You can disable CSRF protection per form using the ``csrf_protection`` option::
|
|
|
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
|
|
|
$form = $formFactory->createBuilder(FormType::class, null, ['csrf_protection' => false])
|
|
->getForm();
|
|
|
|
Twig Templating
|
|
~~~~~~~~~~~~~~~
|
|
|
|
If you're using the Form component to process HTML forms, you'll need a way to
|
|
render your form as HTML form fields (complete with field values, errors, and
|
|
labels). If you use `Twig`_ as your template engine, the Form component offers a
|
|
rich integration.
|
|
|
|
To use the integration, you'll need the twig bridge, which provides integration
|
|
between Twig and several Symfony components:
|
|
|
|
.. code-block:: terminal
|
|
|
|
$ composer require symfony/twig-bridge
|
|
|
|
The TwigBridge integration provides you with several
|
|
:ref:`Twig Functions <reference-form-twig-functions-variables>`
|
|
that help you render the HTML widget, label, help and errors for each field
|
|
(as well as a few other things). To configure the integration, you'll need
|
|
to bootstrap or access Twig and add the :class:`Symfony\\Bridge\\Twig\\Extension\\FormExtension`::
|
|
|
|
use Symfony\Bridge\Twig\Extension\FormExtension;
|
|
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
|
|
use Symfony\Component\Form\FormRenderer;
|
|
use Symfony\Component\Form\Forms;
|
|
use Twig\Environment;
|
|
use Twig\Loader\FilesystemLoader;
|
|
use Twig\RuntimeLoader\FactoryRuntimeLoader;
|
|
|
|
// the Twig file that holds all the default markup for rendering forms
|
|
// this file comes with TwigBridge
|
|
$defaultFormTheme = 'form_div_layout.html.twig';
|
|
|
|
$vendorDirectory = realpath(__DIR__.'/../vendor');
|
|
// the path to TwigBridge library so Twig can locate the
|
|
// form_div_layout.html.twig file
|
|
$appVariableReflection = new \ReflectionClass('\Symfony\Bridge\Twig\AppVariable');
|
|
$vendorTwigBridgeDirectory = dirname($appVariableReflection->getFileName());
|
|
// the path to your other templates
|
|
$viewsDirectory = realpath(__DIR__.'/../views');
|
|
|
|
$twig = new Environment(new FilesystemLoader([
|
|
$viewsDirectory,
|
|
$vendorTwigBridgeDirectory.'/Resources/views/Form',
|
|
]));
|
|
$formEngine = new TwigRendererEngine([$defaultFormTheme], $twig);
|
|
$twig->addRuntimeLoader(new FactoryRuntimeLoader([
|
|
FormRenderer::class => function () use ($formEngine, $csrfManager): FormRenderer {
|
|
return new FormRenderer($formEngine, $csrfManager);
|
|
},
|
|
]));
|
|
|
|
// ... (see the previous CSRF Protection section for more information)
|
|
|
|
// adds the FormExtension to Twig
|
|
$twig->addExtension(new FormExtension());
|
|
|
|
// creates a form factory
|
|
$formFactory = Forms::createFormFactoryBuilder()
|
|
// ...
|
|
->getFormFactory();
|
|
|
|
The exact details of your `Twig Configuration`_ will vary, but the goal is
|
|
always to add the :class:`Symfony\\Bridge\\Twig\\Extension\\FormExtension`
|
|
to Twig, which gives you access to the Twig functions for rendering forms.
|
|
To do this, you first need to create a :class:`Symfony\\Bridge\\Twig\\Form\\TwigRendererEngine`,
|
|
where you define your :doc:`form themes </form/form_themes>`
|
|
(i.e. resources/files that define form HTML markup).
|
|
|
|
For general details on rendering forms, see :doc:`/form/form_customization`.
|
|
|
|
.. note::
|
|
|
|
If you use the Twig integration, read ":ref:`component-form-intro-install-translation`"
|
|
below for details on the needed translation filters.
|
|
|
|
.. _component-form-intro-install-translation:
|
|
|
|
Translation
|
|
~~~~~~~~~~~
|
|
|
|
If you're using the Twig integration with one of the default form theme files
|
|
(e.g. ``form_div_layout.html.twig``), there is a Twig filter (``trans``)
|
|
that is used for translating form labels, errors, option
|
|
text and other strings.
|
|
|
|
To add the ``trans`` Twig filter, you can either use the built-in
|
|
:class:`Symfony\\Bridge\\Twig\\Extension\\TranslationExtension` that integrates
|
|
with Symfony's Translation component, or add the Twig filter yourself,
|
|
via your own Twig extension.
|
|
|
|
To use the built-in integration, be sure that your project has Symfony's
|
|
Translation and :doc:`Config </components/config>` components
|
|
installed:
|
|
|
|
.. code-block:: terminal
|
|
|
|
$ composer require symfony/translation symfony/config
|
|
|
|
Next, add the :class:`Symfony\\Bridge\\Twig\\Extension\\TranslationExtension`
|
|
to your ``Twig\Environment`` instance::
|
|
|
|
use Symfony\Bridge\Twig\Extension\TranslationExtension;
|
|
use Symfony\Component\Form\Forms;
|
|
use Symfony\Component\Translation\Loader\XliffFileLoader;
|
|
use Symfony\Component\Translation\Translator;
|
|
|
|
// creates the Translator
|
|
$translator = new Translator('en');
|
|
// somehow load some translations into it
|
|
$translator->addLoader('xlf', new XliffFileLoader());
|
|
$translator->addResource(
|
|
'xlf',
|
|
__DIR__.'/path/to/translations/messages.en.xlf',
|
|
'en'
|
|
);
|
|
|
|
// adds the TranslationExtension (it gives us trans filter)
|
|
$twig->addExtension(new TranslationExtension($translator));
|
|
|
|
$formFactory = Forms::createFormFactoryBuilder()
|
|
// ...
|
|
->getFormFactory();
|
|
|
|
Depending on how your translations are being loaded, you can now add string
|
|
keys, such as field labels, and their translations to your translation files.
|
|
|
|
For more details on translations, see :doc:`/translation`.
|
|
|
|
Validation
|
|
~~~~~~~~~~
|
|
|
|
The Form component comes with tight (but optional) integration with Symfony's
|
|
Validator component. If you're using a different solution for validation,
|
|
no problem! Take the submitted/bound data of your form (which is an
|
|
array or object) and pass it through your own validation system.
|
|
|
|
To use the integration with Symfony's Validator component, first make sure
|
|
it's installed in your application:
|
|
|
|
.. code-block:: terminal
|
|
|
|
$ composer require symfony/validator
|
|
|
|
If you're not familiar with Symfony's Validator component, read more about
|
|
it: :doc:`/validation`. The Form component comes with a
|
|
:class:`Symfony\\Component\\Form\\Extension\\Validator\\ValidatorExtension`
|
|
class, which automatically applies validation to your data on bind. These
|
|
errors are then mapped to the correct field and rendered.
|
|
|
|
Your integration with the Validation component will look something like this::
|
|
|
|
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
|
|
use Symfony\Component\Form\Forms;
|
|
use Symfony\Component\Validator\Validation;
|
|
|
|
$vendorDirectory = realpath(__DIR__.'/../vendor');
|
|
$vendorFormDirectory = $vendorDirectory.'/symfony/form';
|
|
$vendorValidatorDirectory = $vendorDirectory.'/symfony/validator';
|
|
|
|
// creates the validator - details will vary
|
|
$validator = Validation::createValidator();
|
|
|
|
// there are built-in translations for the core error messages
|
|
$translator->addResource(
|
|
'xlf',
|
|
$vendorFormDirectory.'/Resources/translations/validators.en.xlf',
|
|
'en',
|
|
'validators'
|
|
);
|
|
$translator->addResource(
|
|
'xlf',
|
|
$vendorValidatorDirectory.'/Resources/translations/validators.en.xlf',
|
|
'en',
|
|
'validators'
|
|
);
|
|
|
|
$formFactory = Forms::createFormFactoryBuilder()
|
|
// ...
|
|
->addExtension(new ValidatorExtension($validator))
|
|
->getFormFactory();
|
|
|
|
To learn more, skip down to the :ref:`component-form-intro-validation` section.
|
|
|
|
Accessing the Form Factory
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Your application only needs one form factory, and that one factory object
|
|
should be used to create any and all form objects in your application. This
|
|
means that you should create it in some central, bootstrap part of your application
|
|
and then access it whenever you need to build a form.
|
|
|
|
.. note::
|
|
|
|
In this document, the form factory is always a local variable called
|
|
``$formFactory``. The point here is that you will probably need to create
|
|
this object in some more "global" way so you can access it from anywhere.
|
|
|
|
Exactly how you gain access to your one form factory is up to you. If you're
|
|
using a service container (like provided with the
|
|
:doc:`DependencyInjection component </components/dependency_injection>`),
|
|
then you should add the form factory to your container and grab it out whenever
|
|
you need to. If your application uses global or static variables (not usually a
|
|
good idea), then you can store the object on some static class or do something
|
|
similar.
|
|
|
|
.. _component-form-intro-create-simple-form:
|
|
|
|
Creating a simple Form
|
|
----------------------
|
|
|
|
.. tip::
|
|
|
|
If you're using the Symfony Framework, then the form factory is available
|
|
automatically as a service called ``form.factory``, you can inject it as
|
|
``Symfony\Component\Form\FormFactoryInterface``. Also, the default
|
|
base controller class has a :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController::createFormBuilder`
|
|
method, which is a shortcut to fetch the form factory and call ``createBuilder()``
|
|
on it.
|
|
|
|
Creating a form is done via a :class:`Symfony\\Component\\Form\\FormBuilder`
|
|
object, where you build and configure different fields. The form builder
|
|
is created from the form factory.
|
|
|
|
.. configuration-block::
|
|
|
|
.. code-block:: php-symfony
|
|
|
|
// src/Controller/TaskController.php
|
|
namespace App\Controller;
|
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class TaskController extends AbstractController
|
|
{
|
|
public function new(Request $request): Response
|
|
{
|
|
// createFormBuilder is a shortcut to get the "form factory"
|
|
// and then call "createBuilder()" on it
|
|
|
|
$form = $this->createFormBuilder()
|
|
->add('task', TextType::class)
|
|
->add('dueDate', DateType::class)
|
|
->getForm();
|
|
|
|
return $this->render('task/new.html.twig', [
|
|
'form' => $form->createView(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
.. code-block:: php-standalone
|
|
|
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
|
|
// ...
|
|
|
|
$form = $formFactory->createBuilder()
|
|
->add('task', TextType::class)
|
|
->add('dueDate', DateType::class)
|
|
->getForm();
|
|
|
|
var_dump($twig->render('new.html.twig', [
|
|
'form' => $form->createView(),
|
|
]));
|
|
|
|
As you can see, creating a form is like writing a recipe: you call ``add()``
|
|
for each new field you want to create. The first argument to ``add()`` is the
|
|
name of your field, and the second is the fully qualified class name. The Form
|
|
component comes with a lot of :doc:`built-in types </reference/forms/types>`.
|
|
|
|
Now that you've built your form, learn how to :ref:`render <component-form-intro-rendering-form>`
|
|
it and :ref:`process the form submission <component-form-intro-handling-submission>`.
|
|
|
|
Setting default Values
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
If you need your form to load with some default values (or you're building
|
|
an "edit" form), pass in the default data when creating your form builder:
|
|
|
|
.. configuration-block::
|
|
|
|
.. code-block:: php-symfony
|
|
|
|
// src/Controller/DefaultController.php
|
|
namespace App\Controller;
|
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class DefaultController extends AbstractController
|
|
{
|
|
public function new(Request $request): Response
|
|
{
|
|
$defaults = [
|
|
'dueDate' => new \DateTime('tomorrow'),
|
|
];
|
|
|
|
$form = $this->createFormBuilder($defaults)
|
|
->add('task', TextType::class)
|
|
->add('dueDate', DateType::class)
|
|
->getForm();
|
|
|
|
// ...
|
|
}
|
|
}
|
|
|
|
.. code-block:: php-standalone
|
|
|
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
|
|
// ...
|
|
|
|
$defaults = [
|
|
'dueDate' => new \DateTime('tomorrow'),
|
|
];
|
|
|
|
$form = $formFactory->createBuilder(FormType::class, $defaults)
|
|
->add('task', TextType::class)
|
|
->add('dueDate', DateType::class)
|
|
->getForm();
|
|
|
|
.. tip::
|
|
|
|
In this example, the default data is an array. Later, when you use the
|
|
:ref:`data_class <form-data-class>` option to bind data directly to
|
|
objects, your default data will be an instance of that object.
|
|
|
|
.. _component-form-intro-rendering-form:
|
|
|
|
Rendering the Form
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
Now that the form has been created, the next step is to render it. This is
|
|
done by passing a special form "view" object to your template (notice the
|
|
``$form->createView()`` in the controller above) and using a set of
|
|
:ref:`form helper functions <reference-form-twig-functions>`:
|
|
|
|
.. code-block:: html+twig
|
|
|
|
{{ form_start(form) }}
|
|
{{ form_widget(form) }}
|
|
|
|
<input type="submit">
|
|
{{ form_end(form) }}
|
|
|
|
.. image:: /_images/form/simple-form.png
|
|
:alt: An HTML form showing a text box labelled "Task", three select boxes for a year, month and day labelled "Due date" and a button labelled "Create Task".
|
|
|
|
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). While this is
|
|
convenient, 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 :doc:`form customization </form/form_customization>` article.
|
|
|
|
Changing a Form's Method and Action
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
By default, a form is submitted to the same URI that rendered the form with
|
|
an HTTP POST request. This behavior can be changed using the :ref:`form-option-action`
|
|
and :ref:`form-option-method` options (the ``method`` option is also used
|
|
by :method:`Symfony\\Component\\Form\\Form::handleRequest` to determine whether a form has been submitted):
|
|
|
|
.. configuration-block::
|
|
|
|
.. code-block:: php-symfony
|
|
|
|
// src/Controller/DefaultController.php
|
|
namespace App\Controller;
|
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class DefaultController extends AbstractController
|
|
{
|
|
public function search(): Response
|
|
{
|
|
$formBuilder = $this->createFormBuilder(null, [
|
|
'action' => '/search',
|
|
'method' => 'GET',
|
|
]);
|
|
|
|
// ...
|
|
}
|
|
}
|
|
|
|
.. code-block:: php-standalone
|
|
|
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
|
|
|
// ...
|
|
|
|
$formBuilder = $formFactory->createBuilder(FormType::class, null, [
|
|
'action' => '/search',
|
|
'method' => 'GET',
|
|
]);
|
|
|
|
// ...
|
|
|
|
.. _component-form-intro-handling-submission:
|
|
|
|
Handling Form Submissions
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
To handle form submissions, use the :method:`Symfony\\Component\\Form\\Form::handleRequest`
|
|
method:
|
|
|
|
.. configuration-block::
|
|
|
|
.. code-block:: php-symfony
|
|
|
|
// src/Controller/TaskController.php
|
|
namespace App\Controller;
|
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class TaskController extends AbstractController
|
|
{
|
|
public function new(Request $request): Response
|
|
{
|
|
$form = $this->createFormBuilder()
|
|
->add('task', TextType::class)
|
|
->add('dueDate', DateType::class)
|
|
->getForm();
|
|
|
|
$form->handleRequest($request);
|
|
|
|
if ($form->isSubmitted() && $form->isValid()) {
|
|
$data = $form->getData();
|
|
|
|
// ... perform some action, such as saving the data to the database
|
|
|
|
return $this->redirectToRoute('task_success');
|
|
}
|
|
|
|
// ...
|
|
}
|
|
}
|
|
|
|
.. code-block:: php-standalone
|
|
|
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
|
|
// ...
|
|
|
|
$form = $formFactory->createBuilder()
|
|
->add('task', TextType::class)
|
|
->add('dueDate', DateType::class)
|
|
->getForm();
|
|
|
|
$request = Request::createFromGlobals();
|
|
|
|
$form->handleRequest($request);
|
|
|
|
if ($form->isSubmitted() && $form->isValid()) {
|
|
$data = $form->getData();
|
|
|
|
// ... perform some action, such as saving the data to the database
|
|
|
|
$response = new RedirectResponse('/task/success');
|
|
$response->prepare($request);
|
|
|
|
return $response->send();
|
|
}
|
|
|
|
// ...
|
|
|
|
.. warning::
|
|
|
|
The form's ``createView()`` method should be called *after* ``handleRequest()`` is
|
|
called. Otherwise, when using :doc:`form events </form/events>`, changes done
|
|
in the ``*_SUBMIT`` events won't be applied to the view (like validation errors).
|
|
|
|
This defines a common form "workflow", which contains 3 different possibilities:
|
|
|
|
#. On the initial GET request (i.e. when the user "surfs" to your page),
|
|
build your form and render it;
|
|
|
|
If the request is a POST, process the submitted data (via :method:`Symfony\\Component\\Form\\Form::handleRequest`).
|
|
|
|
Then:
|
|
|
|
#. if the form is invalid, re-render the form (which will now contain errors);
|
|
#. if the form is valid, perform some action and redirect.
|
|
|
|
Luckily, you don't need to decide whether or not a form has been submitted.
|
|
Just pass the current request to the :method:`Symfony\\Component\\Form\\Form::handleRequest`
|
|
method. Then, the Form component will do all the necessary work for you.
|
|
|
|
.. _component-form-intro-validation:
|
|
|
|
Form Validation
|
|
~~~~~~~~~~~~~~~
|
|
|
|
The easiest way to add validation to your form is via the ``constraints``
|
|
option when building each field:
|
|
|
|
.. configuration-block::
|
|
|
|
.. code-block:: php-symfony
|
|
|
|
// src/Controller/DefaultController.php
|
|
namespace App\Controller;
|
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\Validator\Constraints as Assert;
|
|
|
|
class DefaultController extends AbstractController
|
|
{
|
|
public function new(Request $request): Response
|
|
{
|
|
$form = $this->createFormBuilder()
|
|
->add('task', TextType::class, [
|
|
'constraints' => new Assert\NotBlank(),
|
|
])
|
|
->add('dueDate', DateType::class, [
|
|
'constraints' => [
|
|
new Assert\NotBlank(),
|
|
new Assert\Type(\DateTime::class),
|
|
],
|
|
])
|
|
->getForm();
|
|
// ...
|
|
}
|
|
}
|
|
|
|
.. code-block:: php-standalone
|
|
|
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
use Symfony\Component\Validator\Constraints as Assert;
|
|
|
|
$form = $formFactory->createBuilder()
|
|
->add('task', TextType::class, [
|
|
'constraints' => new Assert\NotBlank(),
|
|
])
|
|
->add('dueDate', DateType::class, [
|
|
'constraints' => [
|
|
new Assert\NotBlank(),
|
|
new Assert\Type(\DateTime::class),
|
|
],
|
|
])
|
|
->getForm();
|
|
|
|
When the form is bound, these validation constraints will be applied automatically
|
|
and the errors will display next to the fields on error.
|
|
|
|
.. note::
|
|
|
|
For a list of all of the built-in validation constraints, see
|
|
:doc:`/reference/constraints`.
|
|
|
|
Accessing Form Errors
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
You can use the :method:`Symfony\\Component\\Form\\FormInterface::getErrors`
|
|
method to access the list of errors. It returns a
|
|
:class:`Symfony\\Component\\Form\\FormErrorIterator` instance::
|
|
|
|
$form = ...;
|
|
|
|
// ...
|
|
|
|
// a FormErrorIterator instance, but only errors attached to this
|
|
// form level (e.g. global errors)
|
|
$errors = $form->getErrors();
|
|
|
|
// a FormErrorIterator instance, but only errors attached to the
|
|
// "firstName" field
|
|
$errors = $form['firstName']->getErrors();
|
|
|
|
// a FormErrorIterator instance including child forms in a flattened structure
|
|
// use getOrigin() to determine the form causing the error
|
|
$errors = $form->getErrors(true);
|
|
|
|
// a FormErrorIterator instance including child forms without flattening the output structure
|
|
$errors = $form->getErrors(true, false);
|
|
|
|
Clearing Form Errors
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Any errors can be manually cleared using the
|
|
:method:`Symfony\\Component\\Form\\ClearableErrorsInterface::clearErrors`
|
|
method. This is useful when you'd like to validate the form without showing
|
|
validation errors to the user (i.e. during a partial AJAX submission or
|
|
:doc:`dynamic form modification </form/dynamic_form_modification>`).
|
|
|
|
Because clearing the errors makes the form valid,
|
|
:method:`Symfony\\Component\\Form\\ClearableErrorsInterface::clearErrors`
|
|
should only be called after testing whether the form is valid.
|
|
|
|
Learn more
|
|
----------
|
|
|
|
.. toctree::
|
|
:maxdepth: 1
|
|
:glob:
|
|
|
|
/form/*
|
|
|
|
.. _Twig: https://twig.symfony.com
|
|
.. _`Twig Configuration`: https://twig.symfony.com/doc/3.x/intro.html
|