Skip to content
This repository has been archived by the owner on Dec 12, 2021. It is now read-only.

Commit

Permalink
Caching routes enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
mkorkmaz committed Jun 17, 2017
1 parent 2e3c522 commit e9175e7
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 20 deletions.
84 changes: 70 additions & 14 deletions src/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,25 @@ final class Router

/**
* Default return type if not noted in the $routes
*
* @var string
*/
private $defaultReturnType;

/**
* @var null|string
*/
private $cachedFile;

/**
* @var array
*/
private $routerClosures = [];

/**
* Translation array.
* Make sures about return type.
*
* @var array
*/
private static $translations = [
Expand Down Expand Up @@ -115,21 +126,24 @@ final class Router
* @param string $method
* @param string $requestedPath
* @param string $folder
* @param string $cachedFile
* @throws UnexpectedValueException
*/
public function __construct(
string $defaultReturnType,
string $method,
string $requestedPath,
string $folder = ''
string $folder = '',
?string $cachedFile = null
) {
if (!in_array($method, self::$validRequestMethods, true)) {
$message = sprintf('%s is not valid Http request method.', $method);
throw new UnexpectedValueException($message);
}
$this->method = $method;
$this->requestedPath = $this->extractFolder($requestedPath, $folder);
$this->method = $method;
$this->requestedPath = $this->extractFolder($requestedPath, $folder);
$this->defaultReturnType = self::$translations[$defaultReturnType] ?? self::$validReturnTypes[0];
$this->cachedFile = $cachedFile;
}

/**
Expand Down Expand Up @@ -236,37 +250,78 @@ private function checkRequestMethodParameterType($requestMethod) : void

/**
* Dispatch against the provided HTTP method verb and URI.
* @return array
* @return FastRoute\Dispatcher
*/
private function dispatcher()
private function dispatcher() : FastRoute\Dispatcher
{
if ($this->cachedFile !== null) {
return $this->cachedDispatcher();
}
return $this->simpleDispatcher();
}

private function simpleDispatcher()
{
$options = [
'routeParser' => FastRoute\RouteParser\Std::class,
'routeParser' => FastRoute\RouteParser\Std::class,
'dataGenerator' => FastRoute\DataGenerator\GroupCountBased::class,
'dispatcher' => FastRoute\Dispatcher\GroupCountBased::class,
'dispatcher' => FastRoute\Dispatcher\GroupCountBased::class,
'routeCollector' => FastRoute\RouteCollector::class,
];
/** @var RouteCollector $routeCollector */
$routeCollector = new $options['routeCollector'](
new $options['routeParser'], new $options['dataGenerator']
);
$this->addRoutes($routeCollector);

return new $options['dispatcher']($routeCollector->getData());
}

private function cachedDispatcher()
{
$options = [
'routeParser' => FastRoute\RouteParser\Std::class,
'dataGenerator' => FastRoute\DataGenerator\GroupCountBased::class,
'dispatcher' => FastRoute\Dispatcher\GroupCountBased::class,
'routeCollector' => FastRoute\RouteCollector::class
];
if (file_exists($this->cachedFile)) {
$dispatchData = require $this->cachedFile;
if (!is_array($dispatchData)) {
throw new \RuntimeException('Invalid cache file "' . $options['cacheFile'] . '"');
}
return new $options['dispatcher']($dispatchData);
}
$routeCollector = new $options['routeCollector'](
new $options['routeParser'], new $options['dataGenerator']
);
$this->addRoutes($routeCollector);
/** @var RouteCollector $routeCollector */
$dispatchData = $routeCollector->getData();
file_put_contents(
$this->cachedFile,
'<?php return ' . var_export($dispatchData, true) . ';'
);
return new $options['dispatcher']($dispatchData );
}

/**
* Define Closures for all routes that returns controller info to be used.
* @param FastRoute\RouteCollector $route
*/
private function addRoutes(FastRoute\RouteCollector $route)
private function addRoutes(FastRoute\RouteCollector $route) : void
{
$routeIndex=0;
foreach ($this->routes as $definedRoute) {
$definedRoute[3] = $definedRoute[3] ?? $this->defaultReturnType;
$route->addRoute(strtoupper($definedRoute[0]), $definedRoute[1], function ($args) use ($definedRoute) {
[$null1, $null2, $controller, $returnType] = $definedRoute;
$returnType = Router::$translations[$returnType] ?? $this->defaultReturnType;
$routeName = 'routeClosure'.$routeIndex;
[$null1, $null2, $controller, $returnType] = $definedRoute;
$returnType = Router::$translations[$returnType] ?? $this->defaultReturnType;
$this->routerClosures[$routeName] = function($args) use ($controller, $returnType) {
return ['controller' => $controller, 'returnType'=> $returnType, 'args'=> $args];
});
};
$route->addRoute(strtoupper($definedRoute[0]), $definedRoute[1], $routeName);
$routeIndex++;
}
}

Expand All @@ -280,8 +335,9 @@ public function getRoute() : array
{
$dispatcher = $this->dispatcher();
$routeInfo = $dispatcher->dispatch($this->method, $this->requestedPath);
$route = $this->runDispatcher($routeInfo);
$routerData = [
'route' => $this->runDispatcher($routeInfo),
'route' => $route,
'aliases' => $this->aliases
];
return $routerData;
Expand Down Expand Up @@ -319,7 +375,7 @@ private function getRouteData(array $routeInfo) : array
{
if ($routeInfo[0] === FastRoute\Dispatcher::FOUND) {
[$null1, $handler, $vars] = $routeInfo;
return $handler($vars);
return $this->routerClosures[$handler]($vars);
}
return [
'status' => 200,
Expand Down
36 changes: 30 additions & 6 deletions test/RouterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ class MyRouterClass extends TestCase

private $request;

public function setUp()
public function setUp() : void
{
$basedir = dirname(__DIR__) . '/app';
$this->config['base_dir'] = $basedir;
$this->config['app_dir'] = $basedir;
$this->config['cache_file'] = '/tmp/fastroute.cache';
$_SERVER = [];
$_FILES = [];
$_GET = [];
Expand Down Expand Up @@ -50,7 +51,7 @@ public function setUp()
* @param $folder string
* @param $expected string
*/
public function shouldExtractRouteFromURLSuccessfully($requestedPath, $folder, $expected)
public function shouldExtractRouteFromURLSuccessfully($requestedPath, $folder, $expected) : void
{
$router = new Selami\Router(
$this->config['default_return_type'],
Expand All @@ -73,7 +74,7 @@ public function shouldExtractRouteFromURLSuccessfully($requestedPath, $folder, $
);
}

public function extractFolderDataProvider()
public function extractFolderDataProvider() : array
{
return [
['/', '', '/'],
Expand All @@ -82,6 +83,25 @@ public function extractFolderDataProvider()
];
}

/**
* @test
*/
public function shouldCacheRoutesSuccessfully() : void
{
$router = new Selami\Router(
$this->config['default_return_type'],
$this->request->getMethod(),
$this->request->getUri()->getPath(),
$this->config['folder'],
$this->config['cache_file']
);
$router->add('get', '/', 'app/main', 'html', 'home');
$router->getRoute();
$this->assertFileExists($this->config['cache_file'],
'Couldn\'t cache the file'
);
}

/**
* @test
*/
Expand Down Expand Up @@ -198,7 +218,6 @@ public function shouldThrowInvalidArgumentExceptionForAddMethodIfREquestMEthotIs
$router->add(200, '/', 'app/main', null, 'home');
}


/**
* @test
*/
Expand All @@ -212,7 +231,6 @@ public function shouldCorrectlyReturnMethodNotAllowed()
$this->request->getUri()->getPath(),
$this->config['folder']
);

$router->add('get', '/', 'app/main', null, 'home');
$router->add('get', '/json', 'app/json', 'json');
$router->add('post', '/json', 'app/redirect', 'redirect');
Expand All @@ -235,12 +253,18 @@ public function shouldCorrectlyReturnNotFound()
$this->request->getUri()->getPath(),
$this->config['folder']
);

$router->add('get', '/', 'app/main', null, 'home');
$router->add('get', '/json', 'app/json', 'json');
$router->add('post', '/json', 'app/redirect', 'redirect');
$router->add('get', '/alias', 'app/alias', null, 'alias');
$routeInfo = $router->getRoute();
$this->assertEquals('404', $routeInfo['route']['status'], "Router didn't correctly returnNot FOund");
}

public function tearDown()
{
if (file_exists($this->config['cache_file'])) {
unlink($this->config['cache_file']);
}
}
}

0 comments on commit e9175e7

Please sign in to comment.