Skip to content

Commit

Permalink
Implement a PSR7 routing middleware
Browse files Browse the repository at this point in the history
This middleware applies routing rules to the incoming request and
parses the CakePHP parameters out.
  • Loading branch information
markstory committed Apr 30, 2016
1 parent 3ed6b06 commit 637b994
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 0 deletions.
53 changes: 53 additions & 0 deletions src/Http/Middleware/RoutingMiddleware.php
@@ -0,0 +1,53 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Http\Middleware;

use Cake\Routing\Exception\RedirectException;
use Cake\Routing\Router;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response\RedirectResponse;

/**
* Applies routing rules to the request and creates the controller
* instance if possible.
*/
class RoutingMiddleware
{

/**
* @param ServerRequestInterface $request The request.
* @param ResponseInterface $response The response.
* @param callable $next The next middleware to call
* @return \Psr\Http\Message\ResponseInterface A response
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
{
try {
$params = (array)$request->getAttribute('params', []);
if (empty($params['controller'])) {
$path = $request->getUri()->getPath();
$request = $request->withAttribute('params', Router::parse($path, $request->getMethod()));
}
} catch (RedirectException $e) {
return new RedirectResponse(
$e->getMessage(),
$e->getCode(),
$response->getHeaders()
);
}
return $next($request, $response);
}
}
133 changes: 133 additions & 0 deletions tests/TestCase/Http/Middleware/RoutingMiddlewareTest.php
@@ -0,0 +1,133 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Test\TestCase\Http\Middleware;

use Cake\Http\Middleware\RoutingMiddleware;
use Cake\Routing\Router;
use Cake\TestSuite\TestCase;
use Zend\Diactoros\Request;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequestFactory;

/**
* Test for RoutingMiddleware
*/
class RoutingMiddlewareTest extends TestCase
{
/**
* Setup method
*
* @return void
*/
public function setUp()
{
parent::setUp();
Router::reload();
Router::connect('/articles', ['controller' => 'Articles', 'action' => 'index']);
}

/**
* Test redirect responses from redirect routes
*
* @return void
*/
public function testRedirectResponse()
{
Router::redirect('/testpath', '/pages');
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/testpath']);
$response = new Response();
$next = function ($req, $res) {
};
$middleware = new RoutingMiddleware();
$response = $middleware($request, $response, $next);

$this->assertEquals(301, $response->getStatusCode());
$this->assertEquals('http://localhost/pages', $response->getHeaderLine('Location'));
}

/**
* Test redirects with additional headers
*
* @return void
*/
public function testRedirectResponseWithHeaders()
{
Router::redirect('/testpath', '/pages');
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/testpath']);
$response = new Response('php://memory', 200, ['X-testing' => 'Yes']);
$next = function ($req, $res) {
};
$middleware = new RoutingMiddleware();
$response = $middleware($request, $response, $next);

$this->assertEquals(301, $response->getStatusCode());
$this->assertEquals('http://localhost/pages', $response->getHeaderLine('Location'));
$this->assertEquals('Yes', $response->getHeaderLine('X-testing'));
}

/**
* Test that Router sets parameters
*
* @return void
*/
public function testRouterSetParams()
{
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/articles']);
$response = new Response();
$next = function ($req, $res) {
$expected = [
'controller' => 'Articles',
'action' => 'index',
'plugin' => null,
'pass' => []
];
$this->assertEquals($expected, $req->getAttribute('params'));
};
$middleware = new RoutingMiddleware();
$middleware($request, $response, $next);
}

/**
* Test that routing is not applied if a controller exists already
*
* @return void
*/
public function testRouterNoopOnController()
{
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/articles']);
$request = $request->withAttribute('params', ['controller' => 'Articles']);
$response = new Response();
$next = function ($req, $res) {
$this->assertEquals(['controller' => 'Articles'], $req->getAttribute('params'));
};
$middleware = new RoutingMiddleware();
$middleware($request, $response, $next);
}

/**
* Test missing routes not being caught.
*
* @expectedException \Cake\Routing\Exception\MissingRouteException
*/
public function testMissingRouteNotCaught()
{
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/missing']);
$response = new Response();
$next = function ($req, $res) {
};
$middleware = new RoutingMiddleware();
$middleware($request, $response, $next);
}
}

0 comments on commit 637b994

Please sign in to comment.