Terrain 7 — Twig & composants
🔍 Renfort : 7.1, 7.2. ⚠️ Toute la syntaxe Twig est dans des blocs de code (les accolades Twig hors code casseraient la page).
1. Afficher une date ⭐
🕹️ Mission : affichez booking.start au format « 09/07/2026 14:30 ».
✅ Solution
{{ booking.start|date('d/m/Y H:i') }}2. Valeur de repli ⭐
🕹️ Mission : affichez une description ou « — » si vide.
✅ Solution
{{ description|default('—') }}3. Boucle avec état vide ⭐⭐
🕹️ Mission : listez les services d’un prestataire, avec « Aucun service » si vide.
✅ Solution
{% for service in provider.services %}
<li>{{ service.name }}</li>
{% else %}
<li>Aucun service.</li>
{% endfor %}4. Générer une URL ⭐⭐
🕹️ Mission : un lien vers booking_show sans URL en dur.
✅ Solution
<a href="{{ path('booking_show', { id: booking.id }) }}">Voir</a>5. Héritage ⭐⭐
🕹️ Mission : une page qui étend base.html.twig et remplit title + body.
✅ Solution
{% extends 'base.html.twig' %}
{% block title %}Réservations — {{ parent() }}{% endblock %}
{% block body %}<h1>Réservations</h1>{% endblock %}6. Danger |raw ⭐⭐⭐
🕹️ Mission : pourquoi {{ comment.body|raw }} sur un commentaire utilisateur est-il dangereux ? Que faire ?
✅ Solution
|raw désactive l’échappement → XSS si l’utilisateur injecte du <script>. Laisser Twig échapper (juste {{ comment.body }}), ou assainir avec HtmlSanitizer avant d’afficher.
7. Messages flash ⭐⭐
🕹️ Mission : affichez tous les messages flash.
✅ Solution
{% for label, messages in app.flashes %}
{% for message in messages %}
<div class="flash flash-{{ label }}">{{ message }}</div>
{% endfor %}
{% endfor %}8. Composant Twig ⭐⭐⭐
🕹️ Mission : un composant StatusBadge (classe + template) affichant un badge coloré.
✅ Solution
#[AsTwigComponent]
final class StatusBadge {
public BookingStatus $status;
public function cssClass(): string { return 'badge badge-' . $this->status->value; }
}{# templates/components/StatusBadge.html.twig #}
<span class="{{ this.cssClass }}">{{ status.label }}</span>
{# usage : <twig:StatusBadge :status="booking.status" /> #}9. Éviter le N+1 en Twig ⭐⭐⭐⭐
🕹️ Mission : une liste appelle service.provider.name par ligne (N+1). Où corriger ?
✅ Solution
Pas en Twig, mais dans le repository : charger la relation en fetch join (->addSelect('p')->join('s.provider', 'p')) avant de passer les données au template.
10. Include isolé ⭐⭐
🕹️ Mission : incluez une ligne de tableau en ne passant qu’une variable, contexte isolé.
✅ Solution
{% include 'partials/_row.html.twig' with { booking: b } only %}Terrain suivant : Symfony UX.