Controller schreiben
Controller schreiben
~14 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Ein Controller ist im Kern eine EINFACHE PHP-Methode: nimmt einen Request entgegen (implizit oder explizit) und gibt eine Response zurück. AbstractController stellt dabei nützliche Hilfsmethoden bereit, die wir jetzt kennenlernen.
AbstractController: nützliche Hilfsmethoden
Symfony-Controller erben üblicherweise von AbstractController – NICHT verpflichtend (jede aufrufbare Funktion funktioniert als Controller), aber es erspart wiederkehrenden Code:
$this->render(...)– ein Twig-Template rendern (Kapitel 13).$this->redirectToRoute(...)– zu einer anderen Route weiterleiten (Kapitel 11).$this->json(...)– eine JSON-Response erzeugen (Kapitel 11).$this->getUser()– den eingeloggten Nutzer abrufen (Block 5).$this->addFlash(...)– eine Flash-Nachricht setzen (Kapitel 12).
Vorerst: mit hartcodierten Beispieldaten arbeiten
Doctrine folgt erst in Block 4 – bis dahin arbeiten wir bewusst mit einem simplen, hartcodierten Array, um uns auf Routing/Controller/Twig konzentrieren zu können, ohne gleichzeitig eine Datenbank zu benötigen:
<?php
declare(strict_types=1);
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class ProjectController extends AbstractController
{
private const array BEISPIEL_PROJEKTE = [
['id' => 1, 'name' => 'Website-Relaunch'],
['id' => 2, 'name' => 'Mobile App'],
['id' => 3, 'name' => 'Interne Tools'],
];
#[Route('/projects', name: 'project_index', methods: ['GET'])]
public function index(): Response
{
$ausgabe = 'Projekte:';
foreach (self::BEISPIEL_PROJEKTE as $projekt) {
$ausgabe .= sprintf("\n- %s", $projekt['name']);
}
return new Response($ausgabe, Response::HTTP_OK, [
'Content-Type' => 'text/plain',
]);
}
}Response::HTTP_OK ist eine benannte Konstante statt der "magischen Zahl" 200 – Symfonys Response-Klasse definiert Konstanten für ALLE gängigen HTTP-Status-Codes, was Lesbarkeit deutlich verbessert.
Abhängigkeiten per Constructor Property Promotion
Braucht ein Controller einen Service (Block 6 behandelt das systematisch), wird dieser per Autowiring automatisch in den Constructor injiziert – wir müssen NICHTS manuell registrieren:
// ... use-Statements wie oben ...
use Psr\Log\LoggerInterface;
class ProjectController extends AbstractController
{
public function __construct(
private readonly LoggerInterface $logger,
) {
}
#[Route('/projects', name: 'project_index', methods: ['GET'])]
public function index(): Response
{
$this->logger->info('Projektliste aufgerufen');
return new Response('Projekte werden geladen...');
}
}LoggerInterface ist bereits ab der Standard-Installation als Service verfügbar (Monolog). Kapitel 32-34 erklären das Autowiring-Prinzip dahinter im Detail – für jetzt reicht: JEDE Typ-Deklaration im Constructor, für die Symfony eine passende Service-Definition kennt, wird AUTOMATISCH aufgelöst.
Mehrere Actions pro Controller
Ein Controller darf (und sollte typischerweise) MEHRERE zusammengehörige Routen bündeln – für unser Projekt: eine Klasse pro Domänen-Konzept, mehrere Methoden ("Actions") pro Klasse:
class ProjectController extends AbstractController
{
#[Route('/projects', name: 'project_index', methods: ['GET'])]
public function index(): Response { /* ... */ }
#[Route('/projects/new', name: 'project_new', methods: ['GET', 'POST'])]
public function new(): Response { /* ... */ }
#[Route('/projects/{id}', name: 'project_show', methods: ['GET'])]
public function show(int $id): Response { /* ... */ }
}Tipp: #[Route('/projects', name: 'project_')] lässt sich zusätzlich auf KLASSEN-Ebene setzen, um allen Actions einen gemeinsamen Pfad-/Namens-Präfix zu geben – praktisch, sobald ein Controller wächst. Wir führen das ein, sobald ProjectController mehrere Routen hat.