spacer
spacer
DOWNLOAD NOW
  • The Book
  • The Cookbook
  • The Components
  • Reference
  • Glossary
  • Index
  • Bundles
  • Symfony CMF
  • Security Advisories
  • Docs for symfony 1.x
  • Contributing
  • Talks
  • Trainings
  • Books

Table of Contents

  • Forms
    • Creating a Simple Form
      • Building the Form
      • Rendering the Form
      • Handling Form Submissions
    • Form Validation
      • Validation Groups
      • Groups based on Submitted Data
    • Built-in Field Types
      • Text Fields
      • Choice Fields
      • Date and Time Fields
      • Other Fields
      • Field Groups
      • Hidden Fields
      • Base Fields
      • Field Type Options
    • Field Type Guessing
      • Field Type Options Guessing
    • Rendering a Form in a Template
      • Rendering each Field by Hand
      • Twig Template Function Reference
    • Creating Form Classes
    • Forms and Doctrine
    • Embedded Forms
      • Embedding a Single Object
      • Embedding a Collection of Forms
    • Form Theming
      • Form Fragment Naming
      • Template Fragment Inheritance
      • Global Form Theming
        • Twig
        • PHP
    • CSRF Protection
    • Using a Form without a Class
      • Adding Validation
    • Final Thoughts
    • Learn more from the Cookbook

Questions & Feedback

Found a typo or an error?
Want to improve this document? Edit it.

Need support or have a technical question?
Post to the user mailing-list.

spacer
This work is licensed under a
Creative Commons
Attribution-Share Alike 3.0
Unported License.

Master Symfony2 fundamentals

Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).
trainings.sensiolabs.com

Symfony hosting done right

ServerGrove, outstanding support at the right price for your Symfony hosting needs.
servergrove.com

Discover the SensioLabs Support

Access to the SensioLabs Competency Center for an exclusive and tailor-made support on Symfony
sensiolabs.com
spacer
Home » Documentation » The Book » Forms
2.1 version spacer
  • 2.0 version
  • master version

  • French
  • Italian

Forms

Forms¶

Dealing with HTML forms is one of the most common - and challenging - tasks for a web developer. Symfony2 integrates a Form component that makes dealing with forms easy. In this chapter, you'll build a complex form from the ground-up, learning the most important features of the form library along the way.

Note

The Symfony form component is a standalone library that can be used outside of Symfony2 projects. For more information, see the Symfony2 Form Component on Github.

Creating a Simple Form¶

Suppose you're building a simple todo list application that will need to display "tasks". Because your users will need to edit and create tasks, you're going to need to build a form. But before you begin, first focus on the generic Task class that represents and stores the data for a single task:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// src/Acme/TaskBundle/Entity/Task.php
namespace Acme\TaskBundle\Entity;

class Task
{
    protected $task;

    protected $dueDate;

    public function getTask()
    {
        return $this->task;
    }
    public function setTask($task)
    {
        $this->task = $task;
    }

    public function getDueDate()
    {
        return $this->dueDate;
    }
    public function setDueDate(\DateTime $dueDate = null)
    {
        $this->dueDate = $dueDate;
    }
}

Note

If you're coding along with this example, create the AcmeTaskBundle first by running the following command (and accepting all of the default options):

1
$ php app/console generate:bundle --namespace=Acme/TaskBundle

This class is a "plain-old-PHP-object" because, so far, it has nothing to do with Symfony or any other library. It's quite simply a normal PHP object that directly solves a problem inside your application (i.e. the need to represent a task in your application). Of course, by the end of this chapter, you'll be able to submit data to a Task instance (via an HTML form), validate its data, and persist it to the database.

Building the Form¶

Now that you've created a Task class, the next step is to create and render the actual HTML form. In Symfony2, this is done by building a form object and then rendering it in a template. For now, this can all be done from inside a controller:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// src/Acme/TaskBundle/Controller/DefaultController.php
namespace Acme\TaskBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Acme\TaskBundle\Entity\Task;
use Symfony\Component\HttpFoundation\Request;

class DefaultController extends Controller
{
    public function newAction(Request $request)
    {
        // create a task and give it some dummy data for this example
        $task = new Task();
        $task->setTask('Write a blog post');
        $task->setDueDate(new \DateTime('tomorrow'));

        $form = $this->createFormBuilder($task)
            ->add('task', 'text')
            ->add('dueDate', 'date')
            ->getForm();

        return $this->render('AcmeTaskBundle:Default:new.html.twig', array(
            'form' => $form->createView(),
        ));
    }
}

Tip

This example shows you how to build your form directly in the controller. Later, in the "Creating Form Classes" section, you'll learn how to build your form in a standalone class, which is recommended as your form becomes reusable.

Creating a form requires relatively little code because Symfony2 form objects are built with a "form builder". The form builder's purpose is to allow you to write simple form "recipes", and have it do all the heavy-lifting of actually building the form.

