Forms

Screencast

Do you prefer video tutorials? Check out the Symfony Forms screencast series.

Creating and processing HTML forms is hard and repetitive. You need to deal withrendering HTML form fields, validating submitted data, mapping the form datainto objects and a lot more. Symfony includes a powerful form feature thatprovides all these features and many more for truly complex scenarios.

Installation

In applications using Symfony Flex, run this command toinstall the form feature before using it:

  1. $ composer require symfony/form

Usage

The recommended workflow when working with Symfony forms is the following:

  • Build the form in a Symfony controller or using a dedicated form class;
  • Render the form in a template so the user can edit and submit it;
  • Process the form to validate the submitted data, transform it into PHPdata and do something with it (e.g. persist it in a database).Each of these steps is explained in detail in the next sections. To makeexamples easier to follow, all of them assume that you're building a simple Todolist application that displays "tasks".

Users create and edit tasks using Symfony forms. Each task is an instance of thefollowing Task class:

  1. // src/Entity/Task.php
  2. namespace App\Entity;
  3.  
  4. class Task
  5. {
  6. protected $task;
  7. protected $dueDate;
  8.  
  9. public function getTask()
  10. {
  11. return $this->task;
  12. }
  13.  
  14. public function setTask($task)
  15. {
  16. $this->task = $task;
  17. }
  18.  
  19. public function getDueDate()
  20. {
  21. return $this->dueDate;
  22. }
  23.  
  24. public function setDueDate(\DateTime $dueDate = null)
  25. {
  26. $this->dueDate = $dueDate;
  27. }
  28. }

This class is a "plain-old-PHP-object" because, so far, it has nothing to dowith Symfony or any other library. It's a normal PHP object that directly solvesa problem inside your application (i.e. the need to represent a task in yourapplication). But you can also edit Doctrine entities in thesame way.

Form Types

Before creating your first Symfony form, it's important to understand theconcept of "form type". In other projects, it's common to differentiate between"forms" and "form fields". In Symfony, all of them are "form types":

  • a single <input type="text"> form field is a "form type" (e.g. TextType);
  • a group of several HTML fields used to input a postal address is a "form type"(e.g. PostalAddressType);
  • an entire <form> with multiple fields to edit a user profile is a"form type" (e.g. UserProfileType).This may be confusing at first, but it will feel natural to you soon enough.Besides, it simplifies code and makes "composing" and "embedding" form fieldsmuch easier to implement.

There are tens of form types provided by Symfonyand you can also create your own form types.

Building Forms

Symfony provides a "form builder" object which allows you to describe the formfields using a fluent interface. Later, this builder creates the actual formobject used to render and process contents.

Creating Forms in Controllers

If your controller extends from the AbstractController,use the createFormBuilder() helper:

  1. // src/Controller/TaskController.php
  2. namespace App\Controller;
  3.  
  4. use App\Entity\Task;
  5. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  6. use Symfony\Component\Form\Extension\Core\Type\DateType;
  7. use Symfony\Component\Form\Extension\Core\Type\SubmitType;
  8. use Symfony\Component\Form\Extension\Core\Type\TextType;
  9. use Symfony\Component\HttpFoundation\Request;
  10.  
  11. class TaskController extends AbstractController
  12. {
  13. public function new(Request $request)
  14. {
  15. // creates a task object and initializes some data for this example
  16. $task = new Task();
  17. $task->setTask('Write a blog post');
  18. $task->setDueDate(new \DateTime('tomorrow'));
  19.  
  20. $form = $this->createFormBuilder($task)
  21. ->add('task', TextType::class)
  22. ->add('dueDate', DateType::class)
  23. ->add('save', SubmitType::class, ['label' => 'Create Task'])
  24. ->getForm();
  25.  
  26. // ...
  27. }
  28. }

If your controller does not extend from AbstractController, you'll need tofetch services in your controller anduse the createBuilder() method of the form.factory service.

In this example, you've added two fields to your form - task and dueDate- corresponding to the task and dueDate properties of the Taskclass. You've also assigned each a form type (e.g. TextTypeand DateType), represented by its fully qualified class name. Finally, youadded a submit button with a custom label for submitting the form to the server.

Creating Form Classes

Symfony recommends to put as little logic as possible in controllers. That's whyit's better to move complex forms to dedicated classes instead of defining themin controller actions. Besides, forms defined in classes can be reused inmultiple actions and services.

