6
votes

I'm using Symfony 4.1. I'm trying to create a route "/dev/import/{file}" which can only be accessed from within the 'dev' environment.

This answer for Symfony 2 suggests adding the route to routing_dev.yml or adding condition: "request.getScriptName() == '/app_dev.php'" to your route definition.

Neither option will work. In Symfony 4 there is no routing_dev.yml, it's now dev\routing_dev.YAML, which as far as I can tell is configuration only (i.e. you can not create routes there). Routes have to be defined in routes.yaml which will apply to all environments.

Adding the route to routes.yaml and applying the condition also does not work, as we're trying to match against the app_dev front controller, which has been removed in Symfony 4.

According to the Symfony 4 Documentation, conditions in routes only expose the Context and Request objects, neither of which (AFAICT) contain any information about the current environment. So, unless I am missing something, other conditions will not work either.

One possible, but (IMHO) inelegant solution would be to check that $_SERVER['APP_ENV'] = 'dev' in the controller and throw a RouteNotFoundException if it does not.

Rather than doing that, I would really like to either have the route simply not be available when not in 'dev', or define the route somehow to test for the 'dev' environment.

Any ideas on how to do that? Preferably using annotations.

1
No idea how to do this using evil annotations but putting your routing file under config/routes/dev will work. Not sure where it is documented but if you install the debug bundle then the directory is created.Cerad

1 Answers

8
votes

If you see the default configureRoutes() method on the generated Kernel class:

 protected function configureRoutes(RouteCollectionBuilder $routes)
    {
        $confDir = $this->getProjectDir().'/config';

        $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob');
        $routes->import($confDir.'/{routes}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob');
        $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob');
    }

The second import() call reads:

$routes->import($confDir.'/{routes}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob');

This will try to load routes defined under config/routes/[environment].

So if you create a dev folder there and add your routes there, those will only be loaded when on that specific environment. Logically that could also be used to define specific, specialized routes for other possible environments, although generally that wouldn't very particularly useful.

Of course, the generated configureRoutes() method belongs to your app, and you are free to tweak it to your needs if they are more esoteric. You could always rewrite it so it loaded the routes you wanted in the specific order you of your preference.


Apparently, you can also use 'conditions' (documented here) to define the same route but evaluate at runtime if it applies according to specific circumstances.:

E.g, as shown in this answer here using annotations:

/**
 * @Route("/my_route", condition="'dev' === '%kernel.environment%'")
 */

Or using YAML configuration, like in this answer:

my_route:
    path:       /my_route}
    defaults:   { _controller: App\Controller\MyRouteController }
    condition:  "%kernel.environment% === 'dev'"

Or using XML configuration:

<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        https://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="my_route" path="/my_route" controller="App\Controller\MyRouteController">
        <condition>%kernel.environment% === 'dev'</condition>
    </route>
</routes>