summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnold Daniels <arnold@jasny.net>2016-10-12 21:25:44 +0200
committerGitHub <noreply@github.com>2016-10-12 21:25:44 +0200
commit2943ae006845288475caf271a81db1e8bff4c0cb (patch)
tree91b3a426fa45f5542753a9758d35851758183796
parent2f69176c84865f372c4c50de271ab743067951be (diff)
parentf9df2a343453c80ac982cb46af60c7b40ace74fc (diff)
downloadrouter-2943ae006845288475caf271a81db1e8bff4c0cb.zip
router-2943ae006845288475caf271a81db1e8bff4c0cb.tar.gz
router-2943ae006845288475caf271a81db1e8bff4c0cb.tar.bz2
Merge pull request #5 from Minstel/router-cleanup
Implementation and tests for Router. Minor fixes
-rw-r--r--src/Router.php121
-rw-r--r--src/Router/Routes.php10
-rw-r--r--src/Router/Runner.php10
-rw-r--r--src/Router/Runner/Callback.php6
-rw-r--r--src/Router/Runner/Controller.php20
-rw-r--r--src/Router/Runner/PhpScript.php8
-rw-r--r--tests/Router/Runner/CallbackTest.php6
-rw-r--r--tests/Router/Runner/ControllerTest.php140
-rw-r--r--tests/Router/Runner/PhpScriptTest.php4
-rw-r--r--tests/Router/RunnerTest.php4
-rw-r--r--tests/RouterTest.php227
11 files changed, 502 insertions, 54 deletions
diff --git a/src/Router.php b/src/Router.php
index e0f3acb..955e1e1 100644
--- a/src/Router.php
+++ b/src/Router.php
@@ -2,9 +2,10 @@
namespace Jasny;
-use Jasny\Router\Routes;
-use Psr7\Http\Message\ServerRequest;
-use Psr7\Http\Message\Response;
+use Jasny\Router\Runner;
+use Jasny\Router\Routes\Glob;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\ResponseInterface;
/**
* Route pretty URLs to correct controller
@@ -13,17 +14,22 @@ class Router
{
/**
* Specific routes
- * @var Routes
+ * @var array
*/
- protected $routes;
-
+ protected $routes = [];
+
+ /**
+ * Middlewares actions
+ * @var array
+ **/
+ protected $middlewares = [];
/**
* Class constructor
*
- * @param Routes $routes
+ * @param array $routes
*/
- public function __construct(Routes $routes)
+ public function __construct(array $routes)
{
$this->routes = $routes;
}
@@ -36,46 +42,109 @@ class Router
public function getRoutes()
{
return $this->routes;
+ }
+
+ /**
+ * Get middlewares
+ *
+ * @return array
+ */
+ public function getMiddlewares()
+ {
+ return $this->middlewares;
+ }
+
+ /**
+ * Add middleware call to router
+ *
+ * @param callback $middleware
+ * @return Router $this
+ */
+ public function add($middleware)
+ {
+ if (!is_callable($middleware)) {
+ throw new \InvalidArgumentException("Middleware should be a callable");
+ }
+
+ $this->middlewares[] = $middleware;
+
+ return $this;
}
-
/**
* Run the action for the request
*
- * @param ServerRequest $request
- * @param Response $response
- * @return Response
+ * @param ServerRequestInterface $request
+ * @param ResponseInterface $response
+ * @return ResponseInterface
*/
- final public function run(ServerRequest $request, Response $response)
+ final public function run(ServerRequestInterface $request, ResponseInterface $response)
{
return $this->__invoke($request, $response);
}
/**
- * Run the action for the request (optionally as middleware)
+ * Run the action for the request (optionally as middleware), previously running middlewares, if any
*
- * @param ServerRequest $request
- * @param Response $response
- * @param callback $next
- * @return Response
+ * @param ServerRequestInterface $request
+ * @param ResponseInterface $response
+ * @param callback $next
+ * @return ResponseInterface
*/
- public function __invoke(ServerRequest $request, Response $response, $next = null)
+ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next = null)
{
- return $this->handle($request, $response, $next);
+ $handle = [$this, 'handle'];
+
+ #Call to $this->handle will be executed last in the chain of middlewares
+ $next = function(ServerRequestInterface $request, ResponseInterface $response) use ($next, $handle) {
+ return call_user_func($handle, $request, $response, $next);
+ };
+
+ #Build middlewares call chain, so that the last added was executed in first place
+ foreach ($this->middlewares as $middleware) {
+ $next = function(ServerRequestInterface $request, ResponseInterface $response) use ($next, $middleware) {
+ return $middleware($request, $response, $next);
+ };
+ }
+
+ return $next($request, $response);
}
/**
* Run the action
*
- * @param ServerRequest $request
- * @param Response $response
+ * @param ServerRequestInterface $request
+ * @param ResponseInterface $response
* @param callback $next
- * @return Response
+ * @return ResponseInterface
*/
- protected function handle(ServerRequest $request, Response $response, $next = null)
+ protected function handle(ServerRequestInterface $request, ResponseInterface $response, $next = null)
{
- // TODO find route and run.
- // TODO if not found -> 404
+ $glob = new Glob($this->routes);
+ $route = $glob->getRoute($request);
+
+ if (!$route) return $this->notFound($response);
+
+ $runner = Runner::create($route);
+
+ return $runner($request, $response, $next);
+ }
+
+ /**
+ * Return 'Not Found' response
+ *
+ * @param ResponseInterface $response
+ * @return ResponseInterface
+ */
+ protected function notFound(ResponseInterface $response)
+ {
+ $message = 'Not Found';
+
+ $body = $response->getBody();
+ $body->rewind();
+ $body->write($message);
+
+ return $response->withStatus(404, $message)->withBody($body);
}
}
diff --git a/src/Router/Routes.php b/src/Router/Routes.php
index 26d407c..ce4fa1a 100644
--- a/src/Router/Routes.php
+++ b/src/Router/Routes.php
@@ -2,7 +2,7 @@
namespace Jasny\Router;
-use Psr\Http\Message\ServerRequestInterface as ServerRequest;
+use Psr\Http\Message\ServerRequestInterface;
/**
* Collection of routes
@@ -12,16 +12,16 @@ interface Routes
/**
* Check if a route for the request exists
*
- * @param ServerRequest $request
+ * @param ServerRequestInterface $request
* @return boolean
*/
- public function hasRoute(ServerRequest $request);
+ public function hasRoute(ServerRequestInterface $request);
/**
* Get route for the request
*
- * @param ServerRequest $request
+ * @param ServerRequestInterface $request
* @return Route
*/
- public function getRoute(ServerRequest $request);
+ public function getRoute(ServerRequestInterface $request);
}
diff --git a/src/Router/Runner.php b/src/Router/Runner.php
index 2c8d259..51300a4 100644
--- a/src/Router/Runner.php
+++ b/src/Router/Runner.php
@@ -2,7 +2,7 @@
namespace Jasny\Router;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Jasny\Router\Route;
@@ -39,21 +39,21 @@ abstract class Runner
/**
* Invoke the action specified in the route
*
- * @param RequestInterface $request
+ * @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
- abstract public function run(RequestInterface $request, ResponseInterface $response);
+ abstract public function run(ServerRequestInterface $request, ResponseInterface $response);
/**
* Invoke the action specified in the route and call the next method
*
- * @param RequestInterface $request
+ * @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param callback $next Callback for if runner is used as middleware
* @return ResponseInterface
*/
- public function __invoke(RequestInterface $request, ResponseInterface $response, $next = null)
+ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next = null)
{
$response = $this->run($request, $response);
diff --git a/src/Router/Runner/Callback.php b/src/Router/Runner/Callback.php
index cf1063b..34ebc4c 100644
--- a/src/Router/Runner/Callback.php
+++ b/src/Router/Runner/Callback.php
@@ -3,7 +3,7 @@
namespace Jasny\Router\Runner;
use Jasny\Router\Runner;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
@@ -16,11 +16,11 @@ class Callback extends Runner
/**
* Use function to handle request and response
*
- * @param RequestInterface $request
+ * @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface|mixed
*/
- public function run(RequestInterface $request, ResponseInterface $response)
+ public function run(ServerRequestInterface $request, ResponseInterface $response)
{
$callback = !empty($this->route->fn) ? $this->route->fn : null;
diff --git a/src/Router/Runner/Controller.php b/src/Router/Runner/Controller.php
index ed8c060..0488be5 100644
--- a/src/Router/Runner/Controller.php
+++ b/src/Router/Runner/Controller.php
@@ -3,7 +3,7 @@
namespace Jasny\Router\Runner;
use Jasny\Router\Runner;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
@@ -14,14 +14,26 @@ use Psr\Http\Message\ResponseInterface;
class Controller extends Runner
{
/**
- * Route to a file
+ * Route to a controller
*
- * @param RequestInterface $request
+ * @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface|mixed
*/
- public function run(RequestInterface $request, ResponseInterface $response)
+ public function run(ServerRequestInterface $request, ResponseInterface $response)
{
+ $class = !empty($this->route->controller) ? $this->route->controller : null;
+ if (!class_exists($class)) {
+ throw new \RuntimeException("Can not route to controller '$class': class not exists");
+ }
+
+ if (!method_exists($class, '__invoke')) {
+ throw new \RuntimeException("Can not route to controller '$class': class does not have '__invoke' method");
+ }
+
+ $controller = new $class($this->route);
+
+ return $controller($request, $response);
}
}
diff --git a/src/Router/Runner/PhpScript.php b/src/Router/Runner/PhpScript.php
index 43e4934..f6595a3 100644
--- a/src/Router/Runner/PhpScript.php
+++ b/src/Router/Runner/PhpScript.php
@@ -3,7 +3,7 @@
namespace Jasny\Router\Runner;
use Jasny\Router\Runner;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
@@ -24,11 +24,11 @@ class PhpScript extends Runner
/**
* Route to a file
*
- * @param RequestInterface $request
- * @param ResponseInterface $response
+ * @param ServerRequestInterface $request
+ * @param ResponseInterface $response
* @return ResponseInterface|mixed
*/
- public function run(RequestInterface $request, ResponseInterface $response)
+ public function run(ServerRequestInterface $request, ResponseInterface $response)
{
$file = !empty($this->route->file) ? ltrim($this->route->file, '/') : '';
diff --git a/tests/Router/Runner/CallbackTest.php b/tests/Router/Runner/CallbackTest.php
index 04bbd27..b4ee4ef 100644
--- a/tests/Router/Runner/CallbackTest.php
+++ b/tests/Router/Runner/CallbackTest.php
@@ -2,7 +2,7 @@
use Jasny\Router\Route;
use Jasny\Router\Runner\Callback;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class CallbackTest extends PHPUnit_Framework_TestCase
@@ -19,7 +19,7 @@ class CallbackTest extends PHPUnit_Framework_TestCase
$runner = new Callback($route);
$this->assertEquals($route, $runner->getRoute(), "Route was not set correctly");
- $request = $this->createMock(RequestInterface::class);
+ $request = $this->createMock(ServerRequestInterface::class);
$response = $this->createMock(ResponseInterface::class);
if (!$positive) $this->expectException(\RuntimeException::class);
@@ -53,7 +53,7 @@ class CallbackTest extends PHPUnit_Framework_TestCase
/**
* Testable callback for creating Route
*
- * @param RequestInterface $request
+ * @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return array
*/
diff --git a/tests/Router/Runner/ControllerTest.php b/tests/Router/Runner/ControllerTest.php
new file mode 100644
index 0000000..1d64622
--- /dev/null
+++ b/tests/Router/Runner/ControllerTest.php
@@ -0,0 +1,140 @@
+<?php
+
+use Jasny\Router\Route;
+use Jasny\Router\Runner\Controller;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+class ControllerTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * Tmp scripts
+ * @var array
+ **/
+ public static $files = [];
+
+ /**
+ * Test creating Controller runner
+ *
+ * @dataProvider phpScriptProvider
+ * @param Route $route
+ * @param boolean $positive
+ */
+ 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);
+
+ if (!$positive) $this->expectException(\RuntimeException::class);
+ $result = $runner->run($request, $response);
+
+ $this->assertEquals($request, $result['request'], "Request object was not passed correctly to result");
+ $this->assertEquals($response, $result['response'], "Response object was not passed correctly to result");
+ }
+
+ /**
+ * Provide data for testing 'create' method
+ */
+ public function phpScriptProvider()
+ {
+ foreach (['noInvoke', 'withInvoke'] as $type) {
+ list($class, $path) = static::createTmpScript($type);
+ static::$files[$type] = compact('class', 'path');
+ }
+
+ return [
+ [Route::create(['test' => 'test']), false],
+ [Route::create(['fn' => 'testFunction', 'value' => 'test']), false],
+ [Route::create(['controller' => 'TestController', 'value' => 'test']), false],
+ [Route::create(['controller' => '', 'value' => 'test']), false],
+ [Route::create(['controller' => static::$files['noInvoke']['class'], 'path' => static::$files['noInvoke']['path']]), false],
+ [Route::create(['controller' => static::$files['withInvoke']['class'], 'path' => static::$files['withInvoke']['path']]), true],
+ ];
+ }
+
+ /**
+ * Delete tmp test scripts
+ */
+ public static function tearDownAfterClass()
+ {
+ foreach (static::$files as $path) {
+ unlink($path['path']);
+ }
+ }
+
+ /**
+ * Create single tmp script file for testing
+ *
+ * @param string $type ('returnTrue', 'returnNotTrue')
+ * @return string $path
+ */
+ public static function createTmpScript($type)
+ {
+ $dir = rtrim(sys_get_temp_dir(), '/');
+
+ do {
+ $name = static::getRandomString() . '-test-script.php';
+ $path = $dir . '/' . $name;
+
+ if (!file_exists($path)) break;
+ } while (true);
+
+ if ($type === 'noInvoke') {
+ $class = 'RunnerTestConrtollerInvalid';
+ $content =
+<<<CONTENT
+<?php
+
+class $class {
+ public \$route = null;
+
+ public function __construct(\$route)
+ {
+ \$this->route = \$route;
+ }
+}
+CONTENT;
+ } else {
+ $class = 'RunnerTestConrtoller';
+ $content =
+<<<CONTENT
+<?php
+
+class $class {
+ public \$route = null;
+
+ public function __construct(\$route)
+ {
+ \$this->route = \$route;
+ }
+
+ public function __invoke(Psr\Http\Message\ServerRequestInterface \$request, Psr\Http\Message\ResponseInterface \$response)
+ {
+ return ['request' => \$request, 'response' => \$response];
+ }
+}
+CONTENT;
+ }
+
+ $bytes = file_put_contents($path, $content);
+ static::assertTrue((int)$bytes > 0);
+
+ require_once $path;
+
+ return [$class, $path];
+ }
+
+ /**
+ * Get random string of given length (no more then length of md5 hash)
+ *
+ * @param int $length
+ * @return string
+ */
+ public static function getRandomString($length = 10)
+ {
+ return substr(md5(microtime(true) * mt_rand()), 0, $length);
+ }
+}
diff --git a/tests/Router/Runner/PhpScriptTest.php b/tests/Router/Runner/PhpScriptTest.php
index a7cb4e1..12b9219 100644
--- a/tests/Router/Runner/PhpScriptTest.php
+++ b/tests/Router/Runner/PhpScriptTest.php
@@ -2,7 +2,7 @@
use Jasny\Router\Route;
use Jasny\Router\Runner\PhpScript;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class PhpScriptTest extends PHPUnit_Framework_TestCase
@@ -19,7 +19,7 @@ class PhpScriptTest extends PHPUnit_Framework_TestCase
$runner = new PhpScript($route);
$this->assertEquals($route, $runner->getRoute(), "Route was not set correctly");
- $request = $this->createMock(RequestInterface::class);
+ $request = $this->createMock(ServerRequestInterface::class);
$response = $this->createMock(ResponseInterface::class);
if (!$positive) $this->expectException(\RuntimeException::class);
diff --git a/tests/Router/RunnerTest.php b/tests/Router/RunnerTest.php
index b6e2baf..60b80b9 100644
--- a/tests/Router/RunnerTest.php
+++ b/tests/Router/RunnerTest.php
@@ -5,7 +5,7 @@ use Jasny\Router\Runner;
use Jasny\Router\Runner\Controller;
use Jasny\Router\Runner\Callback;
use Jasny\Router\Runner\PhpScript;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class RunnerTest extends PHPUnit_Framework_TestCase
@@ -50,7 +50,7 @@ class RunnerTest extends PHPUnit_Framework_TestCase
{
$runner = $this->getMockBuilder('Jasny\Router\Runner')->disableOriginalConstructor()->getMockForAbstractClass();
$queries = [
- 'request' => $this->createMock(RequestInterface::class),
+ 'request' => $this->createMock(ServerRequestInterface::class),
'response' => $this->createMock(ResponseInterface::class)
];
diff --git a/tests/RouterTest.php b/tests/RouterTest.php
new file mode 100644
index 0000000..9b63360
--- /dev/null
+++ b/tests/RouterTest.php
@@ -0,0 +1,227 @@
+<?php
+
+use Jasny\Router;
+use Jasny\Router\Route;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\StreamInterface;
+
+class RouterTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * Test creating Router
+ */
+ public function testConstruct()
+ {
+ $routes = [
+ '/foo' => ['fn' => 'test_function'],
+ '/foo/bar' => ['controller' => 'TestController']
+ ];
+
+ $router = new Router($routes);
+ $this->assertEquals($routes, $router->getRoutes(), "Routes were not set correctly");
+ }
+
+ /**
+ * Test that on router 'run', method '__invoke' is called
+ */
+ public function testRun()
+ {
+ $router = $this->createMock(Router::class, ['__invoke']);
+ list($request, $response) = $this->getRequests();
+
+ $router->method('__invoke')->will($this->returnCallback(function($arg1, $arg2) {
+ return ['request' => $arg1, 'response' => $arg2];
+ }));
+
+ $result = $router->run($request, $response);
+
+ $this->assertEquals($request, $result['request'], "Request was not processed correctly");
+ $this->assertEquals($response, $result['response'], "Response was not processed correctly");
+ }
+
+ /**
+ * Test '__invoke' method
+ */
+ public function testInvoke()
+ {
+ $routes = [
+ '/foo/bar' => Route::create(['controller' => 'TestController']),
+ '/foo' => Route::create(['fn' => function($arg1, $arg2) {
+ return ['request' => $arg1, 'response' => $arg2];
+ }])
+ ];
+
+ list($request, $response) = $this->getRequests();
+ $router = new Router($routes);
+ $result = $router($request, $response);
+
+ $this->assertEquals($request, $result['request'], "Request was not processed correctly");
+ $this->assertEquals($response, $result['response'], "Response was not processed correctly");
+ }
+
+ /**
+ * Test '__invoke' method with 'next' callback
+ */
+ public function testInvokeNext()
+ {
+ $routes = [
+ '/foo/bar' => Route::create(['controller' => 'TestController']),
+ '/foo' => Route::create(['fn' => function($request, $response) {
+ return $response;
+ }])
+ ];
+
+ list($request, $response) = $this->getRequests();
+ $router = new Router($routes);
+ $result = $router($request, $response, function($arg1, $arg2) {
+ return ['request' => $arg1, 'response' => $arg2];
+ });
+
+ $this->assertEquals($request, $result['request'], "Request was not processed correctly");
+ $this->assertEquals($response, $result['response'], "Response was not processed correctly");
+ }
+
+ /**
+ * Test case when route is not found
+ */
+ public function testNotFound()
+ {
+ $routes = [
+ '/foo/bar' => Route::create(['controller' => 'TestController'])
+ ];
+
+ list($request, $response) = $this->getRequests();
+ $this->expectNotFound($response);
+
+ $router = new Router($routes);
+ $result = $router($request, $response);
+
+ $this->assertEquals(get_class($response), get_class($result), "Returned result is not an instance of 'ServerRequestInterface'");
+ }
+
+ /**
+ * Test adding middleware action
+ *
+ * @dataProvider addProvider
+ * @param mixed $middleware1
+ * @param callable $middleware2
+ * @param boolean $positive
+ */
+ public function testAdd($middleware1, $middleware2, $positive)
+ {
+ $router = new Router([]);
+ $this->assertEquals(0, count($router->getMiddlewares()), "Middlewares array should be empty");
+
+ if (!$positive) $this->expectException(\InvalidArgumentException::class);
+
+ $result = $router->add($middleware1);
+ $this->assertEquals(1, count($router->getMiddlewares()), "There should be only one item in middlewares array");
+ $this->assertEquals($middleware1, reset($router->getMiddlewares()), "Wrong item in middlewares array");
+ $this->assertEquals($router, $result, "'Add' should return '\$this'");
+
+ if (!$middleware2) return;
+
+ $router->add($middleware2);
+ $this->assertEquals(2, count($router->getMiddlewares()), "There should be two items in middlewares array");
+ foreach ($router->getMiddlewares() as $action) {
+ $this->assertTrue($action == $middleware1 || $action == $middleware2, "Wrong item in middlewares array");
+ }
+ }
+
+ /**
+ * Provide data for testing 'add' method
+ */
+ public function addProvider()
+ {
+ return [
+ ['wrong_callback', null, false],
+ [[$this, 'getMiddlewareCalledFirst'], null, true],
+ [[$this, 'getMiddlewareCalledFirst'], [$this, 'getMiddlewareCalledLast'], true]
+ ];
+ }
+
+ /**
+ * Test executing router with middlewares chain (test only execution order)
+ */
+ public function testRunMiddlewares()
+ {
+ $routes = [
+ '/foo' => Route::create(['fn' => function($request, $response) {
+ $response->testMiddlewareCalls[] = 'handle';
+ return $response;
+ }])
+ ];
+
+ list($request, $response) = $this->getRequests();
+ $router = new Router($routes);
+ $router->add([$this, 'getMiddlewareCalledLast'])->add([$this, 'getMiddlewareCalledFirst']);
+
+ $result = $router($request, $response, function($request, $response) {
+ $response->testMiddlewareCalls[] = 'outer';
+ return $response;
+ });
+
+ $this->assertEquals(['first','last','handle','outer'], $response->testMiddlewareCalls, "Actions were executed in wrong order");
+ }
+
+ /**
+ * Get requests for testing
+ *
+ * @return array
+ */
+ public function getRequests()
+ {
+ $request = $this->createMock(ServerRequestInterface::class);
+ $response = $this->createMock(ResponseInterface::class);
+
+ $request->method('getUri')->will($this->returnValue('/foo'));
+ $request->method('getMethod')->will($this->returnValue('GET'));
+
+ return [$request, $response];
+ }
+
+ /**
+ * Get middleware action, that should ba called first in middleware chain
+ *
+ * @param ServerRequestInterface $request
+ * @param ResponseInterface $response
+ * @param callback $next
+ * @return ResponseInterface
+ */
+ public function getMiddlewareCalledFirst(ServerRequestInterface $request, ResponseInterface $response, $next)
+ {
+ $response->testMiddlewareCalls[] = 'first';
+ return $next($request, $response);
+ }
+
+ /**
+ * Get middleware action, that should be called last in middleware chain
+ *
+ * @param ServerRequestInterface $request
+ * @param ResponseInterface $response
+ * @param callback $next
+ * @return ResponseInterface
+ */
+ public function getMiddlewareCalledLast(ServerRequestInterface $request, ResponseInterface $response, $next)
+ {
+ $response->testMiddlewareCalls[] = 'last';
+ return $next($request, $response);
+ }
+
+ /**
+ * Expect 'not found' response
+ *
+ * @param ResponseInterface
+ */
+ public function expectNotFound(ResponseInterface $response)
+ {
+ $stream = $this->createMock(StreamInterface::class);
+ $stream->expects($this->once())->method('rewind');
+ $stream->expects($this->once())->method('write')->with($this->equalTo('Not Found'));
+
+ $response->method('getBody')->will($this->returnValue($stream));
+ $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());
+ }
+}