summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnold Daniels <arnold@jasny.net>2016-10-18 19:33:59 +0200
committerGitHub <noreply@github.com>2016-10-18 19:33:59 +0200
commit08b0a5385f5d58f73f33514f0a4b0f2985d042c7 (patch)
tree653bb82d201fcdc5613b1fc605152af30d403d44
parentc3b3a87d0b693a191b385bbbc44a857d52879afa (diff)
parent7a4362d4f5961daa21bfcec57e27220a77dc6bc4 (diff)
downloadrouter-08b0a5385f5d58f73f33514f0a4b0f2985d042c7.zip
router-08b0a5385f5d58f73f33514f0a4b0f2985d042c7.tar.gz
router-08b0a5385f5d58f73f33514f0a4b0f2985d042c7.tar.bz2
Merge pull request #12 from Minstel/Add_the_route_as_ServerRequest_attribute
Add the route as ServerRequest attribute
-rw-r--r--src/Router.php43
-rw-r--r--src/Router/Runner.php49
-rw-r--r--src/Router/Runner/Callback.php3
-rw-r--r--src/Router/Runner/Controller.php5
-rw-r--r--src/Router/Runner/PhpScript.php15
-rw-r--r--src/Router/Runner/RunnerFactory.php33
-rw-r--r--tests/Router/Runner/CallbackTest.php4
-rw-r--r--tests/Router/Runner/ControllerTest.php2
-rw-r--r--tests/Router/Runner/PhpScriptTest.php6
-rw-r--r--tests/Router/Runner/RunnerFactoryTest.php41
-rw-r--r--tests/Router/RunnerTest.php35
-rw-r--r--tests/RouterTest.php40
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));
+ }
}