Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Custom Form Types in Symfony

Custom Form Types in Symfony

~14 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

Über einfache Text-Felder hinaus bietet Symfony vorgefertigte Feldtypen für wiederkehrende Muster – wir modellieren jetzt das Aufgaben-Formular mit Status-Auswahl und Fälligkeitsdatum.

ChoiceType für feste Auswahllisten

src/Form/Data/TaskData.php
<?php

declare(strict_types=1);

namespace App\Form\Data;

use Symfony\Component\Validator\Constraints as Assert;

class TaskData
{
    #[Assert\NotBlank(message: 'Bitte geben Sie einen Titel ein.')]
    public string $titel = '';

    #[Assert\Choice(choices: ['offen', 'in_arbeit', 'erledigt'])]
    public string $status = 'offen';

    #[Assert\GreaterThanOrEqual('today', message: 'Das Fälligkeitsdatum darf nicht in der Vergangenheit liegen.')]
    public ?\DateTimeImmutable $faelligAm = null;
}
src/Form/TaskType.php
<?php

declare(strict_types=1);

namespace App\Form;

use App\Form\Data\TaskData;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('titel', TextType::class, ['label' => 'Titel'])
            ->add('status', ChoiceType::class, [
                'label' => 'Status',
                'choices' => [
                    'Offen' => 'offen',
                    'In Arbeit' => 'in_arbeit',
                    'Erledigt' => 'erledigt',
                ],
            ])
            ->add('faelligAm', DateType::class, [
                'label' => 'Fällig am',
                'widget' => 'single_text',
                'required' => false,
            ])
        ;
    }

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

Bei ChoiceType ist die Array-Syntax ['Anzeigetext' => 'gespeicherter_wert'] WICHTIG: der SCHLÜSSEL erscheint im HTML als sichtbarer Text, der WERT wird tatsächlich gespeichert – leicht zu verwechseln beim ersten Mal.

'widget' => 'single_text' rendert das Datumsfeld als EIN einzelnes <input type="date"> – ohne diese Option würde Symfony standardmäßig DREI separate Dropdown-Felder für Tag/Monat/Jahr erzeugen, was für moderne Browser-Datepicker unnötig ist.

Einen eigenen, wiederverwendbaren Form Type bauen

Braucht MEHRERE Formulare dieselbe Feldkombination (z. B. "wähle einen Nutzer aus einer Dropdown-Liste" für sowohl Projekt-Mitglieder als auch Task-Zuweisung), lohnt sich ein EIGENER, wiederverwendbarer Form Type:

src/Form/UserChoiceType.php
<?php

declare(strict_types=1);

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;

class UserChoiceType extends AbstractType
{
    public function getParent(): string
    {
        return ChoiceType::class;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'choices' => [
                // In Block 4 ersetzt durch eine echte Datenbank-Abfrage aller Nutzer
                'Anna Schmidt' => 1,
                'Ben Meier' => 2,
            ],
        ]);
    }
}

getParent() gibt an, dass UserChoiceType auf ChoiceType AUFBAUT – dadurch "erbt" er dessen komplettes Verhalten und MUSS nur die projektspezifischen Standardwerte definieren. Verwendung wie jeder andere Form Type: ->add('zugewiesenAn', UserChoiceType::class).

Tipp: In Block 4 (Kapitel 21) ersetzen wir die hartcodierte choices-Liste durch EntityType – einen speziellen ChoiceType, der die Optionen DIREKT aus der Datenbank lädt. Das Prinzip (eigener, wiederverwendbarer Form Type) bleibt identisch.