Skip to content

Commit

Permalink
Add routes() hook.
Browse files Browse the repository at this point in the history
This hook method is currently optional, but will become required in
4.0.0, and replaces the automatic route loading that Router currently
uses. To fully remove that behavior we'll need to break compatibility,
and there are a few other Router deprecations that need to be done
first.
  • Loading branch information
markstory committed May 11, 2017
1 parent 575e4d7 commit 5ab8de4
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 2 deletions.
13 changes: 13 additions & 0 deletions src/Http/BaseApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ public function bootstrap()
require_once $this->configDir . '/bootstrap.php';
}

/**
* Define the routes for an application.
*
* By default this will load `config/routes.php` for ease of use and backwards compatibility.
*
* @param \Cake\Routing\RouteBuilder $routes A route builder to add routes into.
* @return void
*/
public function routes($routes)
{
require $this->configDir . '/routes.php';
}

/**
* Invoke the application.
*
Expand Down
35 changes: 33 additions & 2 deletions src/Routing/Middleware/RoutingMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
*/
namespace Cake\Routing\Middleware;

use Cake\Http\BaseApplication;
use Cake\Http\MiddlewareQueue;
use Cake\Http\Runner;
use Cake\Routing\Exception\RedirectException;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
Expand All @@ -28,11 +30,39 @@
*/
class RoutingMiddleware
{
/**
* Constructor
*
* @param \Cake\Http\BaseApplication $app The application instance that routes are defined on.
*/
public function __construct(BaseApplication $app = null)
{
$this->app = $app;
}

/**
* Trigger the application's routes() hook if the application exists.
*
* If the middleware is created without an Application, routes will be
* loaded via the automatic route loading that pre-dates the routes() hook.
*
* @return void
*/
protected function loadRoutes()
{
if ($this->app) {
$builder = Router::getRouteBuilder('/');
$this->app->routes($builder);
// Prevent routes from being loaded again
Router::$initialized = true;
}
}

/**
* Apply routing and update the request.
*
* Any route/path specific middleware will be wrapped around $next and then the new middleware stack
* will be invoked.
* Any route/path specific middleware will be wrapped around $next and then the new middleware stack will be
* invoked.
*
* @param \Psr\Http\Message\ServerRequestInterface $request The request.
* @param \Psr\Http\Message\ResponseInterface $response The response.
Expand All @@ -41,6 +71,7 @@ class RoutingMiddleware
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
{
$this->loadRoutes();
try {
Router::setRequestContext($request);
$params = (array)$request->getAttribute('params', []);
Expand Down
1 change: 1 addition & 0 deletions src/Routing/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,7 @@ public static function getRouteCollection()
/**
* Loads route configuration
*
* @deprecated 3.5.0 Routes will be loaded via the Application::routes() hook in 4.0.0
* @return void
*/
protected static function _loadRoutes()
Expand Down
30 changes: 30 additions & 0 deletions tests/TestCase/Routing/Middleware/RoutingMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Cake\Routing\Middleware\RoutingMiddleware;
use Cake\Routing\Router;
use Cake\TestSuite\TestCase;
use TestApp\Application;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequestFactory;

Expand Down Expand Up @@ -104,6 +105,35 @@ public function testRouterSetParams()
$middleware($request, $response, $next);
}

/**
* Test middleware invoking hook method
*
* @return void
*/
public function testRoutesHookInvokedOnApp()
{
Router::reload();
$this->assertFalse(Router::$initialized, 'Router precondition failed');

$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/app/articles']);
$response = new Response();
$next = function ($req, $res) {
$expected = [
'controller' => 'Articles',
'action' => 'index',
'plugin' => null,
'pass' => [],
'_matchedRoute' => '/app/articles'
];
$this->assertEquals($expected, $req->getAttribute('params'));
$this->assertTrue(Router::$initialized, 'Router state should indicate routes loaded');
$this->assertCount(1, Router::routes());
};
$app = new Application(CONFIG);
$middleware = new RoutingMiddleware($app);
$middleware($request, $response, $next);
}

/**
* Test that routing is not applied if a controller exists already
*
Expand Down
13 changes: 13 additions & 0 deletions tests/test_app/TestApp/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,17 @@ public function middleware($middleware)

return $middleware;
}

/**
* Routes hook, used for testing with RoutingMiddleware.
*
* @param \Cake\Routing\RouteBuilder $routes
* @return void
*/
public function routes($routes)
{
$routes->scope('/app', function ($routes) {
$routes->connect('/articles', ['controller' => 'Articles']);
});
}
}

0 comments on commit 5ab8de4

Please sign in to comment.