Skip to content

Commit

Permalink
Merge c58a2bb into 77daca6
Browse files Browse the repository at this point in the history
  • Loading branch information
l0gicgate committed May 24, 2018
2 parents 77daca6 + c58a2bb commit d9e02ee
Show file tree
Hide file tree
Showing 11 changed files with 991 additions and 56 deletions.
20 changes: 12 additions & 8 deletions Slim/App.php
Expand Up @@ -13,6 +13,8 @@
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UriInterface;
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Exception\HttpNotFoundException;
use Slim\Http\Headers;
use Slim\Http\Request;
use Slim\Http\Response;
Expand Down Expand Up @@ -502,23 +504,25 @@ public function respond(ResponseInterface $response)
* @param ResponseInterface $response The most recent Response object
*
* @return ResponseInterface
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response)
{
// Get the route info
$routeInfo = $request->getAttribute('routeInfo');

/** @var \Slim\Interfaces\RouterInterface $router */
$router = $this->getRouter();
/**
* @var RoutingResults $routingResults
*/
$routingResults = $request->getAttribute('routingResults');

// If routing hasn't been done, then do it now so we can dispatch
if ($routeInfo === null) {
if ($routingResults === null) {
$router = $this->getRouter();
$routingMiddleware = new RoutingMiddleware($router);
$request = $routingMiddleware->performRouting($request);
$routeInfo = $request->getAttribute('routeInfo');
}

$route = $router->lookupRoute($routeInfo[1]);
$route = $request->getAttribute('route');
return $route->run($request, $response);
}

Expand Down
131 changes: 131 additions & 0 deletions Slim/Dispatcher.php
@@ -0,0 +1,131 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2018 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
*/
namespace Slim;

use FastRoute\Dispatcher\GroupCountBased;

class Dispatcher extends GroupCountBased
{
/**
* @var string
*/
private $httpMethod;

/**
* @var string
*/
private $uri;

/**
* @var array
*/
private $allowedMethods = [];

/**
* @param string $httpMethod
* @param string $uri
* @return RoutingResults
*/
public function dispatch($httpMethod, $uri)
{
$this->httpMethod = $httpMethod;
$this->uri = $uri;

if (isset($this->staticRouteMap[$httpMethod][$uri])) {
return $this->routingResults(self::FOUND, $this->staticRouteMap[$httpMethod][$uri]);
}

$varRouteData = $this->variableRouteData;
if (isset($varRouteData[$httpMethod])) {
$result = $this->dispatchVariableRoute($varRouteData[$httpMethod], $uri);
$routingResults = $this->routingResultsFromVariableRouteResults($result);
if ($routingResults->getRouteStatus() === Dispatcher::FOUND) {
return $routingResults;
}
}

// For HEAD requests, attempt fallback to GET
if ($httpMethod === 'HEAD') {
if (isset($this->staticRouteMap['GET'][$uri])) {
return $this->routingResults(self::FOUND, $this->staticRouteMap['GET'][$uri]);
}
if (isset($varRouteData['GET'])) {
$result = $this->dispatchVariableRoute($varRouteData['GET'], $uri);
return $this->routingResultsFromVariableRouteResults($result);
}
}

// If nothing else matches, try fallback routes
if (isset($this->staticRouteMap['*'][$uri])) {
return $this->routingResults(self::FOUND, $this->staticRouteMap['*'][$uri]);
}
if (isset($varRouteData['*'])) {
$result = $this->dispatchVariableRoute($varRouteData['*'], $uri);
return $this->routingResultsFromVariableRouteResults($result);
}

if (count($this->getAllowedMethods($httpMethod, $uri))) {
return $this->routingResults(self::METHOD_NOT_ALLOWED);
}

return $this->routingResults(self::NOT_FOUND);
}

/**
* @param $status
* @param null $handler
* @param array $arguments
* @return RoutingResults
*/
protected function routingResults($status, $handler = null, $arguments = [])
{
return new RoutingResults($this, $this->httpMethod, $this->uri, $status, $handler, $arguments);
}

/**
* @param array $result
* @return RoutingResults
*/
protected function routingResultsFromVariableRouteResults($result)
{
if ($result[0] === self::FOUND) {
return $this->routingResults(self::FOUND, $result[1], $result[2]);
}
return $this->routingResults(self::NOT_FOUND);
}

/**
* @param string $httpMethod
* @param string $uri
* @return array
*/
public function getAllowedMethods($httpMethod, $uri)
{
if (isset($this->allowedMethods[$uri])) {
return $this->allowedMethods[$uri];
}

$this->allowedMethods[$uri] = [];
foreach ($this->staticRouteMap as $method => $uriMap) {
if ($method !== $httpMethod && isset($uriMap[$uri])) {
$this->allowedMethods[$uri][] = $method;
}
}

$varRouteData = $this->variableRouteData;
foreach ($varRouteData as $method => $routeData) {
$result = $this->dispatchVariableRoute($routeData, $uri);
if ($result[0] === self::FOUND) {
$this->allowedMethods[$uri][] = $method;
}
}

return $this->allowedMethods[$uri];
}
}
2 changes: 1 addition & 1 deletion Slim/Exception/HttpMethodNotAllowedException.php
Expand Up @@ -21,7 +21,7 @@ class HttpMethodNotAllowedException extends HttpSpecializedException
protected $description = 'The request method is not supported for the requested resource.';

/**
* @return string
* @return array
*/
public function getAllowedMethods()
{
Expand Down
3 changes: 2 additions & 1 deletion Slim/Interfaces/RouterInterface.php
Expand Up @@ -11,6 +11,7 @@
use RuntimeException;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Slim\RoutingResults;

/**
* Router Interface
Expand Down Expand Up @@ -40,7 +41,7 @@ public function map($methods, $pattern, $handler);
*
* @param ServerRequestInterface $request The current HTTP request object
*
* @return array
* @return RoutingResults
*
* @link https://github.com/nikic/FastRoute/blob/master/src/Dispatcher.php
*/
Expand Down
46 changes: 25 additions & 21 deletions Slim/Middleware/RoutingMiddleware.php
Expand Up @@ -14,6 +14,7 @@
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Exception\HttpNotFoundException;
use Slim\Interfaces\RouterInterface;
use RuntimeException;

/**
* Perform routing and store matched route to the request's attributes
Expand Down Expand Up @@ -41,6 +42,10 @@ public function __construct(RouterInterface $router)
* @param ResponseInterface $response PSR7 response
* @param callable $next Middleware callable
* @return ResponseInterface PSR7 response
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
* @throws RuntimeException
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
Expand All @@ -53,35 +58,34 @@ public function __invoke(ServerRequestInterface $request, ResponseInterface $res
*
* @param ServerRequestInterface $request PSR7 server request
* @return ServerRequestInterface
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
*/
public function performRouting(ServerRequestInterface $request)
{
$routeInfo = $this->router->dispatch($request);
$routingResults = $this->router->dispatch($request);
$routeStatus = $routingResults->getRouteStatus();

if ($routeInfo[0] === Dispatcher::FOUND) {
$routeArguments = [];
foreach ($routeInfo[2] as $k => $v) {
$routeArguments[$k] = urldecode($v);
}
switch ($routeStatus) {
case Dispatcher::FOUND:
$routeArguments = $routingResults->getRouteArguments();
$route = $this->router->lookupRoute($routingResults->getRouteHandler());
$route->prepare($request, $routeArguments);
return $request
->withAttribute('route', $route)
->withAttribute('routingResults', $routingResults);

$route = $this->router->lookupRoute($routeInfo[1]);
$route->prepare($request, $routeArguments);
case Dispatcher::NOT_FOUND:
throw new HttpNotFoundException($request);

// add route to the request's attributes
$request = $request->withAttribute('route', $route);
} elseif ($routeInfo[0] === Dispatcher::NOT_FOUND) {
$exception = new HttpNotFoundException($request);
throw $exception;
} elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
$exception = new HttpMethodNotAllowedException($request);
$exception->setAllowedMethods($routeInfo[1]);
throw $exception;
}
case Dispatcher::METHOD_NOT_ALLOWED:
$exception = new HttpMethodNotAllowedException($request);
$exception->setAllowedMethods($routingResults->getAllowedMethods());
throw $exception;

// routeInfo to the request's attributes
$routeInfo['request'] = [$request->getMethod(), (string) $request->getUri()];
return $request->withAttribute('routeInfo', $routeInfo);
default:
throw new RuntimeException('An unexpected error occurred while performing routing.');
}
}
}
21 changes: 8 additions & 13 deletions Slim/Router.php
Expand Up @@ -8,7 +8,6 @@
*/
namespace Slim;

use FastRoute\Dispatcher;
use InvalidArgumentException;
use RuntimeException;
use Psr\Http\Message\ServerRequestInterface;
Expand Down Expand Up @@ -85,7 +84,7 @@ class Router implements RouterInterface
protected $routeGroups = [];

/**
* @var \FastRoute\Dispatcher
* @var Dispatcher
*/
protected $dispatcher;

Expand Down Expand Up @@ -213,18 +212,12 @@ public function map($methods, $pattern, $handler)
*
* @param ServerRequestInterface $request The current HTTP request object
*
* @return array
*
* @link https://github.com/nikic/FastRoute/blob/master/src/Dispatcher.php
* @return RoutingResults
*/
public function dispatch(ServerRequestInterface $request)
{
$uri = '/' . ltrim($request->getUri()->getPath(), '/');

return $this->createDispatcher()->dispatch(
$request->getMethod(),
$uri
);
$uri = '/' . ltrim(rawurldecode($request->getUri()->getPath()), '/');
return $this->createDispatcher()->dispatch($request->getMethod(), $uri);
}

/**
Expand All @@ -250,7 +243,7 @@ protected function createRoute($methods, $pattern, $callable)
}

/**
* @return \FastRoute\Dispatcher
* @return Dispatcher
*/
protected function createDispatcher()
{
Expand All @@ -266,11 +259,13 @@ protected function createDispatcher()

if ($this->cacheFile) {
$this->dispatcher = \FastRoute\cachedDispatcher($routeDefinitionCallback, [
'dispatcher' => Dispatcher::class,
'routeParser' => $this->routeParser,
'cacheFile' => $this->cacheFile,
]);
} else {
$this->dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback, [
'dispatcher' => Dispatcher::class,
'routeParser' => $this->routeParser,
]);
}
Expand All @@ -279,7 +274,7 @@ protected function createDispatcher()
}

/**
* @param \FastRoute\Dispatcher $dispatcher
* @param Dispatcher $dispatcher
*/
public function setDispatcher(Dispatcher $dispatcher)
{
Expand Down

0 comments on commit d9e02ee

Please sign in to comment.