Form classes are form types that implementFormTypeInterface. However, it's better toextend from AbstractType, which alreadyimplements the interface and provides some utilities:

  1. // src/Form/Type/TaskType.php
  2. namespace App\Form\Type;
  3.  
  4. use Symfony\Component\Form\AbstractType;
  5. use Symfony\Component\Form\Extension\Core\Type\DateType;
  6. use Symfony\Component\Form\Extension\Core\Type\SubmitType;
  7. use Symfony\Component\Form\Extension\Core\Type\TextType;
  8. use Symfony\Component\Form\FormBuilderInterface;
  9.  
  10. class TaskType extends AbstractType
  11. {
  12. public function buildForm(FormBuilderInterface $builder, array $options)
  13. {
  14. $builder
  15. ->add('task', TextType::class)
  16. ->add('dueDate', DateType::class)
  17. ->add('save', SubmitType::class)
  18. ;
  19. }
  20. }

Tip

Install the MakerBundle in your project to generate form classes usingthe make:form and make:registration-form commands.

The form class contains all the directions needed to create the task form. Incontrollers extending from the AbstractController,use the createForm() helper (otherwise, use the create() method of theform.factory service):

  1. // src/Controller/TaskController.php
  2. use App\Form\Type\TaskType;
  3. // ...
  4.  
  5. class TaskController extends AbstractController
  6. {
  7. public function new()
  8. {
  9. // creates a task object and initializes some data for this example
  10. $task = new Task();
  11. $task->setTask('Write a blog post');
  12. $task->setDueDate(new \DateTime('tomorrow'));
  13.  
  14. $form = $this->createForm(TaskType::class, $task);
  15.  
  16. // ...
  17. }
  18. }

Every form needs to know the name of the class that holds the underlying data(e.g. App\Entity\Task). Usually, this is just guessed based off of theobject passed to the second argument to createForm() (i.e. $task).Later, when you begin embedding forms, this will nolonger be sufficient.

So, while not always necessary, it's generally a good idea to explicitly specifythe data_class option by adding the following to your form type class:

  1. // src/Form/Type/TaskType.php
  2. use App\Entity\Task;
  3. use Symfony\Component\OptionsResolver\OptionsResolver;
  4. // ...
  5.  
  6. class TaskType extends AbstractType
  7. {
  8. // ...
  9.  
  10. public function configureOptions(OptionsResolver $resolver)
  11. {
  12. $resolver->setDefaults([
  13. 'data_class' => Task::class,
  14. ]);
  15. }
  16. }

Rendering Forms

Now that the form has been created, the next step is to render it. Instead ofpassing the entire form object to the template, use the createView() methodto build another object with the visual representation of the form:

  1. // src/Controller/TaskController.php
  2. namespace App\Controller;
  3.  
  4. use App\Entity\Task;
  5. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  6. use Symfony\Component\Form\Extension\Core\Type\DateType;
  7. use Symfony\Component\Form\Extension\Core\Type\SubmitType;
  8. use Symfony\Component\Form\Extension\Core\Type\TextType;
  9. use Symfony\Component\HttpFoundation\Request;
  10.  
  11. class TaskController extends AbstractController
  12. {
  13. public function new(Request $request)
  14. {
  15. $task = new Task();
  16. // ...
  17.  
  18. $form = $this->createForm(TaskType::class, $task);
  19.  
  20. return $this->render('task/new.html.twig', [
  21. 'form' => $form->createView(),
  22. ]);
  23. }
  24. }

