sajad torkamani

In a nutshell

When used in Symfony applications, the symfony/forms package makes it easier to work with forms in web applications. More specifically it can:

  • Convert submitted form data into PHP objects (usually Doctrine entities) and vice-versa.
  • Validate submitted data using validator constraints that are usually defined on Doctrine entities.
  • Generate the HTML mark up using information defined in the Form Type class (see below).
  • Display error messages when submission is invalid.
  • Generate a hidden _token field to protect against CSRF attacks.

The forms workflow

When working with forms in Symfony, you usually take the following approach:

  1. Build the form in a controller or in a dedicated form class.
  2. Render the form in a template.
  3. Process the form in a controller to validate the submitted data, transform it into PHP data, and do something with it (e.g., persist it to a database).

Build a Form Type

symfony console make:form CommentFormType Comment

This will generate src/Form/CommentFormType.php that looks like this:

<?php

namespace App\Form;

use App\Entity\Comment;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CommentFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('author')
            ->add('text')
            ->add('email')
            ->add('createdAt')
            ->add('photoFilename')
            ->add('conference')
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Comment::class,
        ]);
    }
}

A form type is a class that describes form fields bound to an entity. Symfony converts between the submitted data and the entity class properties. It uses metadata from the corresponding entity (e.g., Doctrine metadata) to guess the configuration for each field. For example, it’ll render a text property as a textarea.

Display a form

1. Create the form in a controller action and pass it to the template

<?php

namespace App\Controller;

use App\Entity\Comment;
use App\Entity\Conference;
use App\Form\CommentFormType;
use App\Repository\CommentRepository;
use App\Repository\ConferenceRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ConferenceController extends AbstractController
{
    #[Route("/conference/{slug}", name: 'conference')]
    public function show(Request $request, Conference $conference): Response
    {
        $comment = new Comment();
        $form = $this->createForm(CommentFormType::class, $comment);

        return $this->render('conference/show.html.twig', [
            'conference' => $conference,
            'comment_form' => $form->createView()
        ]);
    }
}

2. Render form in twig

<h2>Add your own feedback</h2>

{{ form(comment_form) }}

This should render something like:

Symfony forms.

Customise a form

You can customize the buildForm method to add, remove, or modify fields:

<?php

namespace App\Form;

use App\Entity\Comment;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Image;

class CommentFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('author', null, ['label' => 'You name'])
            ->add('text')
            ->add('email')
            ->add('createdAt')
            ->add('photo', FileType::class, [
                'required' => false,
                'mapped' => false,
                'constraints' => [
                    new Image(['maxSize' => '1024k'])
                ]
            ])
            ->add('conference')
            ->add('submit', SubmitType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Comment::class,
        ]);
    }
}

Validate form submission

1. Add validation constraints

Since most forms will be bound to a Doctrine entity, you’ll typically add validation constraints to your entities. For example:

<?php

namespace App\Entity;

use App\Repository\CommentRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity(repositoryClass: CommentRepository::class)]
class Comment
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;

    #[ORM\Column(type: 'string', length: 255)]
    #[Assert\NotBlank] // validation constraint
    private $author;

    #[ORM\Column(type: 'text')]
    #[Assert\NotBlank] // validation constraint
    private $text;

    #[ORM\Column(type: 'string', length: 255)]
    #[Assert\NotBlank] // validation constraint
    #[Assert\Email] // validation constraint
    private $email;

    // code omitted for brevity
}

4. Check if form is valid in controller

<?php

namespace App\Controller;

// Imports

class ConferenceController extends AbstractController
{
    // code omitted for brevity

    #[Route("/conference/{slug}", name: 'conference')]
    public function show(Request $request, Conference $conference): Response
    {
        $comment = new Comment();
        $form = $this->createForm(CommentFormType::class, $comment);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $comment->setConference($conference);

            $this->entityManager->persist($comment);
            $this->entityManager->flush();

            return $this->redirectToRoute('conference', ['slug' => $conference->getSlug()]);
        }

        // render some template...
    }
}

Now, when the form is submitted with invalid data, the Twig form() method will show any validation errors:

Validation errors in Symfony forms

Debug forms using the Symfony Profiler

Click on the Form panel:

Debug Symfony Forms using the Symfony Profiler

You can view the validator calls:

Validator calls in Symfony profiler

Or view the submitted data and any errors.

Forms in Symfony Profiler

Sources

Tagged: Symfony