diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c3c6e..e6ff59b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 5.1.0 - TBD +## 5.1.0 - 2018-06-05 ### Added @@ -10,7 +10,13 @@ All notable changes to this project will be documented in this file, in reverse ### Changed -- Nothing. +- [#62](https://github.com/zendframework/zend-expressive-helpers/pull/62) modifies the `UrlHelperFactory` to allow specifying both a string `$basePath` as well as a string `$routerServiceName` + to its constructor. This change allows having discrete factory instances for generating helpers + that use different router instances and/or which operate under path-segregated middleware. + +- [#62](https://github.com/zendframework/zend-expressive-helpers/pull/62) modifies the `UrlHelperMiddlewareFactory` to allow specifying a string `$urlHelperServiceName` to its constructor. + This change allows having discrete factory instances for generating URL helper middleware + that use different URL helper instances. ### Deprecated diff --git a/src/UrlHelperFactory.php b/src/UrlHelperFactory.php index 2d17c16..f40c0a5 100644 --- a/src/UrlHelperFactory.php +++ b/src/UrlHelperFactory.php @@ -16,6 +16,34 @@ class UrlHelperFactory { + /** @var string Base path for the URL helper */ + private $basePath; + + /** @var string $routerServiceName */ + private $routerServiceName; + + /** + * Allow serialization + */ + public static function __set_state(array $data) : self + { + return new self( + $data['basePath'] ?? '/', + $data['routerServiceName'] ?? RouterInterface::class + ); + } + + /** + * Allows varying behavior per-instance. + * + * Defaults to '/' for the base path, and the FQCN of the RouterInterface. + */ + public function __construct(string $basePath = '/', string $routerServiceName = RouterInterface::class) + { + $this->basePath = $basePath; + $this->routerServiceName = $routerServiceName; + } + /** * Create a UrlHelper instance. * @@ -23,14 +51,16 @@ class UrlHelperFactory */ public function __invoke(ContainerInterface $container) : UrlHelper { - if (! $container->has(RouterInterface::class)) { + if (! $container->has($this->routerServiceName)) { throw new Exception\MissingRouterException(sprintf( '%s requires a %s implementation; none found in container', UrlHelper::class, - RouterInterface::class + $this->routerServiceName )); } - return new UrlHelper($container->get(RouterInterface::class)); + $helper = new UrlHelper($container->get($this->routerServiceName)); + $helper->setBasePath($this->basePath); + return $helper; } } diff --git a/src/UrlHelperMiddlewareFactory.php b/src/UrlHelperMiddlewareFactory.php index 334ebe2..56f75bf 100644 --- a/src/UrlHelperMiddlewareFactory.php +++ b/src/UrlHelperMiddlewareFactory.php @@ -15,6 +15,27 @@ class UrlHelperMiddlewareFactory { + /** @var string */ + private $urlHelperServiceName; + + /** + * Allow serialization + */ + public static function __set_state(array $data) : self + { + return new self( + $data['urlHelperServiceName'] ?? UrlHelper::class + ); + } + + /** + * Allow varying behavior based on URL helper service name. + */ + public function __construct(string $urlHelperServiceName = UrlHelper::class) + { + $this->urlHelperServiceName = $urlHelperServiceName; + } + /** * Create and return a UrlHelperMiddleware instance. * @@ -23,14 +44,14 @@ class UrlHelperMiddlewareFactory */ public function __invoke(ContainerInterface $container) : UrlHelperMiddleware { - if (! $container->has(UrlHelper::class)) { + if (! $container->has($this->urlHelperServiceName)) { throw new Exception\MissingHelperException(sprintf( '%s requires a %s service at instantiation; none found', UrlHelperMiddleware::class, - UrlHelper::class + $this->urlHelperServiceName )); } - return new UrlHelperMiddleware($container->get(UrlHelper::class)); + return new UrlHelperMiddleware($container->get($this->urlHelperServiceName)); } } diff --git a/test/UrlHelperFactoryTest.php b/test/UrlHelperFactoryTest.php index 6f40856..6d1c780 100644 --- a/test/UrlHelperFactoryTest.php +++ b/test/UrlHelperFactoryTest.php @@ -55,6 +55,15 @@ public function testFactoryReturnsHelperWithRouterInjected() $helper = $this->factory->__invoke($this->container->reveal()); $this->assertInstanceOf(UrlHelper::class, $helper); $this->assertAttributeSame($this->router->reveal(), 'router', $helper); + return $helper; + } + + /** + * @depends testFactoryReturnsHelperWithRouterInjected + */ + public function testHelperUsesDefaultBasePathWhenNoneProvidedAtInstantiation(UrlHelper $helper) + { + $this->assertEquals('/', $helper->getBasePath()); } public function testFactoryRaisesExceptionWhenRouterIsNotPresentInContainer() @@ -62,4 +71,28 @@ public function testFactoryRaisesExceptionWhenRouterIsNotPresentInContainer() $this->expectException(MissingRouterException::class); $this->factory->__invoke($this->container->reveal()); } + + public function testFactoryUsesBasePathAndRouterServiceProvidedAtInstantiation() + { + $this->injectContainerService(Router::class, $this->router->reveal()); + $factory = new UrlHelperFactory('/api', Router::class); + + $helper = $factory($this->container->reveal()); + + $this->assertInstanceOf(UrlHelper::class, $helper); + $this->assertAttributeSame($this->router->reveal(), 'router', $helper); + $this->assertEquals('/api', $helper->getBasePath()); + } + + public function testFactoryAllowsSerialization() + { + $factory = UrlHelperFactory::__set_state([ + 'basePath' => '/api', + 'routerServiceName' => Router::class, + ]); + + $this->assertInstanceOf(UrlHelperFactory::class, $factory); + $this->assertAttributeSame('/api', 'basePath', $factory); + $this->assertAttributeSame(Router::class, 'routerServiceName', $factory); + } } diff --git a/test/UrlHelperMiddlewareFactoryTest.php b/test/UrlHelperMiddlewareFactoryTest.php index da75df9..7b70598 100644 --- a/test/UrlHelperMiddlewareFactoryTest.php +++ b/test/UrlHelperMiddlewareFactoryTest.php @@ -54,4 +54,26 @@ public function testFactoryRaisesExceptionWhenContainerDoesNotContainHelper() $this->expectException(MissingHelperException::class); $factory($this->container->reveal()); } + + public function testFactoryUsesUrlHelperServiceProvidedAtInstantiation() + { + $helper = $this->prophesize(UrlHelper::class)->reveal(); + $this->injectContainer(MyUrlHelper::class, $helper); + $factory = new UrlHelperMiddlewareFactory(MyUrlHelper::class); + + $middleware = $factory($this->container->reveal()); + + $this->assertInstanceOf(UrlHelperMiddleware::class, $middleware); + $this->assertAttributeSame($helper, 'helper', $middleware); + } + + public function testFactoryAllowsSerialization() + { + $factory = UrlHelperMiddlewareFactory::__set_state([ + 'urlHelperServiceName' => MyUrlHelper::class, + ]); + + $this->assertInstanceOf(UrlHelperMiddlewareFactory::class, $factory); + $this->assertAttributeSame(MyUrlHelper::class, 'urlHelperServiceName', $factory); + } }