diff options
-rw-r--r-- | src/Router.php | 43 | ||||
-rw-r--r-- | src/Router/Runner.php | 49 | ||||
-rw-r--r-- | src/Router/Runner/Callback.php | 3 | ||||
-rw-r--r-- | src/Router/Runner/Controller.php | 5 | ||||
-rw-r--r-- | src/Router/Runner/PhpScript.php | 15 | ||||
-rw-r--r-- | src/Router/Runner/RunnerFactory.php | 33 | ||||
-rw-r--r-- | tests/Router/Runner/CallbackTest.php | 4 | ||||
-rw-r--r-- | tests/Router/Runner/ControllerTest.php | 2 | ||||
-rw-r--r-- | tests/Router/Runner/PhpScriptTest.php | 6 | ||||
-rw-r--r-- | tests/Router/Runner/RunnerFactoryTest.php | 41 | ||||
-rw-r--r-- | tests/Router/RunnerTest.php | 35 | ||||
-rw-r--r-- | tests/RouterTest.php | 40 |
12 files changed, 169 insertions, 107 deletions
diff --git a/src/Router.php b/src/Router.php index 955e1e1..a7d4bca 100644 --- a/src/Router.php +++ b/src/Router.php @@ -2,7 +2,7 @@ namespace Jasny; -use Jasny\Router\Runner; +use Jasny\Router\Runner\RunnerFactory; use Jasny\Router\Routes\Glob; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; @@ -23,6 +23,12 @@ class Router * @var array **/ protected $middlewares = []; + + /** + * Factory of Runner objects + * @var RunnerFactory + **/ + protected $factory = null; /** * Class constructor @@ -55,6 +61,37 @@ class Router } /** + * Get factory of Runner objects + * + * @return RunnerFactory + */ + public function getFactory() + { + if (!isset($this->factory)) { + $this->factory = new RunnerFactory(); + } + + return $this->factory; + } + + /** + * Set the factory of Runner objects + * + * @param callable $factory + * @return Router $this + */ + public function setFactory($factory) + { + if (!is_callable($factory)) { + throw new \InvalidArgumentException("Factory must be a callable"); + } + + $this->factory = $factory; + + return $this; + } + + /** * Add middleware call to router * * @param callback $middleware @@ -125,7 +162,9 @@ class Router if (!$route) return $this->notFound($response); - $runner = Runner::create($route); + $request->withAttribute('route', $route); + $factory = $this->getFactory(); + $runner = $factory($route); return $runner($request, $response, $next); } diff --git a/src/Router/Runner.php b/src/Router/Runner.php index 51300a4..87f082e 100644 --- a/src/Router/Runner.php +++ b/src/Router/Runner.php @@ -10,32 +10,7 @@ use Jasny\Router\Route; * A runner can be invoked in order to run the action specified in a route */ abstract class Runner -{ - /** - * @var \stdClass - */ - protected $route; - - /** - * Class constructor - * - * @param \stdClass $route - */ - public function __construct(\stdClass $route) - { - $this->route = $route; - } - - /** - * Get runner route - * - * @return Route - */ - public function getRoute() - { - return $this->route; - } - +{ /** * Invoke the action specified in the route * @@ -63,27 +38,5 @@ abstract class Runner return $response; } - - /** - * Factory method - * - * @param Route $route - * @return Runner - * @throws \RuntimeException if the route is misconfigured - */ - public static function create(Route $route) - { - if (isset($route->controller)) { - $class = Runner\Controller::class; - } elseif (isset($route->fn)) { - $class = Runner\Callback::class; - } elseif (isset($route->file)) { - $class = Runner\PhpScript::class; - } else { - throw new \RuntimeException("Route has neither 'controller', 'fn' or 'file' defined"); - } - - return new $class($route); - } } diff --git a/src/Router/Runner/Callback.php b/src/Router/Runner/Callback.php index 34ebc4c..7f4c457 100644 --- a/src/Router/Runner/Callback.php +++ b/src/Router/Runner/Callback.php @@ -22,7 +22,8 @@ class Callback extends Runner */ public function run(ServerRequestInterface $request, ResponseInterface $response) { - $callback = !empty($this->route->fn) ? $this->route->fn : null; + $route = $request->getAttribute('route'); + $callback = !empty($route->fn) ? $route->fn : null; if (!is_callable($callback)) { throw new \RuntimeException("'fn' property of route shoud be a callable"); diff --git a/src/Router/Runner/Controller.php b/src/Router/Runner/Controller.php index 0488be5..56cf2b5 100644 --- a/src/Router/Runner/Controller.php +++ b/src/Router/Runner/Controller.php @@ -22,7 +22,8 @@ class Controller extends Runner */ public function run(ServerRequestInterface $request, ResponseInterface $response) { - $class = !empty($this->route->controller) ? $this->route->controller : null; + $route = $request->getAttribute('route'); + $class = !empty($route->controller) ? $route->controller : null; if (!class_exists($class)) { throw new \RuntimeException("Can not route to controller '$class': class not exists"); @@ -32,7 +33,7 @@ class Controller extends Runner throw new \RuntimeException("Can not route to controller '$class': class does not have '__invoke' method"); } - $controller = new $class($this->route); + $controller = new $class($route); return $controller($request, $response); } diff --git a/src/Router/Runner/PhpScript.php b/src/Router/Runner/PhpScript.php index f6595a3..d223bd7 100644 --- a/src/Router/Runner/PhpScript.php +++ b/src/Router/Runner/PhpScript.php @@ -10,17 +10,7 @@ use Psr\Http\Message\ResponseInterface; * Route to a PHP script */ class PhpScript extends Runner -{ - /** - * Return route file path - * - * @return string - */ - public function __toString() - { - return (string)$this->route->file; - } - +{ /** * Route to a file * @@ -30,7 +20,8 @@ class PhpScript extends Runner */ public function run(ServerRequestInterface $request, ResponseInterface $response) { - $file = !empty($this->route->file) ? ltrim($this->route->file, '/') : ''; + $route = $request->getAttribute('route'); + $file = !empty($route->file) ? ltrim($route->file, '/') : ''; if (!file_exists($file)) { throw new \RuntimeException("Failed to route using '$file': File '$file' doesn't exist."); diff --git a/src/Router/Runner/RunnerFactory.php b/src/Router/Runner/RunnerFactory.php new file mode 100644 index 0000000..e32d2cc --- /dev/null +++ b/src/Router/Runner/RunnerFactory.php @@ -0,0 +1,33 @@ +<?php + +namespace Jasny\Router\Runner; + +use Jasny\Router\Route; + +/** + * Factory of Runner instances + */ +class RunnerFactory +{ + /** + * Create Runner instance + * + * @param Route $route + * @return Runner + */ + public function __invoke(Route $route) + { + if (isset($route->controller)) { + $class = Controller::class; + } elseif (isset($route->fn)) { + $class = Callback::class; + } elseif (isset($route->file)) { + $class = PhpScript::class; + } else { + throw new \InvalidArgumentException("Route has neither 'controller', 'fn' or 'file' defined"); + } + + return new $class(); + } +} + diff --git a/tests/Router/Runner/CallbackTest.php b/tests/Router/Runner/CallbackTest.php index b4ee4ef..8a31794 100644 --- a/tests/Router/Runner/CallbackTest.php +++ b/tests/Router/Runner/CallbackTest.php @@ -15,12 +15,12 @@ class CallbackTest extends PHPUnit_Framework_TestCase * @param boolean $positive */ public function testCallback($route, $positive) - { + { $runner = new Callback($route); - $this->assertEquals($route, $runner->getRoute(), "Route was not set correctly"); $request = $this->createMock(ServerRequestInterface::class); $response = $this->createMock(ResponseInterface::class); + $request->expects($this->once())->method('getAttribute')->with($this->equalTo('route'))->will($this->returnValue($route)); if (!$positive) $this->expectException(\RuntimeException::class); $result = $runner->run($request, $response); diff --git a/tests/Router/Runner/ControllerTest.php b/tests/Router/Runner/ControllerTest.php index 1d64622..433d36d 100644 --- a/tests/Router/Runner/ControllerTest.php +++ b/tests/Router/Runner/ControllerTest.php @@ -23,10 +23,10 @@ class ControllerTest extends PHPUnit_Framework_TestCase public function testPhpScript($route, $positive) { $runner = new Controller($route); - $this->assertEquals($route, $runner->getRoute(), "Route was not set correctly"); $request = $this->createMock(ServerRequestInterface::class); $response = $this->createMock(ResponseInterface::class); + $request->expects($this->once())->method('getAttribute')->with($this->equalTo('route'))->will($this->returnValue($route)); if (!$positive) $this->expectException(\RuntimeException::class); $result = $runner->run($request, $response); diff --git a/tests/Router/Runner/PhpScriptTest.php b/tests/Router/Runner/PhpScriptTest.php index 12b9219..2f31f73 100644 --- a/tests/Router/Runner/PhpScriptTest.php +++ b/tests/Router/Runner/PhpScriptTest.php @@ -17,18 +17,14 @@ class PhpScriptTest extends PHPUnit_Framework_TestCase public function testPhpScript($route, $positive) { $runner = new PhpScript($route); - $this->assertEquals($route, $runner->getRoute(), "Route was not set correctly"); $request = $this->createMock(ServerRequestInterface::class); $response = $this->createMock(ResponseInterface::class); + $request->expects($this->once())->method('getAttribute')->with($this->equalTo('route'))->will($this->returnValue($route)); if (!$positive) $this->expectException(\RuntimeException::class); $result = $runner->run($request, $response); - if (!$positive) return; - - $this->assertEquals($runner->getRoute()->file, (string)$runner); - if ($route->type === 'returnTrue') { $this->assertEquals($response, $result, "Request object was not returned as result"); } else { diff --git a/tests/Router/Runner/RunnerFactoryTest.php b/tests/Router/Runner/RunnerFactoryTest.php new file mode 100644 index 0000000..c18656d --- /dev/null +++ b/tests/Router/Runner/RunnerFactoryTest.php @@ -0,0 +1,41 @@ +<?php + +use Jasny\Router\Route; +use Jasny\Router\Runner\RunnerFactory; +use Jasny\Router\Runner\Controller; +use Jasny\Router\Runner\Callback; +use Jasny\Router\Runner\PhpScript; + +class RunnerFactoryTest extends PHPUnit_Framework_TestCase +{ + /** + * Test creating Runner object using factory + * + * @dataProvider createProvider + * @param Route $route + * @param string $class Runner class to use + * @param boolean $positive + */ + public function testCreate($route, $class, $positive) + { + if (!$positive) $this->expectException(\InvalidArgumentException::class); + + $factory = new RunnerFactory(); + $runner = $factory($route); + + $this->assertInstanceOf($class, $runner, "Runner object has invalid class"); + } + + /** + * Provide data fpr testing 'create' method + */ + public function createProvider() + { + return [ + [Route::create(['controller' => 'TestController', 'value' => 'test']), Controller::class, true], + [Route::create(['fn' => 'testFunction', 'value' => 'test']), Callback::class, true], + [Route::create(['file' => 'some_file.php', 'value' => 'test']), PhpScript::class, true], + [Route::create(['test' => 'test']), '', false], + ]; + } +} diff --git a/tests/Router/RunnerTest.php b/tests/Router/RunnerTest.php index 60b80b9..7db4c02 100644 --- a/tests/Router/RunnerTest.php +++ b/tests/Router/RunnerTest.php @@ -11,44 +11,11 @@ use Psr\Http\Message\ResponseInterface; class RunnerTest extends PHPUnit_Framework_TestCase { /** - * Test creating Runner object using factory method - * - * @dataProvider createProvider - * @param Route $route - * @param string $class Runner class to use - * @param boolean $positive - */ - public function testCreate($route, $class, $positive) - { - if (!$positive) $this->expectException(\RuntimeException::class); - - $runner = Runner::create($route); - - if (!$positive) return; - - $this->assertInstanceOf($class, $runner, "Runner object has invalid class"); - $this->assertEquals($route, $runner->getRoute(), "Route was not set correctly"); - } - - /** - * Provide data fpr testing 'create' method - */ - public function createProvider() - { - return [ - [Route::create(['controller' => 'TestController', 'value' => 'test']), Controller::class, true], - [Route::create(['fn' => 'testFunction', 'value' => 'test']), Callback::class, true], - [Route::create(['file' => 'some_file.php', 'value' => 'test']), PhpScript::class, true], - [Route::create(['test' => 'test']), '', false], - ]; - } - - /** * Test runner __invoke method */ public function testInvoke() { - $runner = $this->getMockBuilder('Jasny\Router\Runner')->disableOriginalConstructor()->getMockForAbstractClass(); + $runner = $this->getMockBuilder(Runner::class)->disableOriginalConstructor()->getMockForAbstractClass(); $queries = [ 'request' => $this->createMock(ServerRequestInterface::class), 'response' => $this->createMock(ResponseInterface::class) diff --git a/tests/RouterTest.php b/tests/RouterTest.php index 9b63360..c5be4e2 100644 --- a/tests/RouterTest.php +++ b/tests/RouterTest.php @@ -2,6 +2,7 @@ use Jasny\Router; use Jasny\Router\Route; +use Jasny\Router\Runner\RunnerFactory; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; @@ -53,6 +54,8 @@ class RouterTest extends PHPUnit_Framework_TestCase ]; list($request, $response) = $this->getRequests(); + $this->expectRequestRoute($request, $routes['/foo']); + $router = new Router($routes); $result = $router($request, $response); @@ -73,6 +76,8 @@ class RouterTest extends PHPUnit_Framework_TestCase ]; list($request, $response) = $this->getRequests(); + $this->expectRequestRoute($request, $routes['/foo']); + $router = new Router($routes); $result = $router($request, $response, function($arg1, $arg2) { return ['request' => $arg1, 'response' => $arg2]; @@ -154,6 +159,8 @@ class RouterTest extends PHPUnit_Framework_TestCase ]; list($request, $response) = $this->getRequests(); + $this->expectRequestRoute($request, $routes['/foo']); + $router = new Router($routes); $router->add([$this, 'getMiddlewareCalledLast'])->add([$this, 'getMiddlewareCalledFirst']); @@ -166,6 +173,28 @@ class RouterTest extends PHPUnit_Framework_TestCase } /** + * Test getting and setting runner factory + */ + public function testRunnerFactory() + { + $router = new Router([]); + $factory = $router->getFactory(); + + $this->assertEquals(RunnerFactory::class, get_class($factory), "By default 'getFactory' should return 'RunnerFactory' instance, not " . get_class($factory)); + + $self = $router->setFactory(function() { + return 'test'; + }); + $factory = $router->getFactory(); + + $this->assertEquals($router, $self, "'setFactory' must return an instance of router"); + $this->assertEquals('test', $factory(), "Factory was not set or got correctly"); + + $this->expectException(\InvalidArgumentException::class); + $router->setFactory('test'); + } + + /** * Get requests for testing * * @return array @@ -224,4 +253,15 @@ class RouterTest extends PHPUnit_Framework_TestCase $response->expects($this->once())->method('withBody')->with($this->equalTo($stream))->will($this->returnSelf()); $response->expects($this->once())->method('withStatus')->with($this->equalTo(404), $this->equalTo('Not Found'))->will($this->returnSelf()); } + + /** + * Expect that request will return given route + * + * @param ServerRequestInterface $request + * @param Route $route + */ + public function expectRequestRoute(ServerRequestInterface $request, $route) + { + $request->expects($this->once())->method('getAttribute')->with($this->equalTo('route'))->will($this->returnValue($route)); + } } |