Twig-Vererbung und Layouts
Twig-Vererbung und Layouts
~13 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Ohne Vererbung müsste JEDES Template Navigation, Footer und HTML-Grundgerüst wiederholen. Twigs Vererbungssystem löst das elegant – GENAU das Muster, das wir in Kapitel 12 für Flash Messages bereits vorweggenommen haben.
Das Basis-Template: base.html.twig
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>{% block title %}Aufgaben-Manager{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
<nav>
<a href="{{ path('project_index') }}">Projekte</a>
</nav>
{% for label, messages in app.flashes %}
{% for message in messages %}
<div class="alert alert-{{ label }}">{{ message }}</div>
{% endfor %}
{% endfor %}
<main>
{% block body %}{% endblock %}
</main>
{% block javascripts %}{% endblock %}
</body>
</html>{% block name %}...{% endblock %} definiert eine BENANNTE Stelle, die kindliche Templates ÜBERSCHREIBEN können. path('project_index') löst einen Routennamen (Kapitel 7) zur tatsächlichen URL auf – GENAU wie redirectToRoute() im Controller, niemals eine URL hartcodieren.
Ein kindliches Template: extends
{% extends 'base.html.twig' %}
{% block title %}Projekte – {{ parent() }}{% endblock %}
{% block body %}
<h1>Projekte</h1>
<ul>
{% for projekt in projekte %}
<li>{{ projekt.name }}</li>
{% endfor %}
</ul>
{% endblock %}{% extends %} MUSS die erste Zeile des Templates sein. {{ parent() }} innerhalb eines Blocks fügt den INHALT des übergeordneten Blocks ein – hier: Projekte – Aufgaben-Manager statt die Basis-Beschriftung komplett zu ersetzen.
Wiederverwendbare Teil-Templates: include
Für Bausteine, die auf MEHREREN Seiten unabhängig von der Vererbungshierarchie vorkommen (z. B. eine Projekt-Karte), eignet sich {% include %} besser als Vererbung:
<div class="projekt-karte">
<h3>{{ projekt.name }}</h3>
<a href="{{ path('project_show', {id: projekt.id}) }}">Details</a>
</div>{% for projekt in projekte %}
{{ include('project/_karte.html.twig', {projekt: projekt}) }}
{% endfor %}Der führende Unterstrich (_karte.html.twig) ist reine Konvention (kein Symfony-Zwang), signalisiert aber "dieses Template wird nur EINGEBUNDEN, nicht direkt aus einem Controller gerendert".
path('project_show', {id: projekt.id}) zeigt, wie Route-Parameter (Kapitel 9) aus Twig heraus übergeben werden – als zweites Argument, ein Objekt-Literal mit den Platzhalter-Namen als Schlüssel.
Vererbung vs. include: eine Faustregel
| Mechanismus | Einsatzfall |
|---|---|
| extends | Für die GESAMTE Seitenstruktur – EINE Basis, viele Seiten füllen ihre Blöcke. |
| include | Für WIEDERVERWENDBARE Bausteine INNERHALB einer Seite, unabhängig von der Block-Hierarchie – z. B. eine Karte, ein Formular-Fragment. |
CSS und JavaScript einbinden: die asset()-Funktion
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('styles/app.css') }}">
{% endblock %}Tipp: asset('styles/app.css') löst den Pfad relativ zu public/ auf und berücksichtigt automatisch ein konfiguriertes "Asset-Versioning" (Cache-Busting per Query-String) – robuster als einen hartcodierten /styles/app.css-Pfad.