Cet article est une synthèse de la documentation officielle : Controller.
Généralités
Qu'est-ce qu'un contrôleur ?
Son rôle est de transformer la Request de l'utilisateur en une Response à lui renvoyer.
Concrètement, c'est juste un callable.
On a l'habitude d'appeler contrôleur la classe contenant une action associée à une route,
mais en réalité c'est l'action en elle-même qui est un contrôleur.
Pour éviter cette incohérence, on peut n'avoir qu'une action par fichier contrôleur, nommée __invoke().
Comment Symfony sait-il ce qui est un contrôleur ?
C'est le fichier services.yaml qui l'indique :
services:
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller/'
tags: ['controller.service_arguments']
Comme on le voit dans ce fichier, pas de contrainte sur le nommage de la classe ou de ses actions.
Tous les services dans src/Controller/ auront le tag controller.service_arguments.
Qu'elles sont les particularités des contrôleurs, apportées via le tag controller.service_arguments ?
Ce tag permet à Symfony de :
- passer le service contrôleur en
public(car ce sera un point d'entrée de l'application, donc non appelé explicitement par nos services) - injecter les éléments demandés dans les signatures des actions (des services, des arguments, la Request),
via un
ArgumentResolver. (Cf. classeRegisterControllerArgumentLocatorsPass) Un contrôleur doit-il retourner absolument une Response ? Pas obligatoirement.
Si ce n'est pas le cas, le HttpKernel dispatche unViewEvent. Un listener pourra traiter cet évènement pour forwarder vers un contrôleur en fallback.
AbstractController
Cette classe peut être héritée par une classe de contrôleur. (Cf. classe AbstractController)
Elle fournit un certain nombre de raccourcis, pour accéder à des méthodes de certains services (cf. Service locator ci-après).
Service Locator
Il s'agit d'un proxy du Conteneur de services, contenant un sous-ensemble des services.
Par exemple, la propriété $container d'AbstractController en est un (et pas le vrai Conteneur).
Il donne accès à seulement certains services et arguments (cf. AbstractController::getSubscribedServices()).
Redirections et Forwards
Quelle est différence entre forward et redirect ?
La redirection redirige l'utilisateur vers une nouvelle page et son navigateur fait une seconde requête.
Cela lui est donc visible. C'est une redirection HTTP.
Le forward exécute une seconde (sous-)requête directement, pour en retourner sa réponse.
L'utilisateur reçoit directement le résultat de cette seconde requête sans en avoir conscience.
C'est une redirection interne.
Note : Tous les listeners seront à nouveaux appelés, même sur la requête secondaire.
Redirection
Par défaut, une redirection n'est pas permanente. Elle est conditionnée ponctuellement.
Par exemple, si on n'est pas connecté et qu'on essaie d'accéder à une page privée, on pourra
être redirigé vers la page de login. Ce n'est pas une redirection permanente, car une fois connecté, l'utilisateur
devra pouvoir y accéder.
Par défaut, le code HTTP est donc 302. On peut le rendre permanent via le code301.
Il existe également leurs pendants 308 (par défaut) et 307.
Cela oblige de conserver la même méthode HTTP (GET, POST,...).
Pour effectuer une redirection dans un contrôleur, on peut utiliser plusieurs méthodes :
public function __invoke(): RedirectResponse
{
// Si on étend l'AbstractController
return $this->redirectToRoute('app_homepage');
// ou
return $this->redirect($this->generateUrl('app_homepage'));
// Ou comme on le ferait dans un contrôleur agnostique
return new RedirectResponse(
return $this->urlGenerator->generate('app_homepage')
);
}
HttpException
Qu'est-ce qu'une HttpException ?
C'est une exception classique, dont le code correspond à un code HTTP (ex: 404, 403, ...).
Quand Symfony rencontre une erreur de ce type, il la transforme en une Response évitant ainsi de retourner
une erreur 500 au client.
Symfony implémente beaucoup d'exceptions HTTP, visibles dans
Symfony\Component\HttpKernel\Exception.
Request
Documentation La Request contient des conteneurs de données appelés bags :
query: paramètres d'URL (ex: ?foo=bar&bar=foo)request: données envoyées en POSTcookiesfiles: fichiers téléversésserver: variables $_ENV et $_SERVERheaders: variables $_SERVER['headers']attributes: variables spécifiques au fonctionnement (ex:_route) Elle permet principalement d'accéder aux données dans ces conteneurs, mais propose également un certain nombre de raccourcis, souvent pour accéder aux headers les plus communs.
Récupération des valeurs
Les valeurs de chaque bag sont accessibles de la même manière, via la même méthode get(). Ex :
use Symfony\Component\HttpFoundation\Request;
/** @var Request $request */
$request->request->get('email');
Il existe des variantes permettant de filter/convertir la donnée directement :
Filtres (utilise la fonction filter() de php derrière) :
getAlpha()getAlnum()getDigits()Conversions :getInt()getBoolean()
Cookies
Comment envoyer un cookie au navigateur de l'utilisateur ?
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Cookie;
$response = new Response('A foo enters in a bar');
$response->headers->setCookie(
Cookie::create('last_visit', \time())
);
Comment supprimer un cookie du navigateur de l'utilisateur ?
use Symfony\Component\HttpFoundation\Response;
$response = new Response('A foo enters in a bar');
$response->headers->clearCookie('last_visit');
Note : il existe également removeCookie(), qui permet (via un listener par exemple) de retirer un cookie
qui devait être ajouté via setCookie() durant le traitement de la requête.
Session
Documentation
Comment récupérer la session ?
Plusieurs manières possibles.
Elle est disponible dans le bag session de la Request :
use Symfony\Component\HttpFoundation\Request;
/** @var Request $request */
$session = $request->getSession();
$emailInSession = $session->get('email');
Elle est disponible via le Service Locator d'AbstractController :
$session = $this->get('session');
$emailInSession = $session->get('email');
On peut également l'injecter en tant que service (classe SessionInterface).
Flash message
Documentation
Un message flash est stocké dans la session.
Le principe est d'y stocker un message qui disparaitra dès qu'il est consommé/lu.
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
// Ajout d'un message flash
/** @var SessionInterface $session */
$session->getFlashBag()->add('success', 'You reach level 2!');
// ou via le raccourci d'AbstractController
/** @var AbstractController $this */
$this->addFlash('success', 'You reach level 2!');
// Consommation d'un message flash
/** @var SessionInterface $session */
$session->getFlashBag()->get('You reach level 2!');
Note :
Il existe également les fonctions peek() et peekAll() qui permettent de lire des messages sans les consommer.
Dans twig
Ce bag est accessible dans Twig via app.flashes :
{% for message in app.flashes('notice') %}
<div class="flash-notice">
{{ message }}
</div>
{% endfor %}
Contrôleurs Symfony spécifiques
Symfony fournit deux contrôleurs spécifiques :
TemplateController: pour servir automatiquement un template comme page statique.RedirectController: pour rediriger automatiquement une URL vers une autre.
Pages d'erreur
Il est possible de personnaliser les pages d'erreurs HTTP Symfony (ex: 404, 403, ...). Note : Pour tester le rendu d'une de ces pages d'erreur sans devoir causer l'erreur, on peut utiliser une URL spécifique (ex pour l'erreur 403 : localhost:8080/_error/403).