Skip to content

Commit

Permalink
Use ServiceLocator to allow for private handlers and subscribers
Browse files Browse the repository at this point in the history
  • Loading branch information
ruudk committed Feb 7, 2019
1 parent bf2db5d commit c06f1f1
Show file tree
Hide file tree
Showing 18 changed files with 137 additions and 50 deletions.
28 changes: 20 additions & 8 deletions src/DependencyInjection/Compiler/RegisterHandlers.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,27 @@

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class RegisterHandlers implements CompilerPassInterface
{
use CollectServices;

private $serviceId;
private $callableServiceId;
private $serviceLocatorId;
private $tag;
private $keyAttribute;

/**
* @param string $serviceId The service id of the MessageHandlerMap
* @param string $callableServiceId The service id of the MessageHandlerMap
* @param string $serviceLocatorId The service id of the ServiceLocator
* @param string $tag The tag name of message handler services
* @param string $keyAttribute The name of the tag attribute that contains the name of the handler
*/
public function __construct($serviceId, $tag, $keyAttribute)
public function __construct($callableServiceId, $serviceLocatorId, $tag, $keyAttribute)
{
$this->serviceId = $serviceId;
$this->callableServiceId = $callableServiceId;
$this->serviceLocatorId = $serviceLocatorId;
$this->tag = $tag;
$this->keyAttribute = $keyAttribute;
}
Expand All @@ -33,19 +37,25 @@ public function __construct($serviceId, $tag, $keyAttribute)
*/
public function process(ContainerBuilder $container)
{
if (!$container->has($this->serviceId)) {
if (!$container->has($this->callableServiceId)) {
return;
}

$definition = $container->findDefinition($this->serviceId);
if (!$container->has($this->serviceLocatorId)) {
return;
}

$callableDefinition = $container->findDefinition($this->callableServiceId);
$serviceLocatorDefinition = $container->findDefinition($this->serviceLocatorId);

$handlers = array();
$services = array();

$this->collectServiceIds(
$container,
$this->tag,
$this->keyAttribute,
function ($key, $serviceId, array $tagAttributes) use (&$handlers) {
function ($key, $serviceId, array $tagAttributes) use (&$handlers, &$services) {
if (isset($tagAttributes['method'])) {
// Symfony 3.3 supports services by classname. This interferes with `is_callable`
// in `ServiceLocatorAwareCallableResolver`
Expand All @@ -58,9 +68,11 @@ function ($key, $serviceId, array $tagAttributes) use (&$handlers) {
}

$handlers[ltrim($key, '\\')] = $callable;
$services[$serviceId] = new Reference($serviceId);
}
);

$definition->replaceArgument(0, $handlers);
$callableDefinition->replaceArgument(0, $handlers);
$serviceLocatorDefinition->replaceArgument(0, $services);
}
}
32 changes: 22 additions & 10 deletions src/DependencyInjection/Compiler/RegisterSubscribers.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,27 @@

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class RegisterSubscribers implements CompilerPassInterface
{
use CollectServices;

private $serviceId;
private $callableServiceId;
private $serviceLocatorId;
private $tag;
private $keyAttribute;

/**
* @param string $serviceId The service id of the MessageSubscriberCollection
* @param string $tag The tag name of message subscriber services
* @param string $keyAttribute The name of the tag attribute that contains the name of the subscriber
* @param string $callableServiceId The service id of the MessageSubscriberCollection
* @param string $serviceLocatorId The service id of the ServiceLocator
* @param string $tag The tag name of message subscriber services
* @param string $keyAttribute The name of the tag attribute that contains the name of the subscriber
*/
public function __construct($serviceId, $tag, $keyAttribute)
public function __construct($callableServiceId, $serviceLocatorId, $tag, $keyAttribute)
{
$this->serviceId = $serviceId;
$this->callableServiceId = $callableServiceId;
$this->serviceLocatorId = $serviceLocatorId;
$this->tag = $tag;
$this->keyAttribute = $keyAttribute;
}
Expand All @@ -33,19 +37,25 @@ public function __construct($serviceId, $tag, $keyAttribute)
*/
public function process(ContainerBuilder $container)
{
if (!$container->has($this->serviceId)) {
if (!$container->has($this->callableServiceId)) {
return;
}

$definition = $container->findDefinition($this->serviceId);
if (!$container->has($this->serviceLocatorId)) {
return;
}

$callableDefinition = $container->findDefinition($this->callableServiceId);
$serviceLocatorDefinition = $container->findDefinition($this->serviceLocatorId);

$handlers = array();
$services = array();

$this->collectServiceIds(
$container,
$this->tag,
$this->keyAttribute,
function ($key, $serviceId, array $tagAttributes) use (&$handlers) {
function ($key, $serviceId, array $tagAttributes) use (&$handlers, &$services) {
if (isset($tagAttributes['method'])) {
// Symfony 3.3 supports services by classname. This interferes with `is_callable`
// in `ServiceLocatorAwareCallableResolver`
Expand All @@ -58,9 +68,11 @@ function ($key, $serviceId, array $tagAttributes) use (&$handlers) {
}

$handlers[ltrim($key, '\\')][] = $callable;
$services[$serviceId] = new Reference($serviceId);
}
);

$definition->replaceArgument(0, $handlers);
$callableDefinition->replaceArgument(0, $handlers);
$serviceLocatorDefinition->replaceArgument(0, $services);
}
}
9 changes: 8 additions & 1 deletion src/Resources/config/command_bus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,14 @@ services:
class: SimpleBus\Message\CallableResolver\ServiceLocatorAwareCallableResolver
public: false
arguments:
- ['@service_container', 'get']
- ['@simple_bus.command_bus.command_handler_service_locator', 'get']

simple_bus.command_bus.command_handler_service_locator:
class: Symfony\Component\DependencyInjection\ServiceLocator
tags: ['container.service_locator']
arguments:
# collection of command handler service ids, will be provided by the RegisterHandlers compiler pass
- []

simple_bus.command_bus.command_handler_map:
class: SimpleBus\Message\CallableResolver\CallableMap
Expand Down
9 changes: 8 additions & 1 deletion src/Resources/config/event_bus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ services:
class: SimpleBus\Message\CallableResolver\ServiceLocatorAwareCallableResolver
public: false
arguments:
- ['@service_container', 'get']
- ['@simple_bus.event_bus.event_subscribers_service_locator', 'get']

simple_bus.event_bus.event_subscribers_service_locator:
class: Symfony\Component\DependencyInjection\ServiceLocator
tags: ['container.service_locator']
arguments:
# collection of command handler service ids, will be provided by the RegisterHandlers compiler pass
- []

simple_bus.event_bus.event_subscribers_collection:
class: SimpleBus\Message\CallableResolver\CallableCollection
Expand Down
1 change: 1 addition & 0 deletions src/SimpleBusCommandBusBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(
new RegisterHandlers(
'simple_bus.command_bus.command_handler_map',
'simple_bus.command_bus.command_handler_service_locator',
'command_handler',
'handles'
)
Expand Down
1 change: 1 addition & 0 deletions src/SimpleBusEventBusBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(
new RegisterSubscribers(
'simple_bus.event_bus.event_subscribers_collection',
'simple_bus.event_bus.event_subscribers_service_locator',
'event_subscriber',
'subscribes_to'
)
Expand Down
24 changes: 12 additions & 12 deletions tests/Functional/SmokeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoEvent1;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoEvent2;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoEvent3;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoEventSubscriberUsingInvoke;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoEventSubscriberUsingPublicMethod;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommand;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestKernel;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
Expand Down Expand Up @@ -68,14 +70,13 @@ public function it_can_auto_register_event_subscribers_using_invoke()
self::bootKernel(['environment' => 'config2']);
$container = self::$kernel->getContainer();

$subscriber = $container->get('auto_event_subscriber_using_invoke');
$event = new AutoEvent1();

$this->assertNull($subscriber->handled);
$this->assertFalse($event->isHandledBy(AutoEventSubscriberUsingInvoke::class));

$container->get('event_bus')->handle($event);

$this->assertSame($event, $subscriber->handled);
$this->assertTrue($event->isHandledBy(AutoEventSubscriberUsingInvoke::class));
}

/**
Expand All @@ -86,16 +87,17 @@ public function it_can_auto_register_event_subscribers_using_public_method()
self::bootKernel(['environment' => 'config2']);
$container = self::$kernel->getContainer();

$subscriber = $container->get('auto_event_subscriber_using_public_method');
$event2 = new AutoEvent2();
$event3 = new AutoEvent3();

$this->assertEmpty($subscriber->handled);
$this->assertFalse($event2->isHandledBy(AutoEventSubscriberUsingPublicMethod::class));
$this->assertFalse($event3->isHandledBy(AutoEventSubscriberUsingPublicMethod::class));

$container->get('event_bus')->handle($event2);
$container->get('event_bus')->handle($event3);

$this->assertSame([$event2, $event3], $subscriber->handled);
$this->assertTrue($event2->isHandledBy(AutoEventSubscriberUsingPublicMethod::class));
$this->assertTrue($event3->isHandledBy(AutoEventSubscriberUsingPublicMethod::class));
}

/**
Expand All @@ -106,14 +108,13 @@ public function it_can_auto_register_command_handlers_using_invoke()
self::bootKernel(['environment' => 'config2']);
$container = self::$kernel->getContainer();

$handler = $container->get('auto_command_handler_using_invoke');
$command = new AutoCommand1();

$this->assertNull($handler->handled);
$this->assertFalse($command->isHandled());

$container->get('command_bus')->handle($command);

$this->assertSame($command, $handler->handled);
$this->assertTrue($command->isHandled());
}

/**
Expand All @@ -124,14 +125,13 @@ public function it_can_auto_register_command_handlers_using_public_method()
self::bootKernel(['environment' => 'config2']);
$container = self::$kernel->getContainer();

$handler = $container->get('auto_command_handler_using_public_method');
$command = new AutoCommand2();

$this->assertNull($handler->handled);
$this->assertFalse($command->isHandled());

$container->get('command_bus')->handle($command);

$this->assertSame($command, $handler->handled);
$this->assertTrue($command->isHandled());
}

/**
Expand Down
11 changes: 11 additions & 0 deletions tests/Functional/SmokeTest/Auto/AutoCommand1.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@

final class AutoCommand1
{
private $handled = false;

public function isHandled() : bool
{
return $this->handled;
}

public function setHandled(bool $handled) : void
{
$this->handled = $handled;
}
}
11 changes: 11 additions & 0 deletions tests/Functional/SmokeTest/Auto/AutoCommand2.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@

final class AutoCommand2
{
private $handled = false;

public function isHandled() : bool
{
return $this->handled;
}

public function setHandled(bool $handled) : void
{
$this->handled = $handled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

final class AutoCommandHandlerUsingInvoke
{
public $handled;

public function __invoke(AutoCommand1 $command)
{
$this->handled = $command;
$command->setHandled(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

final class AutoCommandHandlerUsingPublicMethod
{
public $handled;

public function someHandleMethod(AutoCommand2 $command)
{
$this->handled = $command;
$command->setHandled(true);
}
}
11 changes: 11 additions & 0 deletions tests/Functional/SmokeTest/Auto/AutoEvent1.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@

final class AutoEvent1
{
private $handled = [];

public function isHandledBy($subscriber) : bool
{
return in_array($subscriber, $this->handled);
}

public function setHandledBy($subscriber) : void
{
$this->handled[] = get_class($subscriber);
}
}
11 changes: 11 additions & 0 deletions tests/Functional/SmokeTest/Auto/AutoEvent2.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@

final class AutoEvent2
{
private $handled = [];

public function isHandledBy($subscriber) : bool
{
return in_array($subscriber, $this->handled);
}

public function setHandledBy($subscriber) : void
{
$this->handled[] = get_class($subscriber);
}
}
11 changes: 11 additions & 0 deletions tests/Functional/SmokeTest/Auto/AutoEvent3.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@

final class AutoEvent3
{
private $handled = [];

public function isHandledBy($subscriber) : bool
{
return in_array($subscriber, $this->handled);
}

public function setHandledBy($subscriber) : void
{
$this->handled[] = get_class($subscriber);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

final class AutoEventSubscriberUsingInvoke
{
public $handled;

public function __invoke(AutoEvent1 $event)
{
$this->handled = $event;
$event->setHandledBy($this);
}

public function randomPublicMethod($value)
Expand Down
Loading

0 comments on commit c06f1f1

Please sign in to comment.