Skip to content

Commit

Permalink
refs #10778 add router cache
Browse files Browse the repository at this point in the history
  • Loading branch information
steinkel committed Mar 1, 2018
1 parent 48b500e commit 03744a2
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/Routing/Middleware/RoutingMiddleware.php
Expand Up @@ -14,6 +14,9 @@
*/
namespace Cake\Routing\Middleware;

=======
use Cake\Cache\Cache;
use Cake\Core\Configure;
use Cake\Core\PluginApplicationInterface;
use Cake\Http\BaseApplication;
use Cake\Http\MiddlewareQueue;
Expand All @@ -30,6 +33,16 @@
*/
class RoutingMiddleware
{
/**
* Name of the default cache configuration name used to store routes collection
*/
const DEFAULT_ROUTER_CACHE_CONFIG = '_cake_router_';

/**
* Key used to store the route collection in the cache engine
*/
const ROUTE_COLLECTION_CACHE_KEY = 'routeCollection';

/**
* The application that will have its routing hook invoked.
*
Expand All @@ -49,6 +62,7 @@ public function __construct(BaseApplication $app = null)

/**
* Trigger the application's routes() hook if the application exists and Router isn't initialized.
* Uses the routes cache if enabled via configuration param "Router.cache"
*
* If the middleware is created without an Application, routes will be
* loaded via the automatic route loading that pre-dates the routes() hook.
Expand All @@ -60,11 +74,46 @@ protected function loadRoutes()
if (!$this->app) {
return;
}
$routeCollection = $this->buildRouteCollection();
Router::setRouteCollection($routeCollection);
// Prevent routes from being loaded again
Router::$initialized = true;
}

/**
* Check if route cache is enabled and use the configured Cache to 'remember' the route collection
*
* @return \Cake\Routing\RouteCollection
*/
protected function buildRouteCollection()
{
$isRouterCacheEnabled = Configure::read('Router.cache');
if (Cache::enabled() && $isRouterCacheEnabled) {
$routesCacheConfig = Configure::read('Router.cacheConfig', self::DEFAULT_ROUTER_CACHE_CONFIG);

return Cache::remember(self::ROUTE_COLLECTION_CACHE_KEY, function () {

return $this->prepareRouteCollection();
}, $routesCacheConfig);
}

return $this->prepareRouteCollection();
}

/**
* Generate the route collection using the builder
*
* @return \Cake\Routing\RouteCollection
*/
protected function prepareRouteCollection()
{
$builder = Router::createRouteBuilder('/');
$this->app->routes($builder);
if ($this->app instanceof PluginApplicationInterface) {
$this->app->pluginRoutes($builder);
}

return Router::getRouteCollection();
}

/**
Expand All @@ -77,6 +126,7 @@ protected function loadRoutes()
* @param \Psr\Http\Message\ResponseInterface $response The response.
* @param callable $next The next middleware to call.
* @return \Psr\Http\Message\ResponseInterface A response.
* @throws \Cake\Routing\InvalidArgumentException
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
{
Expand Down
12 changes: 12 additions & 0 deletions src/Routing/Router.php
Expand Up @@ -1148,6 +1148,17 @@ public static function getRouteCollection()
return static::$_collection;
}

/**
* Set the RouteCollection inside the Router
*
* @param RouteCollection $routeCollection
* @return void
*/
public static function setRouteCollection($routeCollection)
{
static::$_collection = $routeCollection;
}

/**
* Loads route configuration
*
Expand All @@ -1159,4 +1170,5 @@ protected static function _loadRoutes()
static::$initialized = true;
include CONFIG . 'routes.php';
}

}
87 changes: 87 additions & 0 deletions tests/TestCase/Routing/Middleware/RoutingMiddlewareTest.php
Expand Up @@ -14,6 +14,8 @@
*/
namespace Cake\Test\TestCase\Routing\Middleware;

use Cake\Cache\Cache;
use Cake\Core\Configure;
use Cake\Routing\Middleware\RoutingMiddleware;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
Expand Down Expand Up @@ -454,4 +456,89 @@ public function scopedMiddlewareUrlProvider()
['/api/version', ['second', 'last']],
];
}

/**
* Test we store route collection in cache.
*
* @return void
*/
public function testCacheRoutes()
{
Configure::write('Router.cache', true);
Cache::setConfig('_cake_router_', [
'engine' => 'File',
'path' => TMP,
]);
Router::$initialized = false;
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/articles']);
$response = new Response();
$next = function ($req, $res) {
$routeCollection = Cache::read('routeCollection', '_cake_router_');
$this->assertInstanceOf('\Cake\Routing\RouteCollection', $routeCollection);
return $res;
};
$app = new Application(CONFIG);
$middleware = new RoutingMiddleware($app);
$middleware($request, $response, $next);

Cache::clear(false, '_cake_router_');
Cache::drop('_cake_router_');
}

/**
* Test we don't cache routes if cache is disabled.
*
* @return void
*/
public function testCacheNotUsedIfCacheDisabled()
{
Configure::write('Router.cache', true);
Cache::disable();
Cache::setConfig('_cake_router_', [
'engine' => 'File',
'path' => TMP,
]);
Router::$initialized = false;
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/articles']);
$response = new Response();
$next = function ($req, $res) {
$routeCollection = Cache::read('routeCollection', '_cake_router_');
$this->assertFalse($routeCollection);
return $res;
};
$app = new Application(CONFIG);
$middleware = new RoutingMiddleware($app);
$middleware($request, $response, $next);

Cache::drop('_cake_router_');
Cache::enable();
}

/**
* Test cache name is used
*
* @return void
* @expectedException InvalidArgumentException
* @expectedExceptionMessage The "notfound" cache configuration does not exist
*/
public function testCacheConfigNotFound()
{
Configure::write('Router.cache', true);
Configure::write('Router.cacheConfig', 'notfound');
Cache::setConfig('_cake_router_', [
'engine' => 'File',
'path' => TMP,
]);
Router::$initialized = false;
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/articles']);
$response = new Response();
$next = function ($req, $res) {
return $res;
};
$app = new Application(CONFIG);
$middleware = new RoutingMiddleware($app);
$middleware($request, $response, $next);

Cache::drop('_cake_router_');
}
}

0 comments on commit 03744a2

Please sign in to comment.