diff options
author | Arnold Daniels <arnold@jasny.net> | 2016-11-29 11:28:38 +0100 |
---|---|---|
committer | Arnold Daniels <arnold@jasny.net> | 2016-11-29 11:28:38 +0100 |
commit | fb4bba481c8ce95749ade5a162e566eb15e6d321 (patch) | |
tree | fc454e34b5dbd8bcdc476966a799fdebf7c39cd6 | |
parent | b2c47c1a0efe0af9a3c171060258d667ce47e2a8 (diff) | |
download | router-fb4bba481c8ce95749ade5a162e566eb15e6d321.zip router-fb4bba481c8ce95749ade5a162e566eb15e6d321.tar.gz router-fb4bba481c8ce95749ade5a162e566eb15e6d321.tar.bz2 |
Specify a path when adding middleware
-rw-r--r-- | src/Router.php | 46 | ||||
-rw-r--r-- | tests/Router/Runner/ControllerTest.php | 2 | ||||
-rw-r--r-- | tests/RouterTest.php | 62 |
3 files changed, 99 insertions, 11 deletions
diff --git a/src/Router.php b/src/Router.php index 5cc2108..1957f91 100644 --- a/src/Router.php +++ b/src/Router.php @@ -94,22 +94,60 @@ class Router } /** - * Add middleware call to router + * Add middleware call to router. * - * @param callback $middleware + * @param string $path Middleware is only applied for this path (including subdirectories), may be omitted + * @param callable $middleware * @return Router $this */ - public function add($middleware) + public function add($path, $middleware = null) { + if (!isset($middleware)) { + $middleware = $path; + $path = null; + } + + if (!empty($path) && !ctype_digit($path) && $path[0] !== '/') { + trigger_error("Middleware path '$path' doesn't start with a '/'", E_USER_NOTICE); + } + if (!is_callable($middleware)) { throw new \InvalidArgumentException("Middleware should be callable"); } + if (!empty($path)) { + $middleware = $this->wrapMiddleware($path, $middleware); + } + $this->middlewares[] = $middleware; - + return $this; } + /** + * Wrap middleware, so it's only applied to a specified path + * + * @param string $path + * @param callable $middleware + * @return callable + */ + protected function wrapMiddleware($path, $middleware) + { + return function( + ServerRequestInterface $request, + ResponseInterface $response, + $next + ) use ($middleware, $path) { + $uriPath = $request->getUri()->getPath(); + + if ($uriPath === $path || strpos($uriPath, rtrim($path, '/') . '/') === 0) { + return $middleware($request, $response, $next); + } else { + return $next($request, $response); + } + }; + } + /** * Run the action for the request diff --git a/tests/Router/Runner/ControllerTest.php b/tests/Router/Runner/ControllerTest.php index cd3e653..c1b1801 100644 --- a/tests/Router/Runner/ControllerTest.php +++ b/tests/Router/Runner/ControllerTest.php @@ -10,7 +10,7 @@ use Psr\Http\Message\ResponseInterface; use Jasny\Router\TestHelpers; /** - * @covers Jasny\Router\Runner\Controller; + * @covers Jasny\Router\Runner\Controller */ class ControllerTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/RouterTest.php b/tests/RouterTest.php index c036c71..3746574 100644 --- a/tests/RouterTest.php +++ b/tests/RouterTest.php @@ -1,6 +1,6 @@ <?php -namespace Jasny\Router; +namespace Jasny; use Jasny\Router; use Jasny\Router\Route; @@ -9,6 +9,7 @@ use Jasny\Router\RunnerFactory; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UriInterface; use Jasny\Router\TestHelpers; @@ -169,7 +170,7 @@ class RouterTest extends \PHPUnit_Framework_TestCase $this->assertSame([$middlewareOne, $middlewareTwo], $router->getMiddlewares()); } - + /** * @expectedException \InvalidArgumentException */ @@ -186,6 +187,9 @@ class RouterTest extends \PHPUnit_Framework_TestCase { $route = $this->createMock(Route::class); + $uri = $this->createMock(UriInterface::class); + $uri->method('getPath')->willReturn('/'); + $request = $this->createMock(ServerRequestInterface::class); $request->expects($this->once())->method('withAttribute')->with('route')->willReturn($request); $requestOne = $this->createMock(ServerRequestInterface::class); @@ -197,15 +201,15 @@ class RouterTest extends \PHPUnit_Framework_TestCase $finalResponse = $this->createMock(ResponseInterface::class); $middlewareOne = $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock(); - $middlewareOne->expects($this->once())->method('__invoke')->id('one') - ->with($request, $response, $this->isInstanceOf(Closure::class)) + $middlewareOne->expects($this->once())->method('__invoke') + ->with($request, $response, $this->isInstanceOf(\Closure::class)) ->will($this->returnCallback(function($a, $b, $next) use ($requestOne, $responseOne) { return $next($requestOne, $responseOne); })); $middlewareTwo = $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock(); - $middlewareTwo->expects($this->once())->method('__invoke')->id('two')->after('one') - ->with($request, $response, $this->isInstanceOf(Closure::class)) + $middlewareTwo->expects($this->once())->method('__invoke') + ->with($request, $response, $this->isInstanceOf(\Closure::class)) ->will($this->returnCallback(function($a, $b, $next) use ($requestTwo, $responseTwo) { return $next($requestTwo, $responseTwo); })); @@ -226,4 +230,50 @@ class RouterTest extends \PHPUnit_Framework_TestCase $this->assertSame($finalResponse, $result); } + + /** + * Test executing router with middlewares chain (test only execution order) + */ + public function testRunMiddlewaresByPath() + { + $route = $this->createMock(Route::class); + + $uri = $this->createMock(UriInterface::class); + $uri->method('getPath')->willReturn('/foo/bar'); + + $request = $this->createMock(ServerRequestInterface::class); + $request->expects($this->once())->method('withAttribute')->with('route')->willReturn($request); + $request->method('getUri')->willReturn($uri); + $requestOne = $this->createMock(ServerRequestInterface::class); + + $response = $this->createMock(ResponseInterface::class); + $responseOne = $this->createMock(ResponseInterface::class); + $finalResponse = $this->createMock(ResponseInterface::class); + + $middlewareOne = $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock(); + $middlewareOne->expects($this->once())->method('__invoke') + ->with($request, $response, $this->isInstanceOf(\Closure::class)) + ->will($this->returnCallback(function($a, $b, $next) use ($requestOne, $responseOne) { + return $next($requestOne, $responseOne); + })); + + $middlewareTwo = $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock(); + $middlewareTwo->expects($this->never())->method('__invoke'); + + $runner = $this->createCallbackMock($this->once(), [$requestOne, $responseOne], $finalResponse); + $factory = $this->createCallbackMock($this->once(), [$route], $runner); + + $routes = $this->createMock(Routes::class); + $routes->expects($this->once())->method('getRoute')->with($request)->willReturn($route); + + $router = new Router($routes); + $router->setFactory($factory); + + $router->add('/foo', $middlewareOne); + $router->add('/zoo', $middlewareTwo); + + $result = $router($request, $response); + + $this->assertSame($finalResponse, $result); + } } |