Aller au contenu principal

Le cycle de vie d'une requête Symfony

Prendre du recul sur tout ce que vous avez manipulé jusqu'ici (routes, contrôleurs, vues, base de données) pour comprendre comment Symfony articule tout cela à chaque requête HTTP.


Notions théoriques

Le Front Controller

Depuis le début de ce cours, vous avez créé des routes, des contrôleurs et des vues Twig. Mais comment une simple URL tapée dans le navigateur finit-elle par exécuter la bonne méthode PHP ?

La réponse tient en un principe : le Front Controller (contrôleur frontal). Dans une application Symfony, toutes les requêtes HTTP passent par un unique point d'entrée : le fichier public/index.php.

info

Que vous visitiez /game/1, /player ou n'importe quelle autre URL de votre application, c'est toujours le même fichier public/index.php qui est exécuté en premier. C'est lui qui va ensuite déterminer quoi faire de la requête.

Ce principe évite d'avoir un fichier PHP différent par page (comme en PHP procédural classique), et permet à Symfony de mettre en place un traitement uniforme pour chaque requête : sécurité, journalisation, gestion des erreurs, etc.

Le rôle du Kernel

Le fichier public/index.php délègue immédiatement le travail à un objet central : le Kernel (le noyau de l'application), fourni par le composant HttpKernel.

Le rôle du Kernel est simple à formuler, même s'il cache une mécanique riche :

Le Kernel reçoit un objet Request (la requête HTTP entrante) et retourne un objet Response (la réponse HTTP à renvoyer).

Tout ce que fait Symfony entre les deux, ce sont les étapes que vous avez déjà pratiquées séparément dans les séances précédentes, sans forcément voir comment elles s'enchaînent.

Les grandes étapes du cycle

Voici le déroulement complet d'une requête, du navigateur jusqu'à la réponse affichée :

  1. Requête entrante : le navigateur envoie une requête HTTP (ex. GET /game/1) qui arrive sur public/index.php.
  2. Le routeur analyse l'URL et détermine quelle route correspond, donc quel contrôleur (et quelle méthode) doit être appelé (voir la séance sur le routage).
  3. Exécution du contrôleur : Symfony appelle la méthode du contrôleur correspondante, en lui passant les paramètres nécessaires (comme l'id extrait de l'URL).
  4. Accès aux données (optionnel) : le contrôleur peut interroger la base de données via Doctrine pour récupérer les informations nécessaires (voir la séance sur Doctrine).
  5. Génération de la réponse : le contrôleur prépare les données et les transmet à un template Twig via render(), qui génère le HTML final (voir la séance sur Twig). Le contrôleur peut aussi construire une réponse directement, sans passer par Twig.
  6. Réponse renvoyée : le HTML généré est encapsulé dans un objet Response, renvoyé au Kernel, puis envoyé au navigateur.
Navigateur
│ requête HTTP (GET /game/1)

public/index.php (Front Controller)


Kernel (HttpKernel)
│ reçoit un objet Request

Routeur → détermine : GameController::show()


Contrôleur (GameController::show)
│ interroge éventuellement la base de données (Doctrine)
│ transmet les données à un template Twig (render)

Réponse HTML générée
│ encapsulée dans un objet Response

Kernel → Navigateur

Les objets Request et Response

Ce cycle repose sur deux objets fournis par Symfony, dans le composant HttpFoundation :

  • Request représente la requête HTTP entrante : elle contient l'URL, les paramètres GET ($request->query), les données POST ($request->request), les en-têtes, etc.
  • Response représente la réponse HTTP sortante : elle contient le contenu (souvent du HTML), le code de statut (ex. 200, 404) et des en-têtes.

Un contrôleur peut recevoir un objet Request en paramètre, et doit toujours retourner un objet Response — que ce Response soit construit à la main ou généré par $this->render() (qui retourne en réalité un Response contenant le HTML généré par Twig).

public function show(int $id, Request $request): Response
{
$format = $request->query->get('format', 'html');

// ... le contrôleur peut utiliser Doctrine, puis Twig ...

return $this->render('game/show.html.twig', ['id' => $id]);
}
astuce

La méthode render() que vous utilisez depuis la séance sur les vues ne fait pas exception à la règle : elle retourne bien un objet Response, dont le contenu a simplement été généré par le moteur Twig.

Exemple de mise en application

Reprenons le GameController du projet my_game. Ajoutons une méthode search qui lit un paramètre GET directement depuis l'objet Request, pour illustrer le cycle complet.

namespace App\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Attribute\Route;

class GameController extends AbstractController
{
#[Route('/game/search', name: 'game_search')]
public function search(Request $request): Response
{
// Étape 1 : le routeur a déjà identifié cette méthode grâce à l'URL /game/search
// Étape 2 : on lit un paramètre transmis dans l'URL, ex. /game/search?q=echecs
$query = $request->query->get('q', '');

// Étape 3 : on pourrait interroger Doctrine ici pour chercher des jeux
// Étape 4 : on transmet le résultat à Twig, qui génère le HTML
return $this->render('game/search.html.twig', [
'query' => $query,
]);
}
}

Quand un utilisateur visite http://localhost:8000/game/search?q=echecs, voici ce qui se passe : public/index.php reçoit la requête, le Kernel la transforme en objet Request, le routeur identifie la méthode search() de GameController, cette méthode lit le paramètre q dans la Request, puis retourne un Response généré par Twig. Ce Response est renvoyé au navigateur.

Test de mémorisation/compréhension


Quel est le seul fichier PHP par lequel passent toutes les requêtes HTTP d'une application Symfony ?


Comment appelle-t-on ce principe où toutes les requêtes passent par un point d'entrée unique ?


Quel composant Symfony reçoit une Request et retourne une Response ?


Dans le cycle d'une requête, que fait le routeur ?


Que retourne toujours une méthode de contrôleur dans Symfony ?


La méthode render() d'un contrôleur retourne-t-elle un objet Response ?


Comment un contrôleur accède-t-il aux paramètres GET transmis dans l'URL ?


À quelle étape du cycle un contrôleur peut-il interroger la base de données avec Doctrine ?


TP pour réfléchir et résoudre des problèmes

Votre défi pour aujourd'hui consiste à ajouter au PlayerController une méthode qui utilise explicitement l'objet Request, pour bien identifier chaque étape du cycle vu en théorie.

Étape 1 — Importer la classe Request

Le contrôleur doit pouvoir recevoir un objet Request en paramètre de méthode. Ajoutez l'import correspondant en haut du fichier PlayerController.php.

Étape 2 — Ajouter un paramètre Request à la méthode index()

Modifiez la signature de la méthode index() pour qu'elle reçoive l'objet Request en plus des paramètres déjà présents.


Bonne pratique - Typer explicitement le paramètre Request

Typer le paramètre Request $request permet à Symfony de reconnaître automatiquement qu'il doit y injecter l'objet représentant la requête HTTP courante. C'est ce qu'on appelle l'injection de dépendances : vous n'avez jamais besoin de créer vous-même cet objet, Symfony s'en charge à chaque requête.

Étape 3 — Lire le paramètre GET "search" depuis la Request

Complétez la ligne qui lit le paramètre GET nommé search dans l'URL (ex. /player?search=alice), avec une valeur par défaut vide si le paramètre est absent.


Bonne pratique - Toujours prévoir une valeur par défaut

Utiliser $request->query->get('search', '') évite une erreur si le paramètre search n'est pas présent dans l'URL. Sans valeur par défaut, la méthode retournerait null, ce qui peut provoquer des erreurs plus loin dans le code si celui-ci suppose une chaîne de caractères.

📌 Une solution