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
JoliCode a été sollicité pour accompagner le développement de la nouvelle version du site. Conçue avec le framework Symfony2, cette nouvelle version bénéficie de la performance et la fiabilité du framework français. Reposant sur des technologies comme Elasticsearch, cette nouvelle version tend à offrir une expérience optimale à l’internaute. Le développement…
Nous avons réalisé différentes applications métier à l’aide de technologies comme Symfony2 et Titanium. Arianespace s’est appuyé sur l’expertise reconnue de JoliCode pour mettre en place des applications sur mesure, testées et réalisées avec un haut niveau de qualité.
Les site e-commerces font face à de nombreuses problématiques : gestion de fort trafic, recherche parmi des milliers de références etc. JoliCode a accompagné l’équipe Smallable dans le choix des solutions pouvant répondre à ces enjeux : utilisation de briques asynchrones, conception d’index Elasticsearch pérenne.