Skip to content

Add auto-register compiler pass #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 5, 2017
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
8 changes: 8 additions & 0 deletions doc/command_bus_bundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ services:
- { name: command_handler, handles: Fully\Qualified\Class\Name\Of\RegisterUser }
```

### Auto-Register command handlers

You can omit the `handles` tag attribute if your handler meets the following conditions:

1. Uses the "class_based" command name resolving strategy
2. Handles a single command using the `__invoke` method
3. Has a single, non optional class type hinted `__invoke` method parameter

> #### Command handlers are lazy-loaded
>
> Since only one of the command handlers is going to handle any particular command, command handlers are lazy-loaded.
Expand Down
8 changes: 8 additions & 0 deletions doc/event_bus_bundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ services:
- { name: event_subscriber, subscribes_to: Fully\Qualified\Class\Name\Of\UserRegistered }
```

### Auto-Register event subscribers

You can omit the `subscribes_to` tag attribute if your subscriber meets the following conditions:

1. Uses the "class_based" event name resolving strategy
2. Subscribers to single event using the `__invoke` method
3. Has a single, non optional class type hinted `__invoke` method parameter

> #### Event subscribers are lazy-loaded
>
> Since only some of the event subscribers are going to handle any particular event, event subscribers are lazy-loaded.
Expand Down
58 changes: 58 additions & 0 deletions src/DependencyInjection/Compiler/AutoRegister.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace SimpleBus\SymfonyBridge\DependencyInjection\Compiler;

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

/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
final class AutoRegister implements CompilerPassInterface
{
private $tagName;
private $tagAttribute;

public function __construct($tagName, $tagAttribute)
{
$this->tagName = $tagName;
$this->tagAttribute = $tagAttribute;
}

public function process(ContainerBuilder $container)
{
foreach ($container->findTaggedServiceIds($this->tagName) as $serviceId => $tags) {
foreach ($tags as $tagAttributes) {

// if tag attributes are set, skip
if (isset($tagAttributes[$this->tagAttribute])) {
continue;
}

$definition = $container->getDefinition($serviceId);

// check if service id is class name
$reflectionClass = new \ReflectionClass($definition->getClass() ?: $serviceId);

// if no __invoke method, skip
if (!$reflectionClass->hasMethod('__invoke')) {
continue;
}

$invokeParameters = $reflectionClass->getMethod('__invoke')->getParameters();

// if no param or optional param, skip
if (count($invokeParameters) !== 1 || $invokeParameters[0]->isOptional()) {
return;
}

// get the class name
$handles = $invokeParameters[0]->getClass()->getName();

// auto handle
$definition->clearTag($this->tagName);
$definition->addTag($this->tagName, [$this->tagAttribute => $handles]);
}
}
}
}
8 changes: 8 additions & 0 deletions src/SimpleBusCommandBusBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace SimpleBus\SymfonyBridge;

use SimpleBus\SymfonyBridge\DependencyInjection\CommandBusExtension;
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\AutoRegister;
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\ConfigureMiddlewares;
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\RegisterHandlers;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

Expand All @@ -19,6 +21,12 @@ public function __construct($alias = 'command_bus')