In this example, you've added two fields to your form - task and dueDate - corresponding to the task and dueDate properties of the Task class. You've also assigned each a "type" (e.g. text, date), which, among other things, determines which HTML form tag(s) is rendered for that field.

Symfony2 comes with many built-in types that will be discussed shortly (see Built-in Field Types).

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 form helper functions:

  • Twig
    1
    2
    3
    4
    5
    6
    {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #}
    <form action="{{ path('task_new') }}" method="post" {{ form_enctype(form) }}>
        {{ form_widget(form) }}
    
        <input type="submit" />
    </form>
    
  • PHP
    1
    2
    3
    4
    5
    6
    <!-- src/Acme/TaskBundle/Resources/views/Default/new.html.php -->
    <form action="<?php echo $view['router']->generate('task_new') ?>" method="post" <?php echo $view['form']->enctype($form) ?> >
        <?php echo $view['form']->widget($form) ?>
    
        <input type="submit" />
    </form>
    
spacer

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.

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 "Rendering a Form in a 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"). This is the first job of a form: to take data from an object and translate it into a format that's suitable for being rendered in an HTML form.

Tip

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

New in version 2.1: Support for "hasser" methods was added in Symfony 2.1.

Handling Form Submissions¶

The second job of a form is to translate user-submitted data back to the properties of an object. To make this happen, the submitted data from the user must be bound to the form. Add the following functionality to your controller:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ...
use Symfony\Component\HttpFoundation\Request;

public function newAction(Request $request)
{
    // just setup a fresh $task object (remove the dummy data)
    $task = new Task();

    $form = $this->createFormBuilder($task)
        ->add('task', 'text')
        ->add('dueDate', 'date')
        ->getForm();

    if ($request->isMethod('POST')) {
        $form->bind($request);

        if ($form->isValid()) {
            // perform some action, such as saving the task to the database

            return $this->redirect($this->generateUrl('task_success'));
        }
    }

    // ...
}

New in version 2.1: The bind method was made more flexible in Symfony 2.1. It now accepts the raw client data (same as before) or a Symfony Request object. This is preferred over the deprecated bindRequest method.

Now, when submitting the form, the controller binds the submitted data to the form, which translates that data back to the task and dueDate properties of the $task object. This all happens via the bind() method.

Note

As soon as bind() is called, the submitted data is transferred to the underlying object immediately. This happens regardless of whether or not the underlying data is actually valid.

This controller follows a common pattern for handling forms, and has three possible paths:

  1. When initially loading the page in a browser, the request method is GET and the form is simply created and rendered;
  2. When the user submits the form (i.e. the method is POST) with invalid data (validation is covered in the next section), the form is bound and then rendered, this time displaying all validation errors;
  3. When the user submits the form with valid data, the form is bound and you have the opportunity to perform some actions using the $task object (e.g. persisting it to the database) before redirecting the user to some other page (e.g. a "thank you" or "success" page).

Note

Redirecting a user after a successful form submission prevents the user from being able to hit "refresh" and re-post the data.

Form Validation¶

In the previous section, you learned how a form can be submitted with valid or invalid data. In Symfony2, validation is applied to the underlying object (e.g. Task). In other words, the question isn't whether the "form" is valid, but whether or not the $task object is valid after the form has applied the submitted data to it. Calling $form->isValid() is a shortcut that asks the $task object whether or not it has valid data.

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

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    # Acme/TaskBundle/Resources/config/validation.yml
    Acme\TaskBundle\Entity\Task:
        properties:
            task:
                - NotBlank: ~
            dueDate:
                - NotBlank: ~
                - Type: \DateTime
    
  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    // Acme/TaskBundle/Entity/Task.php
    use Symfony\Component\Validator\Constraints as Assert;
    
    class Task
    {
        /**
         * @Assert\NotBlank()
         */
        public $task;
    
        /**
         * @Assert\NotBlank()
         * @Assert\Type("\DateTime")
         */
        protected $dueDate;
    }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    <!-- Acme/TaskBundle/Resources/config/validation.xml -->
    <class name="Acme\TaskBundle\Entity\Task">
        <property name="task">
            <constraint name="NotBlank" />
        </property>
        <property name="dueDate">
            <constraint name="NotBlank" />
            <constraint name="Type">\DateTime</constraint>
        </property>
    </class>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    // Acme/TaskBundle/Entity/Task.php
    use Symfony\Component\Validator\Mapping\ClassMetadata;
    use Symfony\Component\Validator\Constraints\NotBlank;
    use Symfony\Component\Validator\Constraints\Type;
    
    class Task
    {
        // ...
    
        public static function loadValidatorMetadata(ClassMetadata $metadata)
        {
            $metadata->addPropertyConstraint('task', new NotBlank());
    
            $metadata->addPropertyConstraint('dueDate', new NotBlank());
            $metadata->addPropertyConstraint('dueDate', new Type('\DateTime'));
        
    
    
    
    
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.