Creating Forms with Symfony

As a web developer, forms will either be your favourite thing or the bane of your existence (and sometimes both). But the reality of the situation is that in order to get data from users into your application, you’re probably going to be using a lot of forms. Symfony, being the smart framework that it is, understands this and provides us with a comprehensive framework to help us build and work with forms.

Flow of Control

The standard flow of control in any form-based interaction typically involves two steps: the display of the form and the post-back.

The display of the form occurs when the user navigates to the page and can view and edit the form. Once the user submits, the post-back sequence begins. In the post-back sequence, the user’s input is validated, application and/or model state may be updated and then the user is redirected to another location within the application.

So how do we handle this sequence of events in Symfony?

Form display

The diagram below depicts the first stage of the process: the display of the form.

Step 1 in the Form filling process

  • Controller builds a form using the FormBuilder class and passes it on to the view.
  • The template renders out the form elements.

Post-back

After user has filled out the form and hit the submit button, the next stage of the process (post-back) occurs.

Step 2 in the Form filling process

  • The form is POST’ed back to the same controller
  • The controller has form handling code wrapped in a “if ($method == ‘POST’)” block.
    • The controller “binds” the POST’ed values to the form. Because this is a new request, the form that we create in the controller is going to be empty. Binding the form fills it in with the POST’ed values.
    • The controller validates the form.
    • If validation passes, the data in the form is persisted to the database.
  • The user is redirected.

The Form object

As you can see in the diagrams above, Symfony builds an internal representation of your form in the controller. This form object is then passed to the view, which uses it to build the HTML for the form. So what does the form object look like, and how can we use it?

The part of the controller that does the heavy lifting in generating the form can be seen here:

$form = $this->createFormBuilder()
    ->add('title', 'text')
    ->add('body', 'textarea')
    ->getForm();

We use a call on the controller object ($this) to get access to an instance of the FormBuilder class. Using this instance, we add variables that we would like form fields for. The parameters supplied to add define the field that will be created. We can supply 3 parameters:

  • The name of the field.
  • The type of the field (optional). For a list of the available types, check out the official documentation.
  • An array of configuration options (optional).

Finally, we create the form by calling getForm() on the form builder. We can then pass the form on to the view using the return value of the controller:

return array('form' => $form->createView());

The view then uses this variable to render the form. We can see this in the template code below:

We can see that the form elements are being individually rendered using the properties of the FormView object passed to the template from the controller. In this particular example, each field has been broken into three elements:

{{ form_label(form.title) }}
{{ form_errors(form.title) }}
{{ form_widget(form.title) }}

If we don’t want to specify each individually (label, error and input element), we can also use this shortcut:

{{ form_row(form.title) }}

Or, if we just want to let Symfony render the whole form for us without individually placing fields:

{{ form_widget(form) }}

Substituting this into our template, the code becomes:

Persisting Data from our Form

Now we can display a form in our web application, it’s time to look at how we can actually use the data posted back from the user. We do this by “binding” the postback to the form and then using the “getData()” method. See below:

Moving Forms into separate classes

This is well and good for small, simple forms. But what about a form for a sign-up form? Or if we need multiple forms on the same page? Generating the form inside the controller code quickly becomes messy and, as it is closer to view than controller code, bad practice. Symfony solves this problem by allowing us to create Form classes. By doing this, all the information about fields and their properties is stored in a separate class that can then be referenced in the controller.

And how do we go about utilising this? Glad you asked…

Now that we’ve defined this form, we can use it in our controller:

CSRF Protection

One of the best things about the Symfony forms framework is that it protects us from cross-site request forgery attacks by default. It does this by inserting a unique token into each form in at hidden field. The field is then validated on post-back to make sure the request came from a Symfony-generated form.

Conclusion

You should now be able to create, embed, parse and persist forms using the Symfony Forms framework. Congratulations! For more information check out the Symfony official forms documentation. Stay tuned for more tutorials on advanced forms-usage, including validation and custom field-types.