Skip to content

Commit

Permalink
Merge 058d684 into a60a712
Browse files Browse the repository at this point in the history
  • Loading branch information
akrabat committed Aug 17, 2017
2 parents a60a712 + 058d684 commit 2e09240
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 53 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,7 @@
### Added

- [#2166](https://github.com/slimphp/Slim/pull/2166) Added Middleware\OutputBufferingMiddleware
- [#2288](https://github.com/slimphp/Slim/pull/2288) Separate routing from dispatching

### Deprecated

Expand Down
44 changes: 5 additions & 39 deletions Slim/App.php
Expand Up @@ -24,6 +24,7 @@
use Slim\Interfaces\RouteGroupInterface;
use Slim\Interfaces\RouteInterface;
use Slim\Interfaces\RouterInterface;
use Slim\Middleware\RoutingMiddleware;
use Throwable;

/**
Expand Down Expand Up @@ -80,7 +81,6 @@ class App
protected $settings = [
'httpVersion' => '1.1',
'responseChunkSize' => 4096,
'determineRouteBeforeAppMiddleware' => false,
'displayErrorDetails' => false,
'addContentLengthHeader' => true,
'routerCacheFile' => false,
Expand Down Expand Up @@ -642,12 +642,6 @@ public function process(ServerRequestInterface $request, ResponseInterface $resp
{
$router = $this->getRouter();

// Dispatch the Router first if the setting for this is on
if ($this->getSetting('determineRouteBeforeAppMiddleware') === true) {
// Dispatch router (note: you won't be able to alter routes after this)
$request = $this->dispatchRouterAndPrepareRoute($request, $router);
}

// Traverse middleware stack
try {
$response = $this->callMiddlewareStack($request, $response);
Expand Down Expand Up @@ -744,9 +738,10 @@ public function __invoke(ServerRequestInterface $request, ResponseInterface $res
/** @var \Slim\Interfaces\RouterInterface $router */
$router = $this->getRouter();

// If router hasn't been dispatched or the URI changed then dispatch
if (null === $routeInfo || ($routeInfo['request'] !== [$request->getMethod(), (string) $request->getUri()])) {
$request = $this->dispatchRouterAndPrepareRoute($request, $router);
// If routing hasn't been done, then do it now so we can dispatch
if (null === $routeInfo) {
$routingMiddleware = new RoutingMiddleware($router);
$request = $routingMiddleware->performRouting($request);
$routeInfo = $request->getAttribute('routeInfo');
}

Expand All @@ -762,35 +757,6 @@ public function __invoke(ServerRequestInterface $request, ResponseInterface $res
return $notFoundHandler($request, $response);
}

/**
* Dispatch the router to find the route. Prepare the route for use.
*
* @param ServerRequestInterface $request
* @param RouterInterface $router
* @return ServerRequestInterface
*/
protected function dispatchRouterAndPrepareRoute(ServerRequestInterface $request, RouterInterface $router)
{
$routeInfo = $router->dispatch($request);

if ($routeInfo[0] === Dispatcher::FOUND) {
$routeArguments = [];
foreach ($routeInfo[2] as $k => $v) {
$routeArguments[$k] = urldecode($v);
}

$route = $router->lookupRoute($routeInfo[1]);
$route->prepare($request, $routeArguments);

// add route to the request's attributes in case a middleware or handler needs access to the route
$request = $request->withAttribute('route', $route);
}

$routeInfo['request'] = [$request->getMethod(), (string) $request->getUri()];

return $request->withAttribute('routeInfo', $routeInfo);
}

/**
* Finalize response
*
Expand Down
1 change: 0 additions & 1 deletion Slim/Container.php
Expand Up @@ -51,7 +51,6 @@ class Container extends PimpleContainer implements ContainerInterface
'httpVersion' => '1.1',
'responseChunkSize' => 4096,
'outputBuffering' => 'append',
'determineRouteBeforeAppMiddleware' => false,
'displayErrorDetails' => false,
'addContentLengthHeader' => true,
'routerCacheFile' => false,
Expand Down
62 changes: 62 additions & 0 deletions Slim/Middleware/RoutingMiddleware.php
@@ -0,0 +1,62 @@
<?php
namespace Slim\Middleware;

use FastRoute\Dispatcher;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\RouterInterface;

/**
* Perform routing and store matched route to the request's attributes
*/
class RoutingMiddleware
{
protected $router;

public function __construct(RouterInterface $router)
{
$this->router = $router;
}

/**
* Invoke
*
* @param ServerRequestInterface $request PSR7 server request
* @param ResponseInterface $response PSR7 response
* @param callable $next Middleware callable
* @return ResponseInterface PSR7 response
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
$request = $this->performRouting($request);
return $next($request, $response);
}

/**
* Perform routing
*
* @param ServerRequestInterface $request PSR7 server request
* @return ServerRequestInterface
*/
public function performRouting(ServerRequestInterface $request)
{
$routeInfo = $this->router->dispatch($request);

if ($routeInfo[0] === Dispatcher::FOUND) {
$routeArguments = [];
foreach ($routeInfo[2] as $k => $v) {
$routeArguments[$k] = urldecode($v);
}

$route = $this->router->lookupRoute($routeInfo[1]);
$route->prepare($request, $routeArguments);

// add route to the request's attributes
$request = $request->withAttribute('route', $route);
}

// routeInfo to the request's attributes
$routeInfo['request'] = [$request->getMethod(), (string) $request->getUri()];
return $request->withAttribute('routeInfo', $routeInfo);
}
}
13 changes: 0 additions & 13 deletions tests/AppTest.php
Expand Up @@ -1895,19 +1895,6 @@ public function testRunNotAllowed()
// $res = $app->run(true);
// }

public function testAppRunWithdetermineRouteBeforeAppMiddleware()
{
$app = $this->appFactory();
$app->addSetting('determineRouteBeforeAppMiddleware', true);
$app->get('/foo', function ($req, $res) {
return $res->write("Test");
});

$resOut = $app->run(true);
$resOut->getBody()->rewind();
$this->assertEquals("Test", $resOut->getBody()->getContents());
}

public function testExceptionErrorHandlerDisplaysErrorDetails()
{
$app = new App([
Expand Down
86 changes: 86 additions & 0 deletions tests/Middleware/RoutingTest.php
@@ -0,0 +1,86 @@
<?php
/**
* Slim Framework (https://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2017 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Tests\Middleware;

use Closure;
use FastRoute\Dispatcher;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Http\Body;
use Slim\Http\Headers;
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Http\Uri;
use Slim\Middleware\RoutingMiddleware;
use Slim\Router;

class RoutingMiddlewareTest extends TestCase
{
protected function getRouter()
{
$router = new Router();
$router->map(['GET'], '/hello/{name}', null);

return $router;
}

public function testRouteIsStoredOnSuccessfulMatch()
{
$router = $this->getRouter();
$mw = new RoutingMiddleware($router);

$uri = Uri::createFromString('https://example.com:443/hello/foo');
$body = new Body(fopen('php://temp', 'r+'));
$request = new Request('GET', $uri, new Headers(), [], [], $body);
$response = new Response();

$next = function (ServerRequestInterface $req, ResponseInterface $res) {
// route is available
$route = $req->getAttribute('route');
$this->assertNotNull($route);
$this->assertEquals('foo', $route->getArgument('name'));

// routeInfo is available
$routeInfo = $req->getAttribute('routeInfo');
$this->assertInternalType('array', $routeInfo);
return $res;
};
Closure::bind($next, $this); // bind test class so we can test request object

$result = $mw($request, $response, $next);
}

public function testRouteIsNotStoredOnMethodNotAllowed()
{
$router = $this->getRouter();
$mw = new RoutingMiddleware($router);

$uri = Uri::createFromString('https://example.com:443/hello/foo');
$body = new Body(fopen('php://temp', 'r+'));
$request = new Request('POST', $uri, new Headers(), [], [], $body);
$response = new Response();

$next = function (ServerRequestInterface $req, ResponseInterface $res) {
// route is not available
$route = $req->getAttribute('route');
$this->assertNull($route);

// routeInfo is available
$routeInfo = $req->getAttribute('routeInfo');
$this->assertInternalType('array', $routeInfo);
$this->assertEquals(Dispatcher::METHOD_NOT_ALLOWED, $routeInfo[0]);


return $res;
};
Closure::bind($next, $this); // bind test class so we can test request object
$result = $mw($request, $response, $next);
}
}

0 comments on commit 2e09240

Please sign in to comment.