Building and Processing Forms in Symfony 2

Share this article

In this tutorial we will look at two examples of using forms in Symfony 2. In the the first, we will place form elements straight in the View file and then handle the form processing manually in the controller. In the second, we’ll use the Symfony form system to declare forms in an object oriented way and have Symfony process and persist the values.

We will be working on a simple installation of the Symfony framework. As you may know, it comes with a default bundle called AcmeDemoBundle and we will use that to illustrate working with forms. All the final code can be found in this repository I set up for this tutorial. Feel free to follow along or take a peek at the final code.

Non-entity forms

The first example we will look at is how to process forms declared as regular HTML elements inside of a Symfony View file. There are 3 steps we will take to illustrate this:

  1. We will create a View file that contains our form HTML
  2. We will create a new Controller method in the WelcomeController class called form1Action that will handle our business logic (rendering the View, processing the form, etc).
  3. We will then create a simple route entry to map a URL path to this method so that we can see the form in the browser and be able to submit it.

Let’s first create the View file that will show our form and the submitted value on top. In a file called form1.html.twig located in the src/Acme/DemoBundle/Resources/views/Welcome folder (the corresponding folder for the Welcome controller class Symfony comes with by default) I have the following:

{% extends "AcmeDemoBundle::layout.html.twig" %}

{% block content %}

<h1>Form values</h1>

{% if name is defined %}
<p>Name: {{ name }} </p>
{% endif %}

<div>
    <form name="input" action="" method="post">

        Name:
        <input type="text" name="name"/>

        <input type="submit" name="submit" value="Submit">

    </form>
</div>

{% endblock %}

Above, I am extending the default layout in the DemoBundle just so I don’t see a very white page. And the rest is pretty basic as well: declaring a simple HTML form that posts to itself and showing the value of the only text field above the form (which will be passed from the Controller after processing in a variable called name).

Next, let’s declare the Controller method in charge of displaying this View and processing the form inside it. In the WelcomeController class file, I do two things:

  1. I make use of the Symfony Request class that will help us easily access the submitted values:

    use Symfony\Component\HttpFoundation\Request;
    

    This goes above the class declaration.

  2. I have the following method:

public function form1Action()
    {

        $post = Request::createFromGlobals();

        if ($post->request->has('submit')) {
            $name = $post->request->get('name');
        } else {
            $name = 'Not submitted yet';
        }

        return $this->render('AcmeDemoBundle:Welcome:form1.html.twig', array('name' => $name));

    }

In this method, I use the createFormGlobals() method found in the $request object to gather the PHP superglobals (including the $_POST values). Then I check if the submitted values include submit (which is basically our submit button), and if they do, I retrieve the value of the name element and pass it along to the View we just created. Simple.

Finally, let’s define a routing rule to match a URL path to this Controller method. In the routing.yml file located in the src/Acme/DemoBundle/Resources/config folder I added the following rule:

_form1:
		pattern:  form1
		defaults: { _controller: AcmeDemoBundle:Welcome:form1 }

This will map the form1/ path to the new Controller method.

And that’s it, you can test it out. One thing to keep in mind is that this is not really a recommended way to handle forms when dealing with entities or any kind of content for your site. Symfony comes with some nice classes that will make doing that much easier. We will see how some of these work next.

Symfony Entities and Forms

Going forward, we will be looking at how to display and process a form for a Symfony entity called Article (that I’ve defined in the meantime and you can find in the repository). For a refresher on how entities work, check out our second part of the series on the Symfony framework.

I will illustrate a very simple example of how to display a form that will then save a new Article entity to the database, using the Symfony way. We’ll be working mainly with 5 files: the controller class file where we add two new methods for showing the form and for showing a simple confirmation page; the routing.yml file since we need to map the URLs; two View files to display the form and confirmation; and an ArticleType.php file in which we build the form.

We’ll start with the latter. Although you can build the form also directly inside the controller, using a separate type file makes it much more reusable so we’ll do that instead. Inside our src/Acme/DemoBundle/Form folder, I have a file called ArticleType, with the following contents:

<?php

namespace Acme\DemoBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class ArticleType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('title', 'text', array('label' => 'Title'))
            ->add('body', 'textarea')
            ->add('save', 'submit');
    }

    public function getName()
    {
        return 'article';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\DemoBundle\Entity\Article',
        ));
    }

}

Above, I extend the default Symfony form builder class to define my own form. The buildForm() method is responsible for actually building the form. Inside, I am adding to the $builder object’s various form elements that will suit our Article entity and that are named after the entity properties. For more information on the available form elements, you can consult the documentation.

The getName() method just returns the name of the form type itself whereas with the setDefaultOptions() method we specify the entity class we use this form for (as the value for the data_class key). And that’s it, we have our form definition, let’s build it inside our controller and display it on the page.

Back in the WelcomeController class, I have included at the top two more class references (for the Article entity and the form type we just created):

use Acme\DemoBundle\Entity\Article;
use Acme\DemoBundle\Form\ArticleType;

Next, I added the following two methods:

public function form2Action(Request $request)
    {

        $article = new Article();

        $form = $this->createForm(new ArticleType(), $article);

        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($article);
            $em->flush();

            $session = $this->getRequest()->getSession();
            $session->getFlashBag()->add('message', 'Article saved!');

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

        return $this->render('AcmeDemoBundle:Welcome:form2.html.twig', array('form' => $form->createView()));

    }

    public function form2savedAction()
    {

        return $this->render('AcmeDemoBundle:Welcome:form2saved.html.twig');

    }

The form2Action() method is responsible for showing and processing the form to create new Article enities. First, it instantiates a new empty object of that class. Then, it creates a new form for it using the form type we defined earlier. Next, it processes the form if one has been submitted, but if not, it renders the form2.html.twig View file and passes the rendered HTML form for it to display. Let’s create that file now and then we’ll come back and see what happens with the form processing.