public function build(ContainerBuilder $container)
{
$container->addCompilerPass(
new AutoRegister('command_handler', 'handles'),
PassConfig::TYPE_BEFORE_OPTIMIZATION,
10
);

$container->addCompilerPass(
new ConfigureMiddlewares(
'command_bus',
Expand Down
8 changes: 8 additions & 0 deletions src/SimpleBusEventBusBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
namespace SimpleBus\SymfonyBridge;

use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\AddMiddlewareTags;
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\AutoRegister;
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\CompilerPassUtil;
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\ConfigureMiddlewares;
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\RegisterMessageRecorders;
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\RegisterSubscribers;
use SimpleBus\SymfonyBridge\DependencyInjection\EventBusExtension;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

Expand All @@ -26,6 +28,12 @@ public function build(ContainerBuilder $container)
{
$this->checkRequirements(array('SimpleBusCommandBusBundle'), $container);

$container->addCompilerPass(
new AutoRegister('event_subscriber', 'subscribes_to'),
PassConfig::TYPE_BEFORE_OPTIMIZATION,
10
);

$container->addCompilerPass(
new ConfigureMiddlewares(
'event_bus',
Expand Down
51 changes: 47 additions & 4 deletions tests/Functional/SmokeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,27 @@

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\SchemaTool;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoCommand;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoEvent;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommand;
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestKernel;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\DependencyInjection\ContainerInterface;

class SmokeTest extends \PHPUnit_Framework_TestCase
class SmokeTest extends KernelTestCase
{
protected static function getKernelClass()
{
return TestKernel::class;
}

/**
* @test
*/
public function it_handles_a_command_then_dispatches_events_for_all_modified_entities()
{
$kernel = new TestKernel('test', true);
$kernel->boot();
$container = $kernel->getContainer();
self::bootKernel(['environment' => 'config1']);
$container = self::$kernel->getContainer();

$this->createSchema($container);

Expand All @@ -42,6 +49,42 @@ public function it_handles_a_command_then_dispatches_events_for_all_modified_ent
$this->assertContains('event_bus.DEBUG: Finished notifying a subscriber', $loggedMessages);
}

/**
* @test
*/
public function it_can_auto_register_event_subscribers()
{
self::bootKernel(['environment' => 'config2']);
$container = self::$kernel->getContainer();

$subscriber = $container->get('auto_event_subscriber');
$event = new AutoEvent();

$this->assertNull($subscriber->handled);

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

$this->assertSame($event, $subscriber->handled);
}

/**
* @test
*/
public function it_can_auto_register_command_handlers()
{
self::bootKernel(['environment' => 'config2']);
$container = self::$kernel->getContainer();

$handler = $container->get('auto_command_handler');
$command = new AutoCommand();

$this->assertNull($handler->handled);

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

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

private function createSchema(ContainerInterface $container)
{
$entityManager = $container->get('doctrine.orm.entity_manager');
Expand Down
7 changes: 7 additions & 0 deletions tests/Functional/SmokeTest/Auto/AutoCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto;

final class AutoCommand
{
}
13 changes: 13 additions & 0 deletions tests/Functional/SmokeTest/Auto/AutoCommandHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto;

final class AutoCommandHandler
{
public $handled;

public function __invoke(AutoCommand $command)
{
$this->handled = $command;
}
}
7 changes: 7 additions & 0 deletions tests/Functional/SmokeTest/Auto/AutoEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto;

final class AutoEvent
{
}
13 changes: 13 additions & 0 deletions tests/Functional/SmokeTest/Auto/AutoEventSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto;

final class AutoEventSubscriber
{
public $handled;

public function __invoke(AutoEvent $event)
{
$this->handled = $event;
}
}
5 changes: 2 additions & 3 deletions tests/Functional/SmokeTest/TestKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ public function __construct($environment, $debug)
{
parent::__construct($environment, $debug);

$this->tempDir = sys_get_temp_dir() . '/' . uniqid();
mkdir($this->tempDir, 0777, true);
$this->tempDir = sys_get_temp_dir() . '/simplebus-symfony-bridge';
}

public function registerBundles()
Expand All @@ -35,7 +34,7 @@ public function registerBundles()

public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__ . '/config.yml');
$loader->load(sprintf('%s/%s.yml', __DIR__, $this->environment));
}

public function getCacheDir()
Expand Down
46 changes: 0 additions & 46 deletions tests/Functional/SmokeTest/config.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,7 @@
parameters:
log_file: %kernel.logs_dir%/%kernel.environment%.log

services:
annotation_reader:
class: Doctrine\Common\Annotations\AnnotationReader

test_command_handler:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommandHandler
arguments:
- '@doctrine.orm.default_entity_manager'
tags:
- { name: command_handler, handles: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommand }

some_other_test_command_handler:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherTestCommandHandler
arguments:
- '@event_recorder'
tags:
- { name: command_handler, handles: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherTestCommand }

test_event_subscriber:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestEntityCreatedEventSubscriber
tags:
- { name: event_subscriber, subscribes_to: test_entity_created }
arguments:
- '@command_bus'

some_other_event_subscriber:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherEventSubscriber
tags:
- { name: event_subscriber, subscribes_to: some_other_event }
arguments:
- '@command_bus'

doctrine:
dbal:
driver: pdo_sqlite
Expand All @@ -49,18 +18,3 @@ doctrine:
prefix: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Entity
alias: Test
is_bundle: false

command_bus:
command_name_resolver_strategy: class_based
logging: ~

event_bus:
event_name_resolver_strategy: named_message
logging: ~

monolog:
handlers:
main:
type: stream
path: %log_file%
level: debug
49 changes: 49 additions & 0 deletions tests/Functional/SmokeTest/config1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
imports:
- { resource: config.yml }

parameters:
log_file: %kernel.logs_dir%/%kernel.environment%.log

services:
test_command_handler:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommandHandler
arguments:
- '@doctrine.orm.default_entity_manager'
tags:
- { name: command_handler, handles: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommand }

some_other_test_command_handler:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherTestCommandHandler
arguments:
- '@event_recorder'
tags:
- { name: command_handler, handles: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherTestCommand }

test_event_subscriber:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestEntityCreatedEventSubscriber
tags:
- { name: event_subscriber, subscribes_to: test_entity_created }
arguments:
- '@command_bus'

some_other_event_subscriber:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherEventSubscriber
tags:
- { name: event_subscriber, subscribes_to: some_other_event }
arguments:
- '@command_bus'

command_bus:
command_name_resolver_strategy: class_based
logging: ~

event_bus:
event_name_resolver_strategy: named_message
logging: ~

monolog:
handlers:
main:
type: stream
path: %log_file%
level: debug
13 changes: 13 additions & 0 deletions tests/Functional/SmokeTest/config2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
imports:
- { resource: config.yml }

services:
auto_command_handler:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoCommandHandler
tags:
- { name: command_handler }

auto_event_subscriber:
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoEventSubscriber
tags:
- { name: event_subscriber }