Skip to content

Commit 5ab8de4

Browse files
committed
Add routes() hook.
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.
1 parent 575e4d7 commit 5ab8de4

File tree

5 files changed

+90
-2
lines changed

5 files changed

+90
-2
lines changed

src/Http/BaseApplication.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ public function bootstrap()
6161
require_once $this->configDir . '/bootstrap.php';
6262
}
6363

64+
/**
65+
* Define the routes for an application.
66+
*
67+
* By default this will load `config/routes.php` for ease of use and backwards compatibility.
68+
*
69+
* @param \Cake\Routing\RouteBuilder $routes A route builder to add routes into.
70+
* @return void
71+
*/
72+
public function routes($routes)
73+
{
74+
require $this->configDir . '/routes.php';
75+
}
76+
6477
/**
6578
* Invoke the application.
6679
*

src/Routing/Middleware/RoutingMiddleware.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
*/
1515
namespace Cake\Routing\Middleware;
1616

17+
use Cake\Http\BaseApplication;
1718
use Cake\Http\MiddlewareQueue;
1819
use Cake\Http\Runner;
1920
use Cake\Routing\Exception\RedirectException;
21+
use Cake\Routing\RouteBuilder;
2022
use Cake\Routing\Router;
2123
use Psr\Http\Message\ResponseInterface;
2224
use Psr\Http\Message\ServerRequestInterface;
@@ -28,11 +30,39 @@
2830
*/
2931
class RoutingMiddleware
3032
{
33+
/**
34+
* Constructor
35+
*
36+
* @param \Cake\Http\BaseApplication $app The application instance that routes are defined on.
37+
*/
38+
public function __construct(BaseApplication $app = null)
39+
{
40+
$this->app = $app;
41+
}
42+
43+
/**
44+
* Trigger the application's routes() hook if the application exists.
45+
*
46+
* If the middleware is created without an Application, routes will be
47+
* loaded via the automatic route loading that pre-dates the routes() hook.
48+
*
49+
* @return void
50+
*/
51+
protected function loadRoutes()
52+
{
53+
if ($this->app) {
54+
$builder = Router::getRouteBuilder('/');
55+
$this->app->routes($builder);
56+
// Prevent routes from being loaded again
57+
Router::$initialized = true;
58+
}
59+
}
60+
3161
/**
3262
* Apply routing and update the request.
3363
*
34-
* Any route/path specific middleware will be wrapped around $next and then the new middleware stack
35-
* will be invoked.
64+
* Any route/path specific middleware will be wrapped around $next and then the new middleware stack will be
65+
* invoked.
3666
*
3767
* @param \Psr\Http\Message\ServerRequestInterface $request The request.
3868
* @param \Psr\Http\Message\ResponseInterface $response The response.
@@ -41,6 +71,7 @@ class RoutingMiddleware
4171
*/
4272
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
4373
{
74+
$this->loadRoutes();
4475
try {
4576
Router::setRequestContext($request);
4677
$params = (array)$request->getAttribute('params', []);

src/Routing/Router.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,7 @@ public static function getRouteCollection()
10861086
/**
10871087
* Loads route configuration
10881088
*
1089+
* @deprecated 3.5.0 Routes will be loaded via the Application::routes() hook in 4.0.0
10891090
* @return void
10901091
*/
10911092
protected static function _loadRoutes()

tests/TestCase/Routing/Middleware/RoutingMiddlewareTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Cake\Routing\Middleware\RoutingMiddleware;
1818
use Cake\Routing\Router;
1919
use Cake\TestSuite\TestCase;
20+
use TestApp\Application;
2021
use Zend\Diactoros\Response;
2122
use Zend\Diactoros\ServerRequestFactory;
2223

@@ -104,6 +105,35 @@ public function testRouterSetParams()
104105
$middleware($request, $response, $next);
105106
}
106107

108+
/**
109+
* Test middleware invoking hook method
110+
*
111+
* @return void
112+
*/
113+
public function testRoutesHookInvokedOnApp()
114+
{
115+
Router::reload();
116+
$this->assertFalse(Router::$initialized, 'Router precondition failed');
117+
118+
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/app/articles']);
119+
$response = new Response();
120+
$next = function ($req, $res) {
121+
$expected = [
122+
'controller' => 'Articles',
123+
'action' => 'index',
124+
'plugin' => null,
125+
'pass' => [],
126+
'_matchedRoute' => '/app/articles'
127+
];
128+
$this->assertEquals($expected, $req->getAttribute('params'));
129+
$this->assertTrue(Router::$initialized, 'Router state should indicate routes loaded');
130+
$this->assertCount(1, Router::routes());
131+
};
132+
$app = new Application(CONFIG);
133+
$middleware = new RoutingMiddleware($app);
134+
$middleware($request, $response, $next);
135+
}
136+
107137
/**
108138
* Test that routing is not applied if a controller exists already
109139
*

tests/test_app/TestApp/Application.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,17 @@ public function middleware($middleware)
4242

4343
return $middleware;
4444
}
45+
46+
/**
47+
* Routes hook, used for testing with RoutingMiddleware.
48+
*
49+
* @param \Cake\Routing\RouteBuilder $routes
50+
* @return void
51+
*/
52+
public function routes($routes)
53+
{
54+
$routes->scope('/app', function ($routes) {
55+
$routes->connect('/articles', ['controller' => 'Articles']);
56+
});
57+
}
4558
}

0 commit comments

Comments
 (0)