I looked at the Slim code and I didn't find a simple way of allowing duplicated routes (preventing the exception).
The new Slim uses FastRoute as dependency. It calls FastRoute\simpleDispatcher
and doesn't offer any configuration possiblity. Even if it did allow some configuration, FastRoute doesn't have any built-in option to allow duplicated routes. A custom implementation of a DataGenerator
would be needed.
But following the instructions above, we can get a custom DataGenerator
by passing to Slim App a custom Router
which instantiates some FastRoute::Dispatcher implementation
which then uses the custom DataGenerator
.
First the CustomDataGenerator
(let's go the easy way and do some copy and pasting from \FastRoute\RegexBasedAbstract and \FastRoute\GroupCountBased)
<?php
class CustomDataGenerator implements \FastRoute\DataGenerator {
/*
* 1. Copy over everything from the RegexBasedAbstract
* 2. Replace abstract methods with implementations from GroupCountBased
* 3. change the addStaticRoute and addVariableRoute
* to the following implementations
*/
private function addStaticRoute($httpMethod, $routeData, $handler) {
$routeStr = $routeData[0];
if (isset($this->methodToRegexToRoutesMap[$httpMethod])) {
foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $route) {
if ($route->matches($routeStr)) {
throw new BadRouteException(sprintf(
'Static route "%s" is shadowed by previously defined variable route "%s" for method "%s"',
$routeStr, $route->regex, $httpMethod
));
}
}
}
if (isset($this->staticRoutes[$httpMethod][$routeStr])) {
unset($this->staticRoutes[$httpMethod][$routeStr]);
}
$this->staticRoutes[$httpMethod][$routeStr] = $handler;
}
private function addVariableRoute($httpMethod, $routeData, $handler) {
list($regex, $variables) = $this->buildRegexForRoute($routeData);
if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) {
unset($this->methodToRegexToRoutesMap[$httpMethod][$regex]);
}
$this->methodToRegexToRoutesMap[$httpMethod][$regex] = new \FastRoute\Route(
$httpMethod, $handler, $regex, $variables
);
}
}
Then the custom Router
<?php
class CustomRouter extends \Slim\Router {
protected function createDispatcher() {
return $this->dispatcher ?: \FastRoute\simpleDispatcher(function (\FastRoute\RouteCollector $r) {
foreach ($this->getRoutes() as $route) {
$r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
}
}, [
'routeParser' => $this->routeParser,
'dataGenerator' => new CustomDataGenerator()
]);
}
}
and finally instantiate the Slim app with the custom router
<?php
$app = new \Slim\App(array(
'router' => new CustomRouter()
));
The code above, if a duplicated route is detected, removes the previous route and stores the new one.
I hope I didn't miss any simpler way of achieving this result.