Then, use some form helper functions torender the form contents:

  1. {# templates/task/new.html.twig #}
  2. {{ form(form) }}

That's it! The form() function renders allfields and the <form> start and end tags. By default, the form method isPOST and the target URL is the same that displayed the form, butyou can change both.

Notice how the rendered task input field has the value of the taskproperty from the $task object (i.e. "Write a blog post"). This is the firstjob of a form: to take data from an object and translate it into a format that'ssuitable for being rendered in an HTML form.

Tip

The form system is smart enough to access the value of the protectedtask property via the getTask() and setTask() methods on theTask class. Unless a property is public, it must have a "getter" and"setter" method so that Symfony can get and put data onto the property. Fora boolean property, you can use an "isser" or "hasser" method (e.g.isPublished() or hasReminder()) instead of a getter (e.g.getPublished() or getReminder()).

As short as this rendering is, it's not very flexible. Usually, you'll need morecontrol about how the entire form or some of its fields look. For example, thanksto the Bootstrap 4 integration with Symfony forms youcan set this option to generate forms compatible with the Bootstrap 4 CSS framework:

  • YAML
  1. # config/packages/twig.yaml
  2. twig:
  3. form_themes: ['bootstrap_4_layout.html.twig']
  • XML
  1. <!-- config/packages/twig.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:twig="http://symfony.com/schema/dic/twig"
  6. xsi:schemaLocation="http://symfony.com/schema/dic/services
  7. https://symfony.com/schema/dic/services/services-1.0.xsd
  8. http://symfony.com/schema/dic/twig
  9. https://symfony.com/schema/dic/twig/twig-1.0.xsd">
  10.  
  11. <twig:config>
  12. <twig:form-theme>bootstrap_4_layout.html.twig</twig:form-theme>
  13. <!-- ... -->
  14. </twig:config>
  15. </container>
  • PHP
  1. // config/packages/twig.php
  2. $container->loadFromExtension('twig', [
  3. 'form_themes' => [
  4. 'bootstrap_4_layout.html.twig',
  5. ],
  6.  
  7. // ...
  8. ]);

The built-in Symfony form themes includeBootstrap 3 and 4 and Foundation 5. You can alsocreate your own Symfony form theme.

In addition to form themes, Symfony allows you tocustomize the way fields are rendered withmultiple functions to render each field part separately (widgets, labels,errors, help messages, etc.)

Processing Forms

The recommended way of processing forms is touse a single action for both rendering the form and handling the form submit.You can use separate actions, but using one action simplifies everything whilekeeping the code concise and maintainable.

Processing a form means to translate user-submitted data back to the propertiesof an object. To make this happen, the submitted data from the user must bewritten into the form object:

  1. // ...
  2. use Symfony\Component\HttpFoundation\Request;
  3.  
  4. public function new(Request $request)
  5. {
  6. // just setup a fresh $task object (remove the example data)
  7. $task = new Task();
  8.  
  9. $form = $this->createForm(TaskType::class, $task);
  10.  
  11. $form->handleRequest($request);
  12. if ($form->isSubmitted() && $form->isValid()) {
  13. // $form->getData() holds the submitted values
  14. // but, the original `$task` variable has also been updated
  15. $task = $form->getData();
  16.  
  17. // ... perform some action, such as saving the task to the database
  18. // for example, if Task is a Doctrine entity, save it!
  19. // $entityManager = $this->getDoctrine()->getManager();
  20. // $entityManager->persist($task);
  21. // $entityManager->flush();
  22.  
  23. return $this->redirectToRoute('task_success');
  24. }
  25.  
  26. return $this->render('task/new.html.twig', [
  27. 'form' => $form->createView(),
  28. ]);
  29. }

This controller follows a common pattern for handling forms and has threepossible paths:

  • When initially loading the page in a browser, the form hasn't been submittedyet and $form->isSubmitted() returns false. So, the form is createdand rendered;
  • When the user submits the form, handleRequest()recognizes this and immediately writes the submitted data back into thetask and dueDate properties of the $task object. Then this objectis validated (validation is explained in the next section). If it is invalid,isValid() returnsfalse and the form is rendered again, but now with validation errors;
  • When the user submits the form with valid data, the submitted data is againwritten into the form, but this time isValid()returns true. Now you have the opportunity to perform some actions usingthe $task object (e.g. persisting it to the database) before redirectingthe user to some other page (e.g. a "thank you" or "success" page);

Note

Redirecting a user after a successful form submission is a best practicethat prevents the user from being able to hit the "Refresh" button oftheir browser and re-post the data.

Caution

The createView() method should be called after handleRequest() iscalled. Otherwise, when using form events, changes donein the *_SUBMIT events won't be applied to the view (like validation errors).

If you need more control over exactly when your form is submitted or whichdata is passed to it, you canuse the submit() method to handle form submissions.

Validating Forms

In the previous section, you learned how a form can be submitted with validor invalid data. In Symfony, the question isn't whether the "form" is valid, butwhether or not the underlying object ($task in this example) is valid afterthe form has applied the submitted data to it. Calling $form->isValid() is ashortcut that asks the $task object whether or not it has valid data.

Before using validation, add support for it in your application:

  1. $ composer require symfony/validator

Validation is done by adding a set of rules (called constraints) to a class. Tosee this in action, add validation constraints so that the task field cannotbe empty and the dueDate field cannot be empty and must be a valid DateTimeobject.

  • Annotations
  1. // src/Entity/Task.php
  2. namespace App\Entity;
  3.  
  4. use Symfony\Component\Validator\Constraints as Assert;
  5.  
  6. class Task
  7. {
  8. /**
  9. * @Assert\NotBlank
  10. */
  11. public $task;
  12.  
  13. /**
  14. * @Assert\NotBlank
  15. * @Assert\Type("\DateTime")
  16. */
  17. protected $dueDate;
  18. }
  • YAML
  1. # config/validator/validation.yaml
  2. App\Entity\Task:
  3. properties:
  4. task:
  5. - NotBlank: ~
  6. dueDate:
  7. - NotBlank: ~
  8. - Type: \DateTime
  • XML
  1. <!-- config/validator/validation.xml -->
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
  6. https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
  7.  
  8. <class name="App\Entity\Task">
  9. <property name="task">
  10. <constraint name="NotBlank"/>
  11. </property>
  12. <property name="dueDate">
  13. <constraint name="NotBlank"/>
  14. <constraint name="Type">\DateTime</constraint>
  15. </property>
  16. </class>
  17. </constraint-mapping>
  • PHP
  1. // src/Entity/Task.php
  2. use Symfony\Component\Validator\Constraints\NotBlank;
  3. use Symfony\Component\Validator\Constraints\Type;
  4. use Symfony\Component\Validator\Mapping\ClassMetadata;
  5.  
  6. class Task
  7. {
  8. // ...
  9.  
  10. public static function loadValidatorMetadata(ClassMetadata $metadata)
  11. {
  12. $metadata->addPropertyConstraint('task', new NotBlank());
  13.  
  14. $metadata->addPropertyConstraint('dueDate', new NotBlank());
  15. $metadata->addPropertyConstraint(
  16. 'dueDate',
  17. new Type(\DateTime::class)
  18. );
  19. }
  20. }

That's it! If you re-submit the form with invalid data, you'll see thecorresponding errors printed out with the form. Read theSymfony validation documentation to learn more about thispowerful feature.

Other Common Form Features

Passing Options to Forms

If you create forms in classes, when buildingthe form in the controller you can pass custom options to it as the third optionalargument of createForm():

  1. // src/Controller/TaskController.php
  2. use App\Form\Type\TaskType;
  3. // ...
  4.  
  5. class TaskController extends AbstractController
  6. {
  7. public function new()
  8. {
  9. $task = new Task();
  10. // use some PHP logic to decide if this form field is required or not
  11. $dueDateIsRequired = ...
  12.  
  13. $form = $this->createForm(TaskType::class, $task, [
  14. 'require_due_date' => $dueDateIsRequired,
  15. ]);
  16.  
  17. // ...
  18. }
  19. }

If you try to use the form now, you'll see an error message: The option"require_due_date" does not exist. That's because forms must declare all theoptions they accept using the configureOptions() method:

  1. // src/Form/Type/TaskType.php
  2. use Symfony\Component\OptionsResolver\OptionsResolver;
  3. // ...
  4.  
  5. class TaskType extends AbstractType
  6. {
  7. // ...
  8.  
  9. public function configureOptions(OptionsResolver $resolver)
  10. {
  11. $resolver->setDefaults([
  12. // ...,
  13. 'require_due_date' => false,
  14. ]);
  15.  
  16. // you can also define the allowed types, allowed values and
  17. // any other feature supported by the OptionsResolver component
  18. $resolver->setAllowedTypes('require_due_date', 'bool');
  19. }
  20. }

Now you can use this new form option inside the buildForm() method:

  1. // src/Form/Type/TaskType.php
  2. namespace App\Form\Type;
  3.  
  4. use Symfony\Component\Form\AbstractType;
  5. use Symfony\Component\Form\Extension\Core\Type\DateType;
  6. use Symfony\Component\Form\FormBuilderInterface;
  7.  
  8. class TaskType extends AbstractType
  9. {
  10. public function buildForm(FormBuilderInterface $builder, array $options)
  11. {
  12. $builder
  13. // ...
  14. ->add('dueDate', DateType::class, [
  15. 'required' => $options['require_due_date'],
  16. ])
  17. ;
  18. }
  19.  
  20. // ...
  21. }

Form Type Options

Each form type has a number of options to configure it, asexplained in the Symfony form types reference.Two commonly used options are required and label.

The required Option

The most common option is the required option, which can be applied to anyfield. By default, this option is set to true, meaning that HTML5-readybrowsers will require to fill in all fields before submitting the form.

If you don't want this behavior, eitherdisable client-side validation for theentire form or set the required option to false on one or more fields:

  1. ->add('dueDate', DateType::class, [
  2. 'required' => false,
  3. ])

The required option does not perform any server-side validation. If a usersubmits a blank value for the field (either with an old browser or a webservice, for example), it will be accepted as a valid value unless you also useSymfony's NotBlank or NotNull validation constraints.

The label Option

By default, the label of form fields are the humanized version of theproperty name (user -> User; postalAddress -> Postal Address).Set the label option on fields to define their labels explicitly:

  1. ->add('dueDate', DateType::class, [
  2. // set it to FALSE to not display the label for this field
  3. 'label' => 'To Be Completed Before',
  4. ])

Tip

By default, <label> tags of required fields are rendered with arequired CSS class, so you can display an asterisk for requiredfields applying these CSS styles:

  1. label.required:before {
  2. content: "*";
  3. }

Changing the Action and HTTP Method

By default, a form will be submitted via an HTTP POST request to the sameURL under which the form was rendered. When building the form in the controller,use the setAction() and setMethod() methods to change this:

  1. // src/Controller/TaskController.php
  2. namespace App\Controller;
  3.  
  4. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  5. use Symfony\Component\Form\Extension\Core\Type\DateType;
  6. use Symfony\Component\Form\Extension\Core\Type\SubmitType;
  7. use Symfony\Component\Form\Extension\Core\Type\TextType;
  8.  
  9. class TaskController extends AbstractController
  10. {
  11. public function new()
  12. {
  13. // ...
  14.  
  15. $form = $this->createFormBuilder($task)
  16. ->setAction($this->generateUrl('target_route'))
  17. ->setMethod('GET')
  18. // ...
  19. ->getForm();
  20.  
  21. // ...
  22. }
  23. }

When building the form in a class, pass the action and method as form options:

  1. // src/Controller/TaskController.php
  2. namespace App\Controller;
  3.  
  4. use App\Form\TaskType;
  5. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  6.  
  7. class TaskController extends AbstractController
  8. {
  9. public function new()
  10. {
  11. // ...
  12.  
  13. $form = $this->createForm(TaskType::class, $task, [
  14. 'action' => $this->generateUrl('target_route'),
  15. 'method' => 'GET',
  16. ]);
  17.  
  18. // ...
  19. }
  20. }

Finally, you can override the action and method in the template by passing themto the form() or the form_start() helper functions:

  1. {# templates/task/new.html.twig #}
  2. {{ form_start(form, {'action': path('target_route'), 'method': 'GET'}) }}

Note

If the form's method is not GET or POST, but PUT, PATCH orDELETE, Symfony will insert a hidden field with the name methodthat stores this method. The form will be submitted in a normal POSTrequest, but [_Symfony's routing]($b8585f355a26145b.md) is capable of detecting the_method parameter and will interpret it as a PUT, PATCH orDELETE request. See the http_method_override option.

Changing the Form Name

If you inspect the HTML contents of the rendered form, you'll see that the<form> name and the field names are generated from the type class name(e.g. <form name="task" …> and <select name="task[dueDate][date][month]" …>).

If you want to modify this, use the createNamed()method:

  1. // src/Controller/TaskController.php
  2. use App\Form\TaskType;
  3. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  4.  
  5. class TaskController extends AbstractController
  6. {
  7. public function newAction()
  8. {
  9. $task = ...;
  10. $form = $this->get('form.factory')->createNamed('my_name', TaskType::class, $task);
  11.  
  12. // ...
  13. }
  14. }

You can even suppress the name completely by setting it to an empty string.

Client-Side HTML Validation

Thanks to HTML5, many browsers can natively enforce certain validationconstraints on the client side. The most common validation is activated byadding a required attribute on fields that are required. For browsersthat support HTML5, this will result in a native browser message being displayedif the user tries to submit the form with that field blank.

Generated forms take full advantage of this new feature by adding sensible HTMLattributes that trigger the validation. The client-side validation, however, canbe disabled by adding the novalidate attribute to the <form> tag orformnovalidate to the submit tag. This is especially useful when you want totest your server-side validation constraints, but are being prevented by yourbrowser from, for example, submitting blank fields.

  1. {# templates/task/new.html.twig #}
  2. {{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}
  3. {{ form_widget(form) }}
  4. {{ form_end(form) }}

Form Type Guessing

If the object handled by the form includes validation constraints, Symfony canintrospect that metadata to guess the type of your field and set it up for you.In the above example, Symfony can guess from the validation rules that both thetask field is a normal TextType field and the dueDate field is aDateType field.

When building the form, omit the second argument to the add() method, orpass null to it, to enable Symfony's "guessing mechanism":

  1. // src/Form/Type/TaskType.php
  2. namespace App\Form\Type;
  3.  
  4. use Symfony\Component\Form\AbstractType;
  5. use Symfony\Component\Form\Extension\Core\Type\DateType;
  6. use Symfony\Component\Form\Extension\Core\Type\SubmitType;
  7. use Symfony\Component\Form\Extension\Core\Type\TextType;
  8. use Symfony\Component\Form\FormBuilderInterface;
  9.  
  10. class TaskType extends AbstractType
  11. {
  12. public function buildForm(FormBuilderInterface $builder, array $options)
  13. {
  14. $builder
  15. // if you don't define field options, you can omit the second argument
  16. ->add('task')
  17. // if you define field options, pass NULL as second argument
  18. ->add('dueDate', null, ['required' => false])
  19. ->add('save', SubmitType::class)
  20. ;
  21. }
  22. }

Caution

When using a specific form validation group,the field type guesser will still consider all validation constraints whenguessing your field types (including constraints that are not part of thevalidation group(s) being used).

Form Type Options Guessing

When the guessing mechanism is enabled for some field (i.e. you omit or passnull as the second argument to add()), in addition to its form type,the following options can be guessed too:

  • required
  • The required option can be guessed based on the validation rules (i.e. isthe field NotBlank or NotNull) or the Doctrine metadata (i.e. is thefield nullable). This is very useful, as your client-side validation willautomatically match your validation rules.
  • maxlength
  • If the field is some sort of text field, then the maxlength option attributecan be guessed from the validation constraints (if Length or Range is used)or from the Doctrine metadata (via the field's length).If you'd like to change one of the guessed values, override it by passing theoption in the options field array:
  1. ->add('task', null, ['attr' => ['maxlength' => 4]])

New in version 4.3: Starting from Symfony 4.3, Doctrine metadata is introspectedto add automatic validation constraints.

Unmapped Fields

When editing an object via a form, all form fields are considered properties ofthe object. Any fields on the form that do not exist on the object will cause anexception to be thrown.

If you need extra fields in the form that won't be stored in the object (forexample to add an "I agree with these terms" checkbox), set the mappedoption to false in those fields:

  1. use Symfony\Component\Form\FormBuilderInterface;
  2.  
  3. public function buildForm(FormBuilderInterface $builder, array $options)
  4. {
  5. $builder
  6. ->add('task')
  7. ->add('dueDate')
  8. ->add('agreeTerms', CheckboxType::class, ['mapped' => false])
  9. ->add('save', SubmitType::class)
  10. ;
  11. }

These "unmapped fields" can be set and accessed in a controller with:

  1. $form->get('agreeTerms')->getData();
  2. $form->get('agreeTerms')->setData(true);

Additionally, if there are any fields on the form that aren't included inthe submitted data, those fields will be explicitly set to null.

Learn more

When building forms, keep in mind that the first goal of a form is to translatedata from an object (Task) to an HTML form so that the user can modify thatdata. The second goal of a form is to take the data submitted by the user and tore-apply it to the object.

There's a lot more to learn and a lot of powerful tricks in the Symfony forms:

Reference:

Advanced Features:

Form Themes and Customization:

Events:

Validation:

Misc.: