Forms, validation, CSRF
Symfony Forms look heavy the first hour - then you notice CSRF, rendering, and validation constraints live in one place. You already know the pieces from the PHP tutorial.
Form type class
php
<?php
namespace App\Form;
use App\Entity\Post;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class PostType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('title', TextType::class)
->add('body', TextareaType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Post::class,
]);
}
}Controller handle
php
<?php
#[Route('/posts/new', name: 'app_posts_new')]
public function new(Request $request, EntityManagerInterface $em): Response
{
$post = new Post();
$form = $this->createForm(PostType::class, $post);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($post);
$em->flush();
return $this->redirectToRoute('app_posts_index');
}
return $this->render('posts/new.html.twig', [
'form' => $form,
]);
}Comments for the code above:
handleRequestbinds POST data onto the form / entity- CSRF is enabled by default on forms - Twig
form_startoutputs the token isValid()runs constraints (on the form and/or the entity)
Validation constraints
On the entity (common):
php
<?php
use Symfony\Component\Validator\Constraints as Assert;
class Post
{
#[Assert\NotBlank]
#[Assert\Length(max: 255)]
private ?string $title = null;
}Or on the form field via constraints option. Same Validator component either way - think Zod / class-validator energy.
Twig
twig
{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.body) }}
<button class="btn">Save</button>
{{ form_end(form) }}form_row = label + widget + errors. Customize later with themes; defaults are fine for learning.
Manual CSRF (APIs / custom forms)
For non-Form POSTs you can inject CsrfTokenManagerInterface - same idea as your hand-rolled token in the PHP tutorial. Prefer the Form component when it's an HTML form.
Next: events and subscribers - Symfony's middleware cousin.
Best,
-- ł.