Closed Vitsen15 closed 2 years ago
So, I did it by overriding a lot of vendor methods, I'd started from DataGenerator. I just needed to use 'i' flag in regex, but there wasn't any option to set it, so I had to redefine FastRoute\DataGenerator\GroupCountBased
DataGenerator with only one character difference:
class CaseInsensitiveGroupCountBased extends \FastRoute\DataGenerator\RegexBasedAbstract
{
protected function getApproxChunkSize(): int
{
return 10;
}
protected function processChunk($regexToRoutesMap): array
{
$routeMap = [];
$regexes = [];
$numGroups = 0;
foreach ($regexToRoutesMap as $regex => $route) {
$numVariables = count($route->variables);
$numGroups = max($numGroups, $numVariables);
$regexes[] = $regex . str_repeat('()', $numGroups - $numVariables);
$routeMap[$numGroups + 1] = [$route->handler, $route->variables];
++$numGroups;
}
$regex = '~^(?|' . implode('|', $regexes) . ')$~i'; //changed line
return ['regex' => $regex, 'routeMap' => $routeMap];
}
}
league/route
package changes.All worked fine, except fully static routes...
For it I had to redefine dispatcher logic in method dispatch
of \League\Route\Dispatcher
(pls see // End of Override
):
class Dispatcher extends \League\Route\Dispatcher
{
/** @inheritDoc */
public function dispatch($httpMethod, $uri): array
{
// Lowercase static routes and uri before comparing.
$lowercaseUri = strtolower($uri);
$lowercaseStaticRoutes = array_change_key_case($this->staticRouteMap[$httpMethod]);
if (isset($lowercaseStaticRoutes[$lowercaseUri])) {
$handler = $lowercaseStaticRoutes[$lowercaseUri];
return [self::FOUND, $handler, []];
}// End of Override
$varRouteData = $this->variableRouteData;
if (isset($varRouteData[$httpMethod])) {
$result = $this->dispatchVariableRoute($varRouteData[$httpMethod], $uri);
if ($result[0] === self::FOUND) {
return $result;
}
}
// For HEAD requests, attempt fallback to GET
if ($httpMethod === 'HEAD') {
if (isset($this->staticRouteMap['GET'][$uri])) {
$handler = $this->staticRouteMap['GET'][$uri];
return [self::FOUND, $handler, []];
}
if (isset($varRouteData['GET'])) {
$result = $this->dispatchVariableRoute($varRouteData['GET'], $uri);
if ($result[0] === self::FOUND) {
return $result;
}
}
}
// If nothing else matches, try fallback routes
if (isset($this->staticRouteMap['*'][$uri])) {
$handler = $this->staticRouteMap['*'][$uri];
return [self::FOUND, $handler, []];
}
if (isset($varRouteData['*'])) {
$result = $this->dispatchVariableRoute($varRouteData['*'], $uri);
if ($result[0] === self::FOUND) {
return $result;
}
}
// Find allowed methods for this URI by matching against all other HTTP methods as well
$allowedMethods = [];
foreach ($this->staticRouteMap as $method => $uriMap) {
if ($method !== $httpMethod && isset($uriMap[$uri])) {
$allowedMethods[] = $method;
}
}
foreach ($varRouteData as $method => $routeData) {
if ($method === $httpMethod) {
continue;
}
$result = $this->dispatchVariableRoute($routeData, $uri);
if ($result[0] === self::FOUND) {
$allowedMethods[] = $method;
}
}
// If there are no allowed methods the route simply does not exist
if ($allowedMethods) {
return [self::METHOD_NOT_ALLOWED, $allowedMethods];
}
return [self::NOT_FOUND];
}
}
But \League\Route\Router
doesn't allow to set your own dispatcher, it uses composition instead of aggregation and initialize dispatcher right in dispatch
method. So I had to override it also (overided only custom dispatcher initialization):
class Router extends \League\Route\Router
{
/**
* The same as parent class method, except usage of custom dispatcher.
* The purpose is to handle case-insensitive static routes.
* Parametrized routes are covered by: RestApi\Kernel\Router\DataGenerator\CaseInsensitiveGroupCountBased.
*
* {@inheritdoc}
*/
public function dispatch(ServerRequestInterface $request): ResponseInterface
{
if ($this->getStrategy() === null) {
$this->setStrategy(new ApplicationStrategy);
}
$this->prepRoutes($request);
/**
* Use custom dispatcher
* @var Dispatcher $dispatcher
*/
$dispatcher = (new Dispatcher($this->getData()))->setStrategy($this->getStrategy()); //changed line
foreach ($this->getMiddlewareStack() as $middleware) {
if (is_string($middleware)) {
$dispatcher->lazyMiddleware($middleware);
continue;
}
$dispatcher->middleware($middleware);
}
return $dispatcher->dispatchRequest($request);
}
}
I'd recommend to add ability to pass regex options to DataGenerators.
Packages versions:
Hello,
I'm trying to use FastRoute based league/route package to handle routing on legacy project. But old routes are case insensitive in static parts. Routes parsing is handeld by FastRoute, so I decided to post question here.
I.e, I have route
/db/preferences/{id}
, which can work with url like/db/Preferences/123
on legacy mode, but don't works with new routing cause it case sensitive.How can I configure routing to handle such requests?
FYI, I know about #175.