A better form

By the end of this lesson, you’ll have refactored the form we created in the last tutorial for the better. Along the way, we’ll be:

  • Adding Validation to the form
  • Making the form blend in with the website by applying a theme

Follow along using the code available from this GIT repository.
Start - the_form_builder
End - a_better_form

Adding Validation

Testing for correctness of data is a very important task to any application. In the Symfony Standard Edition, a validator component is preconfigured to use by placing annotations within the data object class.

This provide greats benefit as it means, we can define the restrictions in one place which can be used on both the frontend and backend, beyond just form use. The validator is integrated with the form builder service and will first try to use native / javascript validation on the web page and on the server (which you should be) make error messages available to the form component whilst also adding in the messages to the next form render

To get started, we include the component in our entity file and write a series of annotations similar to Doctrine.

  1. <?php
  2. // src/AppBundle/Entity/Comment.php
  3. namespace AppBundle\Entity;
  5. use Doctrine\ORM\Mapping as ORM;
  7. /* Include the symfony validator service */
  8. use Symfony\Component\Validator\Constraints as Assert;
  9. /**
  10.  * @ORM\Entity()
  11.  * @ORM\Table(name="comment")
  12.  */
  13. class Comment
  14. {
  15.     /**
  16.      * @ORM\Column(type="integer")
  17.      * @ORM\Id
  18.      * @ORM\GeneratedValue(strategy="AUTO")
  19.      */
  20.     private $id;
  21.     /**
  22.      * @ORM\ManyToOne(targetEntity="Post", inversedBy="comments")
  23.      */
  24.     private $post;
  25.     /**
  26.      * @ORM\Column(type="string", length=100)
  27.      * @Assert\NotBlank()
  28.      * @Assert\Email(
  29.      *  checkMX = true
  30.      * )
  31.      */
  32.     private $email;
  33.     /**
  34.      * @ORM\Column(name="body", type="text")
  35.      * @Assert\NotBlank()
  36.      * @Assert\Length(
  37.      *      min = 5,
  38.      *      max = 2000,
  39.      *      minMessage = "Your message must be longer than {{ limit }} characters",
  40.      *      maxMessage = "Your message cannot be longer than {{ limit }} characters"
  41.      * )
  42.      */
  43.     private $body;
  44.     /**
  45.      * @ORM\Column(type="datetime")
  46.      */
  47.     private $createdAt;
  48. }

There are many available assertions and they often have a series of options available allowing for various customisations, including messages displayed. For more information on the built in validation types, please see the officical documentation page.

Form themes

If you study the HTML created by the form generator, you may notice that it is syntactically clean but, from a presentation point of view looking very basic.

Form rendering is based on a series of twig templates that are simple to override. More conveniently, Symfony supports five semantic builders of form construction; more advanced form customisation options can be found on the official documentation.

  • Basic div layout, the default
  • Table based layout
  • Bootstrap 3 layout
  • Horizontal style bootstrap 3 layout
  • Foundation 5 layout

We are using a Bootstrap 3 based theme so, it makes sense to use that theme for the forms also. To do this globally, all we have to do is import the form theme from the twig configuration.

  1. # app/config/config.yml
  2. twig:
  3.    form_themes:
  4.       - "bootstrap_3_layout.html.twig"


This concludes Core Symfony training and for everything covered within the series, you should now have a good understanding of the the basic building blocks that make up Symfony web applications.

Moving forward from this point will see you diving in to more advanced topics that focus on making your projects more maintainable, then production ready and finally some of the more advanced concepts. I hope you have enjoyed it!


  • Learn more about Symfony validation, it can be used to protect both frontend forms and backend data objects

Communication, our greatest tool

Whether you want to connect, have a problem I can help with or simply want to drop a line, I welcome your words!