Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

Allow varying UrlHelper for path-segregated middleware #62

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@

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

- Nothing.

### 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

Expand Down
36 changes: 33 additions & 3 deletions src/UrlHelperFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,51 @@

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.
*
* @throws Exception\MissingRouterException
*/
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;
}
}
27 changes: 24 additions & 3 deletions src/UrlHelperMiddlewareFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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));
}
}
33 changes: 33 additions & 0 deletions test/UrlHelperFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,44 @@ 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()
{
$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);
}
}
22 changes: 22 additions & 0 deletions test/UrlHelperMiddlewareFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}