Right next to where we created form1.html.twig, I have form2.html.twig with the following contents:

{% extends "AcmeDemoBundle::layout.html.twig" %}

{% block content %}

{{ form(form) }}

{% endblock %}

Couldn’t be simpler. It just renders the form that was passed to it. Let’s quickly also add the following route to our routing.yml file so we can see this in the browser:

_form2:
	    pattern:  form2
	    defaults: { _controller: AcmeDemoBundle:Welcome:form2 }

Now we can point our browser to the form2/ path and see a simple (but rather ugly) form. Now for the processing.

As we saw earlier, the form2Action() method has a parameter passed to it: the $request object. So when we submit this form, it uses the handleRequest() method of the $form object we built to see if the form has been submitted (if its values exist in the $request superglobals). If it has been submitted, it runs a standard validation on it and saves the new object to the database (the one we originally instantiated has been automagically populated with the form values). Lastly, it saves a one request only flash message and redirects to another page, the path being built based on another route:

_form2saved:
	    pattern:  form2saved
	    defaults: { _controller: AcmeDemoBundle:Welcome:form2saved }

The route triggers the form2savedAction() method we declared in the WelcomeController class and which renders the form2saved.html.twig View. And in this View, all I do for now is look if there is a message in the session flashBag and print it out:

{% extends "AcmeDemoBundle::layout.html.twig" %}
	
	{% block content %}
	
		{% for flashMessage in app.session.flashbag.get('message') %}
		    <p>{{ flashMessage }}</p>
		{% endfor %}
	
	{% endblock %}

And that’s it. Now you can refresh the form and submit it. You should be redirected to a simple page that shows the confirmation message. And if you check the database, a new Article record should have been saved.

Conclusion

In this article we’ve looked at very simple usages of the Symfony 2 form system. First, we saw how to process a form submission using regular HTML form elements printed in the View. Then, we saw how to leverage the power of the Symfony form system to define forms in code in order to process and persist the values as an entity.

Each of these techniques have their use case. If you are performing CRUD operations on data or content, it’s best to use the second option. Symfony is very powerful when it comes to abstracting your data and this makes the form building very easy. If, however, you need some ‘on the fly’ processing of a form that does not save anything, you can build the form right into the View and then catch the submitted values in the controller.

Questions? Comments? Would you like to know more? Let us know!

Frequently Asked Questions about Building and Processing Forms in Symfony 2

How do I create a simple form in Symfony 2?

Creating a simple form in Symfony 2 involves a few steps. First, you need to create a form class. This class will define the fields that your form will have. You can create this class in the ‘Form’ directory of your bundle. The form class should extend the ‘AbstractType’ class provided by Symfony. After defining your form class, you can create an instance of this class in your controller and pass it to your view. In your view, you can use the ‘form’ function provided by Symfony to render your form.

How can I handle form submissions in Symfony 2?

Handling form submissions in Symfony 2 is done in your controller. After creating your form, you can use the ‘handleRequest’ method provided by Symfony to handle the form submission. This method will automatically populate your form with the submitted data and validate it. If the form is valid, you can then process the data as needed.

How do I validate form data in Symfony 2?

Symfony 2 provides a powerful validation system that you can use to validate your form data. You can define validation rules in your form class using the ‘Assert’ annotations provided by Symfony. These rules will be automatically checked when you handle your form submission. If any of the rules are not met, Symfony will automatically add an error message to your form.

How can I customize the rendering of my form in Symfony 2?

Symfony 2 provides several ways to customize the rendering of your form. You can customize the HTML of your form fields by overriding the form theme. You can also customize the error messages of your form by defining custom validation messages in your form class.

How do I add a CSRF token to my form in Symfony 2?

Symfony 2 automatically adds a CSRF token to your form when you create it. This token is used to protect your form against CSRF attacks. You can access this token in your view using the ‘form_rest’ function provided by Symfony.

How do I handle file uploads in Symfony 2 forms?

Handling file uploads in Symfony 2 forms involves a few steps. First, you need to add a file field to your form class. This field should be of type ‘file’. After adding the file field, you can handle the file upload in your controller. Symfony will automatically move the uploaded file to a temporary location. You can then move this file to a permanent location as needed.

How do I create a form with multiple steps in Symfony 2?

Creating a form with multiple steps in Symfony 2 involves creating multiple form classes. Each form class will represent a step in your form. You can then handle each step in your controller and store the data of each step in the session. After all steps are completed, you can process the data as needed.

How do I create a form with dynamic fields in Symfony 2?

Creating a form with dynamic fields in Symfony 2 involves using the ‘FormEvents’ provided by Symfony. You can listen to these events in your form class and add or remove fields as needed based on the data of your form.

How do I create a form with a collection of fields in Symfony 2?

Creating a form with a collection of fields in Symfony 2 involves using the ‘collection’ field type provided by Symfony. This field type allows you to handle a collection of data. You can define the fields of each item in the collection in a separate form class.

How do I create a form with a date picker in Symfony 2?

Creating a form with a date picker in Symfony 2 involves using the ‘date’ field type provided by Symfony. This field type will render a date picker in your form. You can customize the format of the date picker by setting the ‘format’ option of your field.

Daniel SiposDaniel Sipos
View Author

Daniel Sipos is a Drupal developer who lives in Brussels, Belgium. He works professionally with Drupal but likes to use other PHP frameworks and technologies as well. He runs webomelette.com, a Drupal blog where he writes articles and tutorials about Drupal development, theming and site building.

FormsframeworkOOPHPPHPsymfonysymfony2
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week