Désactiver des routes Symfony en production
Dans certains cas, il peut être nécessaire d’avoir des actions qui ne sont disponibles que lorsqu’on développe en local, mais pas en production. On peut penser au styleguide ou à des pages de debug par exemple. Voyons ensemble comment implémenter cela.
Section intitulée la-solution-rapideLa solution rapide
Pour désactiver une route rapidement, vous pourriez être tenté d’utiliser l’attribut When('dev')
au niveau du contrôleur :
use Symfony\Component\DependencyInjection\Attribute\When;
// …
#[When('dev')]
class StyleguideController extends AbstractController
{
Bien que cela permette que l’action ne soit plus exécutable en environnement de prod, elle a plusieurs inconvénients. Déjà, cela désactive complètement tout le controleur, et pas juste une action (ce qui n’est peut-être pas un souci si vous utilisez le pattern ADR
). Mais surtout, cela désactive le service attaché au contrôleur, sans supprimer la route associée à l’action. Lorsque que l’on accède à notre styleguide en env de prod, cela va donc déclencher l’exception suivante :
Uncaught PHP Exception InvalidArgumentException: "The controller for URI "/styleguide/" is not callable: Controller "App\Controller\StyleguideController" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?
Ce qui provoque une erreur 500. Je vous propose donc une autre solution qui a le mérite d’être plus granulaire et de provoquer une erreur 404 bien plus adaptée.
Section intitulée une-solution-plus-eleganteUne solution plus élégante
Pour ce faire, nous allons utiliser le système de condition au niveau de nos routes. Si la condition n’est pas respectée, alors la route ne sera pas active et une erreur 404 sera retournée.
Ces conditions vont utiliser le moteur de l’Expression Language et permettent de faire des conditions assez poussées, comme le montre la documentation :
#[Route('/action', name: action, condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'",
// expressions can also include config parameters:
// condition: "request.headers.get('User-Agent') matches '%app.allowed_browsers%'"
)]
Par défaut, il est possible d’accéder à des paramètres de la requête ou la route (variables request
, params
et context
), à des vars d’env (env('XXX')
) ou encore à des services (service('xxx')
).
Dans notre cas, on souhaite que la condition se base sur l’env Symfony, et plus précisément, quand le mode debug est activé (ce qui est le cas par défaut pour les environnements dev
et test
). Mais il semblerait qu’il ne soit pas possible d’accéder aux paramètres enregistrés dans le container (peut-être une idée de contribution dans Symfony ?), donc pas possible de faire une condition à base de %kernel.debug%
.
Pour palier ça, on va chercher à appeler la méthode isDebug()
du kernel directement :
#[Route(path: '/styleguide', name: 'styleguide', condition: "service('kernel').isDebug()")]
Mais si on fait ça, on se retrouve avec l’erreur suivante :
Uncaught PHP Exception Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: "Service "kernel" not found: the container inside "Symfony\Component\DependencyInjection\Argument\ServiceLocator" is a smaller service locator that is empty…" at ServiceLocator.php line 133"
En effet, la fonction service()
des conditions n’a pas accès au conteneur principal de l’application Symfony, mais à un container différent et plus petit dans lequel il faut explicitement définir les services présents. Heureusement, cela se fait facilement avec l’attribut AsRoutingConditionService
à ajouter sur le service qui doit être mis dans ce conteneur dédié. On modifie donc notre kernel, en définissant au passage l’alias (kernel
dans notre cas) que prendra le service dans le conteneur :
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
+#[AsRoutingConditionService('kernel')]
class Kernel extends BaseKernel
{
use MicroKernelTrait;
Voilà, on est maintenant capable de désactiver certaines routes facilement en fonction de l’environnement Symfony actuel.
À bientôt pour de nouvelles astuces 😉
Edit du 04/10/2024 :
Section intitulée la-vraie-bonne-solutionLa vraie bonne solution 😅
L’attribut Route
de Symfony dispose en fait d’une propriété env
depuis Symfony 5.3 qui permet de faire plus ou moins la même chose avec encore moins de code à écrire.
Commentaires et discussions
Nos formations sur ce sujet
Notre expertise est aussi disponible sous forme de formations professionnelles !

Symfony
Formez-vous à Symfony, l’un des frameworks Web PHP les complet au monde
Ces clients ont profité de notre expertise
Nous avons épaulé Adrenaline Hunter, juste avant le lancement public de ses offres, sur des problématiques liées à la performance de leur application développée avec Symfony. Nous avons également mis en place un système de workflow des commandes de séjours afin que toutes les actions avec leurs différents partenaires soient réparties avec fiabilité…
L’équipe d’Alain Afflelou a choisi JoliCode comme référent technique pour le développement de son nouveau site internet. Ce site web-to-store incarne l’image premium de l’enseigne, met en valeur les collections et offre aux clients de nouvelles expériences et fonctionnalités telles que l’e-réservation, le store locator, le click & collect et l’essayage…
Dans le cadre d’une refonte complète de son architecture Web, Expertissim a sollicité l’expertise de JoliCode afin de tenir les délais et le niveau de qualité attendus. Le domaine métier d’Expertissim n’est pas trivial : les spécificités du marché de l’art apportent une logique métier bien particulière et un processus complexe. La plateforme propose…