Forms
Symfony's Form component gives you a structured way to build, render, and
process HTML forms that are tied directly to a PHP object — very often a Doctrine
Entity, like the Article class from the
Doctrine ORM page. Instead of hand-writing form fields and
manually pulling values out of $_POST, you describe the form's fields once in a
reusable class, and Symfony takes care of rendering, populating, and reading it back.
Defining a FormType
A form's fields are defined in a dedicated class that extends AbstractType. Its
buildForm() method adds one field at a time, each tied to a property on the object
the form represents:
<?php
namespace App\Form;
use App\Entity\Article;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ArticleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('title', TextType::class)
->add('content', TextareaType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Article::class,
]);
}
}
configureOptions() sets data_class to Article::class,
telling Symfony which entity this form is bound to — that's what lets the form read the entity's
current values when displaying it, and write submitted values back onto a new or existing
Article object.
Using the Form in a Controller
Inside a controller, you build the form for a given Article, let Symfony pull the
submitted data out of the request, and check whether it was actually submitted and valid:
<?php
$article = new Article();
$form = $this->createForm(ArticleType::class, $article);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($article);
$entityManager->flush();
return $this->redirectToRoute('article_show', ['id' => $article->getId()]);
}
return $this->render('article/new.html.twig', ['form' => $form->createView()]);
createForm() builds the form bound to a fresh (empty) $article.
handleRequest() checks whether the request contains submitted form data and, if so,
maps it onto $article's properties. isSubmitted() and
isValid() together confirm the request was a real submission and that it passed all
validation checks before you save anything — the same persist() /
flush() pair from the Doctrine ORM page handles the actual save.
Rendering the Form in Twig
In the simple case, rendering the whole form — every field, label, and error message — takes a single Twig function call:
{{ form(form) }}
That's enough to get a working, submittable form on the page. Symfony also lets you render a
form field by field for full control over the surrounding markup, but {{ form(form) }}
is the fastest way to get something working.
isValid() only returns true once the submitted data satisfies the entity's validation constraints — annotations or attributes that declare rules like "required" or "maximum length". That's exactly what the next page covers.isValid() checks against.