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
Pour renforcer Ouranos, le référentiel de données dédié à la signalisation ferroviaire, SNCF Réseau a sollicité JoliCode afin d’auditer et améliorer la qualité technique de l’application. Développée en Symfony et API Platform, Ouranos est au cœur des processus de production, utilisé aussi bien en interne que par l’industrie. Notre intervention s’est…
L’équipe de Finarta a fait appel à JoliCode pour le développement de leur plateforme Web. Basée sur le framework Symfony 2, l’application est un réseau privé de galerie et se veut être une place de communication et de vente d’oeuvres d’art entre ses membres. Pour cela, de nombreuses règles de droits ont été mises en places et une administration poussée…
LOOK Cycle bénéficie désormais d’une nouvelle plateforme eCommerce disponible sur 70 pays et 5 langues. La base technique modulaire de Sylius permet de répondre aux exigences de LOOK Cycle en terme de catalogue, produits, tunnel d’achat, commandes, expéditions, gestion des clients et des expéditions.