Skip to content

Commit

Permalink
#14 Provided ability to configure service-handlers with methods diffe…
Browse files Browse the repository at this point in the history
…rent from "__invoke"
  • Loading branch information
awd-studio committed Jun 10, 2020
1 parent b4dffe3 commit d6f0940
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 40 deletions.
7 changes: 4 additions & 3 deletions src/Bus/Handler/HandlerRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ interface HandlerRegistry extends HandlerLocator
/**
* Registers a handler from a PSR-container as a message handler.
*
* @param string $messageId
* @param string $handlerId
* @param string $messageId a message on which the handler subscribes on
* @param string $handlerId an ID of a service that represents a handler in a container
* @param string $handlerMethod the name of a method that handles a message
*
* @throws \AwdStudio\Bus\Exception\InvalidHandler
*
* @psalm-param class-string $messageId
* @phpstan-param class-string $messageId
*/
public function register(string $messageId, string $handlerId): void;
public function register(string $messageId, string $handlerId, string $handlerMethod = '__invoke'): void;
}
4 changes: 2 additions & 2 deletions src/Bus/Handler/ParentsAwareHandlerRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public function __construct(HandlerRegistry $handlers, ?ImplementationParser $pa
/**
* {@inheritdoc}
*/
public function register(string $messageId, string $handlerId): void
public function register(string $messageId, string $handlerId, string $handlerMethod = '__invoke'): void
{
$this->handlers->register($messageId, $handlerId);
$this->handlers->register($messageId, $handlerId, $handlerMethod);
}

/**
Expand Down
17 changes: 9 additions & 8 deletions src/Bus/Handler/PsrContainerHandlerRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ final class PsrContainerHandlerRegistry implements HandlerRegistry
/**
* @var array
*
* @psalm-var array<class-string, array<array-key, string>>
* @phpstan-var array<class-string, array<array-key, string>>
* @psalm-var array<class-string, array<string, string>>
* @phpstan-var array<class-string, array<string, string>>
*/
private $containerHandlers;

Expand All @@ -49,15 +49,15 @@ public function __construct(ContainerInterface $serviceLocator, ?HandlerLocator
/**
* {@inheritdoc}
*/
public function register(string $messageId, string $handlerId): void
public function register(string $messageId, string $handlerId, string $handlerMethod = '__invoke'): void
{
if (false === $this->serviceLocator->has($handlerId)) {
throw new InvalidHandler(
\sprintf('There is no registered services such a "%s" to handle a "%s" message', $handlerId, $messageId)
\sprintf('There is no a service such as "%s" to handle a "%s" message', $handlerId, $messageId)
);
}

$this->containerHandlers[$messageId][] = $handlerId;
$this->containerHandlers[$messageId][$handlerId] = $handlerMethod;
}

/**
Expand All @@ -73,7 +73,7 @@ public function add(string $messageId, callable $handler): void
*/
public function has(string $messageId): bool
{
return $this->dynamicHandlers->has($messageId) || !empty($this->containerHandlers[$messageId]);
return $this->dynamicHandlers->has($messageId) || false === empty($this->containerHandlers[$messageId]);
}

/**
Expand All @@ -88,8 +88,9 @@ public function get(string $messageId): \Iterator
}

if (false === empty($this->containerHandlers[$messageId])) {
foreach (\array_unique($this->containerHandlers[$messageId]) as $handlerId) {
yield $this->serviceLocator->get($handlerId);
foreach ($this->containerHandlers[$messageId] as $handlerId => $handlerMethod) {
$handler = $this->serviceLocator->get($handlerId);
yield '__invoke' === $handlerMethod ? $handler : [$handler, $handlerMethod];
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Bus/Handler/ParentsAwareHandlersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function testMustAllowNotToPassReflector(): void
public function testMustRegisterViaHandlers(): void
{
$this->handlersRegistryProphesy
->register(Argument::exact('Foo'), Argument::exact('FooHandler'))
->register(Argument::exact('Foo'), Argument::exact('FooHandler'), Argument::type('string'))
->shouldBeCalledOnce();

$this->instance->register('Foo', 'FooHandler');
Expand Down
110 changes: 84 additions & 26 deletions tests/Unit/Bus/Handler/PsrContainerHandlersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,41 @@
use Prophecy\Argument;
use Psr\Container\ContainerInterface;

class Foo
{
}

class FooHandler
{
public function __invoke(): void
{
}
}

class FooHandler1
{
public function __invoke(): void
{
}
}

class FooHandler2
{
public function __invoke(): void
{
}
}

class FooHandler3
{
public static $isCalled = false;

public function handle(): void
{
self::$isCalled = true;
}
}

/**
* @coversDefaultClass \AwdStudio\Bus\Handler\PsrContainerHandlerRegistry
*/
Expand Down Expand Up @@ -60,11 +95,11 @@ public function testMustAllowToInstantiateWithoutExternalHandlers(): void
public function testMustCheckAServiceWhenTriesToRegisterIt(): void
{
$this->containerProphecy
->has(Argument::exact('FooHandler'))
->has(Argument::exact(FooHandler::class))
->willReturn(true)
->shouldBeCalledOnce();

$this->instance->register('Foo', 'FooHandler');
$this->instance->register(FooCallback::class, FooHandler::class);
}

/**
Expand All @@ -73,12 +108,12 @@ public function testMustCheckAServiceWhenTriesToRegisterIt(): void
public function testMustThrowAnExceptionIfAHandlerIsNotInTheServiceLocator(): void
{
$this->containerProphecy
->has(Argument::exact('FooHandler'))
->has(Argument::exact(FooHandler::class))
->willReturn(false);

$this->expectException(InvalidHandler::class);

$this->instance->register('Foo', 'FooHandler');
$this->instance->register(FooCallback::class, FooHandler::class);
}

/**
Expand All @@ -101,11 +136,11 @@ public function testMustCallAnExternalHandlersToAddADynamicHandler(): void
public function testMustCheckAnExternalHandlersWhenLooksForAHandler(): void
{
$this->handlerLocatorProphecy
->has(Argument::exact('Foo'))
->has(Argument::exact(FooCallback::class))
->willReturn(false)
->shouldBeCalledOnce();

$this->instance->has('Foo');
$this->instance->has(FooCallback::class);
}

/**
Expand All @@ -114,10 +149,10 @@ public function testMustCheckAnExternalHandlersWhenLooksForAHandler(): void
public function testMustReturnTrueIfAHandlerIsInExternalHandlers(): void
{
$this->handlerLocatorProphecy
->has(Argument::exact('Foo'))
->has(Argument::exact(FooCallback::class))
->willReturn(true);

$this->assertTrue($this->instance->has('Foo'));
$this->assertTrue($this->instance->has(FooCallback::class));
}

/**
Expand All @@ -126,16 +161,16 @@ public function testMustReturnTrueIfAHandlerIsInExternalHandlers(): void
public function testMustReturnTrueIfAHandlerRegisteredInTheContainerHandlers(): void
{
$this->handlerLocatorProphecy
->has(Argument::exact('Foo'))
->has(Argument::exact(FooCallback::class))
->willReturn(false);

$this->containerProphecy
->has(Argument::exact('FooHandler'))
->has(Argument::exact(FooHandler::class))
->willReturn(true);

$this->instance->register('Foo', 'FooHandler');
$this->instance->register(FooCallback::class, FooHandler::class);

$this->assertTrue($this->instance->has('Foo'));
$this->assertTrue($this->instance->has(FooCallback::class));
}

/**
Expand All @@ -144,10 +179,10 @@ public function testMustReturnTrueIfAHandlerRegisteredInTheContainerHandlers():
public function testMustReturnFalseIfThereAreNoHandlersNorInDynamicHandlersNotInRegisteredOnes(): void
{
$this->handlerLocatorProphecy
->has(Argument::exact('Foo'))
->has(Argument::exact(FooCallback::class))
->willReturn(false);

$this->assertFalse($this->instance->has('Foo'));
$this->assertFalse($this->instance->has(FooCallback::class));
}

/**
Expand All @@ -158,14 +193,14 @@ public function testMustYieldAHandlerFromDynamicHandlersIfItHasSome(): void
$dynamicHandler = static function (): void { return; };

$this->handlerLocatorProphecy
->has(Argument::exact('Foo'))
->has(Argument::exact(FooCallback::class))
->willReturn(true);

$this->handlerLocatorProphecy
->get(Argument::exact('Foo'))
->get(Argument::exact(FooCallback::class))
->willYield([$dynamicHandler]);

$this->assertContains($dynamicHandler, $this->instance->get('Foo'));
$this->assertContains($dynamicHandler, $this->instance->get(FooCallback::class));
}

/**
Expand All @@ -175,17 +210,17 @@ public function testMustYieldAHandlerFromContainerIfItRegistered(): void
{
$dynamicHandler = static function (): void { return; };

$this->instance->register('Foo', 'FooHandler');
$this->instance->register(FooCallback::class, FooHandler::class);

$this->handlerLocatorProphecy
->has(Argument::exact('Foo'))
->has(Argument::exact(FooCallback::class))
->willReturn(false);

$this->containerProphecy
->get(Argument::exact('FooHandler'))
->get(Argument::exact(FooHandler::class))
->willReturn($dynamicHandler);

$this->assertContains($dynamicHandler, $this->instance->get('Foo'));
$this->assertContains($dynamicHandler, $this->instance->get(FooCallback::class));
}

/**
Expand All @@ -197,28 +232,51 @@ public function testMustYieldAllHandlersFromBothAndDynamicHandlersAndTheContaine
$dynamicHandler2 = static function (): void { return; };
$dynamicHandler3 = static function (): void { return; };

$this->instance->register('Foo', 'FooHandler1');
$this->instance->register('Foo', 'FooHandler2');
$this->instance->register(FooCallback::class, FooHandler1::class);
$this->instance->register(FooCallback::class, FooHandler2::class);

$this->handlerLocatorProphecy
->has(Argument::exact('Foo'))
->has(Argument::exact(FooCallback::class))
->willReturn(true);

$this->handlerLocatorProphecy
->get(Argument::exact('Foo'))
->get(Argument::exact(FooCallback::class))
->willYield([$dynamicHandler3]);

$this->containerProphecy
->get(Argument::any())
->willReturn($dynamicHandler1, $dynamicHandler2);

$result = [];
foreach ($this->instance->get('Foo') as $handler) {
foreach ($this->instance->get(FooCallback::class) as $handler) {
$result[] = $handler;
}

$this->assertContains($dynamicHandler1, $result);
$this->assertContains($dynamicHandler2, $result);
$this->assertContains($dynamicHandler3, $result);
}

/**
* @covers ::get
*/
public function testMustReturnACallableArrayAsAnObjectAndRegisteredMethod(): void
{
$this->handlerLocatorProphecy
->has(Argument::any())
->willReturn(false);

$this->containerProphecy
->has(Argument::exact(FooHandler3::class))
->willReturn(true);

$this->containerProphecy
->get(Argument::exact(FooHandler3::class))
->willReturn(new FooHandler3());

$this->instance->register(FooCallback::class, FooHandler3::class, 'handle');
$this->instance->get(FooCallback::class)->current()();

$this->assertTrue(FooHandler3::$isCalled);
}
}

0 comments on commit d6f0940

Please sign in to comment.