Formulare mit Symfony Forms erstellen
Formulare mit Symfony Forms erstellen
~16 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Symfony Forms ist EINES der mächtigsten Bündel dieses Frameworks: aus EINER PHP-Klasse entstehen automatisch HTML-Formular, serverseitige Verarbeitung UND Validierung (Kapitel 16) – DREI Aufgaben aus einer einzigen Quelle.
Einen Form Type generieren
php bin/console make:form ProjectTypemake:form (aus dem maker-bundle, Kapitel 6) erzeugt ein Grundgerüst unter src/Form/ – wir passen es für unser Projekt an. (Da unsere Entity-Klassen erst in Block 4 entstehen, arbeiten wir vorerst OHNE die data_class-Option und geben stattdessen ein Array zurück.)
<?php
declare(strict_types=1);
namespace App\Form;
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;
class ProjectType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class, [
'label' => 'Projektname',
])
->add('beschreibung', TextareaType::class, [
'label' => 'Beschreibung',
'required' => false,
])
;
}
}Den Form Type im Controller nutzen
use App\Form\ProjectType;
#[Route('/projects/new', name: 'project_new', methods: ['GET', 'POST'])]
public function new(Request $request): Response
{
$form = $this->createForm(ProjectType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$daten = $form->getData();
// $daten['name'] und $daten['beschreibung'] enthalten die eingegebenen Werte
$this->addFlash('success', 'Projekt erfolgreich erstellt!');
return $this->redirectToRoute('project_index');
}
return $this->render('project/new.html.twig', [
'form' => $form,
]);
}handleRequest($request) ist der entscheidende Aufruf: bei einem GET-Request bleibt das Formular UNBEFÜLLT, bei einem POST-Request liest es AUTOMATISCH $request->request (Kapitel 10) aus und befüllt das Formular-Objekt – wir müssen NICHT mehr manuell auf einzelne POST-Felder zugreifen.
isSubmitted() prüft, ob überhaupt Daten gesendet wurden (also POST statt GET), isValid() prüft die Validierung – Kapitel 16 fügt echte Validierungsregeln hinzu, OHNE die auch leere Felder aktuell als "valide" gelten.
Das Formular in Twig rendern
{% extends 'base.html.twig' %}
{% block body %}
<h1>Neues Projekt</h1>
{{ form(form) }}
{% endblock %}{{ form(form) }} rendert das KOMPLETTE Formular – ALLE Felder, Labels, Validierungsfehler UND einen Submit-Button, inklusive <form>-Tag und CSRF-Schutz (Kapitel 18) – mit EINER einzigen Twig-Funktion.
Feingranulares Rendering für individuelles Styling
form(form) ist praktisch für den Einstieg, aber im echten Projekt braucht man meist mehr Kontrolle über das HTML-Markup:
{{ form_start(form) }}
<div class="formular-feld">
{{ form_label(form.name) }}
{{ form_widget(form.name) }}
{{ form_errors(form.name) }}
</div>
<div class="formular-feld">
{{ form_row(form.beschreibung) }}
</div>
<button type="submit">Speichern</button>
{{ form_end(form) }}form_row(...) bündelt Label, Widget und Fehler für EIN Feld (wie beim beschreibung-Feld oben) – der Mittelweg zwischen der Alles-oder-nichts-Funktion form(form) und der vollständig manuellen Kontrolle über form_label/form_widget/form_errors einzeln (wie beim name-Feld).
Tipp: Faustregel: form(form) für schnelle Prototypen und interne Tools, form_row() pro Feld für die meisten Produktions-Formulare, einzelne form_label/form_widget/form_errors-Aufrufe nur für WIRKLICH individuell gestaltete Felder.