Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0fcf941

Browse filesBrowse files
authored
Merge pull request #43 from kbond/auto-register
[RFC] Add auto-register compiler pass
2 parents c5752d4 + cad85d2 commit 0fcf941
Copy full SHA for 0fcf941

14 files changed

+241
-53
lines changed

‎doc/command_bus_bundle.md

Copy file name to clipboardExpand all lines: doc/command_bus_bundle.md
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ services:
6464
- { name: command_handler, handles: Fully\Qualified\Class\Name\Of\RegisterUser }
6565
```
6666
67+
### Auto-Register command handlers
68+
69+
You can omit the `handles` tag attribute if your handler meets the following conditions:
70+
71+
1. Uses the "class_based" command name resolving strategy
72+
2. Handles a single command using the `__invoke` method
73+
3. Has a single, non optional class type hinted `__invoke` method parameter
74+
6775
> #### Command handlers are lazy-loaded
6876
>
6977
> Since only one of the command handlers is going to handle any particular command, command handlers are lazy-loaded.

‎doc/event_bus_bundle.md

Copy file name to clipboardExpand all lines: doc/event_bus_bundle.md
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ services:
6565
- { name: event_subscriber, subscribes_to: Fully\Qualified\Class\Name\Of\UserRegistered }
6666
```
6767
68+
### Auto-Register event subscribers
69+
70+
You can omit the `subscribes_to` tag attribute if your subscriber meets the following conditions:
71+
72+
1. Uses the "class_based" event name resolving strategy
73+
2. Subscribers to single event using the `__invoke` method
74+
3. Has a single, non optional class type hinted `__invoke` method parameter
75+
6876
> #### Event subscribers are lazy-loaded
6977
>
7078
> Since only some of the event subscribers are going to handle any particular event, event subscribers are lazy-loaded.
+58Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace SimpleBus\SymfonyBridge\DependencyInjection\Compiler;
4+
5+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
6+
use Symfony\Component\DependencyInjection\ContainerBuilder;
7+
8+
/**
9+
* @author Kevin Bond <kevinbond@gmail.com>
10+
*/
11+
final class AutoRegister implements CompilerPassInterface
12+
{
13+
private $tagName;
14+
private $tagAttribute;
15+
16+
public function __construct($tagName, $tagAttribute)
17+
{
18+
$this->tagName = $tagName;
19+
$this->tagAttribute = $tagAttribute;
20+
}
21+
22+
public function process(ContainerBuilder $container)
23+
{
24+
foreach ($container->findTaggedServiceIds($this->tagName) as $serviceId => $tags) {
25+
foreach ($tags as $tagAttributes) {
26+
27+
// if tag attributes are set, skip
28+
if (isset($tagAttributes[$this->tagAttribute])) {
29+
continue;
30+
}
31+
32+
$definition = $container->getDefinition($serviceId);
33+
34+
// check if service id is class name
35+
$reflectionClass = new \ReflectionClass($definition->getClass() ?: $serviceId);
36+
37+
// if no __invoke method, skip
38+
if (!$reflectionClass->hasMethod('__invoke')) {
39+
continue;
40+
}
41+
42+
$invokeParameters = $reflectionClass->getMethod('__invoke')->getParameters();
43+
44+
// if no param or optional param, skip
45+
if (count($invokeParameters) !== 1 || $invokeParameters[0]->isOptional()) {
46+
return;
47+
}
48+
49+
// get the class name
50+
$handles = $invokeParameters[0]->getClass()->getName();
51+
52+
// auto handle
53+
$definition->clearTag($this->tagName);
54+
$definition->addTag($this->tagName, [$this->tagAttribute => $handles]);
55+
}
56+
}
57+
}
58+
}

‎src/SimpleBusCommandBusBundle.php

Copy file name to clipboardExpand all lines: src/SimpleBusCommandBusBundle.php
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
namespace SimpleBus\SymfonyBridge;
44

55
use SimpleBus\SymfonyBridge\DependencyInjection\CommandBusExtension;
6+
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\AutoRegister;
67
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\ConfigureMiddlewares;
78
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\RegisterHandlers;
9+
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
810
use Symfony\Component\DependencyInjection\ContainerBuilder;
911
use Symfony\Component\HttpKernel\Bundle\Bundle;
1012

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

2022
public function build(ContainerBuilder $container)
2123
{
24+
$container->addCompilerPass(
25+
new AutoRegister('command_handler', 'handles'),
26+
PassConfig::TYPE_BEFORE_OPTIMIZATION,
27+
10
28+
);
29+
2230
$container->addCompilerPass(
2331
new ConfigureMiddlewares(
2432
'command_bus',

‎src/SimpleBusEventBusBundle.php

Copy file name to clipboardExpand all lines: src/SimpleBusEventBusBundle.php
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
namespace SimpleBus\SymfonyBridge;
44

55
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\AddMiddlewareTags;
6+
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\AutoRegister;
67
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\CompilerPassUtil;
78
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\ConfigureMiddlewares;
89
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\RegisterMessageRecorders;
910
use SimpleBus\SymfonyBridge\DependencyInjection\Compiler\RegisterSubscribers;
1011
use SimpleBus\SymfonyBridge\DependencyInjection\EventBusExtension;
12+
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
1113
use Symfony\Component\DependencyInjection\ContainerBuilder;
1214
use Symfony\Component\HttpKernel\Bundle\Bundle;
1315

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

31+
$container->addCompilerPass(
32+
new AutoRegister('event_subscriber', 'subscribes_to'),
33+
PassConfig::TYPE_BEFORE_OPTIMIZATION,
34+
10
35+
);
36+
2937
$container->addCompilerPass(
3038
new ConfigureMiddlewares(
3139
'event_bus',

‎tests/Functional/SmokeTest.php

Copy file name to clipboardExpand all lines: tests/Functional/SmokeTest.php
+47-4Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,27 @@
44

55
use Doctrine\ORM\EntityManager;
66
use Doctrine\ORM\Tools\SchemaTool;
7+
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoCommand;
8+
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoEvent;
79
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommand;
810
use SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestKernel;
11+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
912
use Symfony\Component\DependencyInjection\ContainerInterface;
1013

11-
class SmokeTest extends \PHPUnit_Framework_TestCase
14+
class SmokeTest extends KernelTestCase
1215
{
16+
protected static function getKernelClass()
17+
{
18+
return TestKernel::class;
19+
}
20+
1321
/**
1422
* @test
1523
*/
1624
public function it_handles_a_command_then_dispatches_events_for_all_modified_entities()
1725
{
18-
$kernel = new TestKernel('test', true);
19-
$kernel->boot();
20-
$container = $kernel->getContainer();
26+
self::bootKernel(['environment' => 'config1']);
27+
$container = self::$kernel->getContainer();
2128

2229
$this->createSchema($container);
2330

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

52+
/**
53+
* @test
54+
*/
55+
public function it_can_auto_register_event_subscribers()
56+
{
57+
self::bootKernel(['environment' => 'config2']);
58+
$container = self::$kernel->getContainer();
59+
60+
$subscriber = $container->get('auto_event_subscriber');
61+
$event = new AutoEvent();
62+
63+
$this->assertNull($subscriber->handled);
64+
65+
$container->get('event_bus')->handle($event);
66+
67+
$this->assertSame($event, $subscriber->handled);
68+
}
69+
70+
/**
71+
* @test
72+
*/
73+
public function it_can_auto_register_command_handlers()
74+
{
75+
self::bootKernel(['environment' => 'config2']);
76+
$container = self::$kernel->getContainer();
77+
78+
$handler = $container->get('auto_command_handler');
79+
$command = new AutoCommand();
80+
81+
$this->assertNull($handler->handled);
82+
83+
$container->get('command_bus')->handle($command);
84+
85+
$this->assertSame($command, $handler->handled);
86+
}
87+
4588
private function createSchema(ContainerInterface $container)
4689
{
4790
$entityManager = $container->get('doctrine.orm.entity_manager');
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto;
4+
5+
final class AutoCommand
6+
{
7+
}
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto;
4+
5+
final class AutoCommandHandler
6+
{
7+
public $handled;
8+
9+
public function __invoke(AutoCommand $command)
10+
{
11+
$this->handled = $command;
12+
}
13+
}
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto;
4+
5+
final class AutoEvent
6+
{
7+
}
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto;
4+
5+
final class AutoEventSubscriber
6+
{
7+
public $handled;
8+
9+
public function __invoke(AutoEvent $event)
10+
{
11+
$this->handled = $event;
12+
}
13+
}

‎tests/Functional/SmokeTest/TestKernel.php

Copy file name to clipboardExpand all lines: tests/Functional/SmokeTest/TestKernel.php
+2-3Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ public function __construct($environment, $debug)
1818
{
1919
parent::__construct($environment, $debug);
2020

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

2524
public function registerBundles()
@@ -35,7 +34,7 @@ public function registerBundles()
3534

3635
public function registerContainerConfiguration(LoaderInterface $loader)
3736
{
38-
$loader->load(__DIR__ . '/config.yml');
37+
$loader->load(sprintf('%s/%s.yml', __DIR__, $this->environment));
3938
}
4039

4140
public function getCacheDir()

‎tests/Functional/SmokeTest/config.yml

Copy file name to clipboard
-46Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,7 @@
1-
parameters:
2-
log_file: %kernel.logs_dir%/%kernel.environment%.log
3-
41
services:
52
annotation_reader:
63
class: Doctrine\Common\Annotations\AnnotationReader
74

8-
test_command_handler:
9-
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommandHandler
10-
arguments:
11-
- '@doctrine.orm.default_entity_manager'
12-
tags:
13-
- { name: command_handler, handles: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommand }
14-
15-
some_other_test_command_handler:
16-
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherTestCommandHandler
17-
arguments:
18-
- '@event_recorder'
19-
tags:
20-
- { name: command_handler, handles: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherTestCommand }
21-
22-
test_event_subscriber:
23-
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestEntityCreatedEventSubscriber
24-
tags:
25-
- { name: event_subscriber, subscribes_to: test_entity_created }
26-
arguments:
27-
- '@command_bus'
28-
29-
some_other_event_subscriber:
30-
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherEventSubscriber
31-
tags:
32-
- { name: event_subscriber, subscribes_to: some_other_event }
33-
arguments:
34-
- '@command_bus'
35-
365
doctrine:
376
dbal:
387
driver: pdo_sqlite
@@ -49,18 +18,3 @@ doctrine:
4918
prefix: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Entity
5019
alias: Test
5120
is_bundle: false
52-
53-
command_bus:
54-
command_name_resolver_strategy: class_based
55-
logging: ~
56-
57-
event_bus:
58-
event_name_resolver_strategy: named_message
59-
logging: ~
60-
61-
monolog:
62-
handlers:
63-
main:
64-
type: stream
65-
path: %log_file%
66-
level: debug
+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
imports:
2+
- { resource: config.yml }
3+
4+
parameters:
5+
log_file: %kernel.logs_dir%/%kernel.environment%.log
6+
7+
services:
8+
test_command_handler:
9+
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommandHandler
10+
arguments:
11+
- '@doctrine.orm.default_entity_manager'
12+
tags:
13+
- { name: command_handler, handles: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestCommand }
14+
15+
some_other_test_command_handler:
16+
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherTestCommandHandler
17+
arguments:
18+
- '@event_recorder'
19+
tags:
20+
- { name: command_handler, handles: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherTestCommand }
21+
22+
test_event_subscriber:
23+
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\TestEntityCreatedEventSubscriber
24+
tags:
25+
- { name: event_subscriber, subscribes_to: test_entity_created }
26+
arguments:
27+
- '@command_bus'
28+
29+
some_other_event_subscriber:
30+
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\SomeOtherEventSubscriber
31+
tags:
32+
- { name: event_subscriber, subscribes_to: some_other_event }
33+
arguments:
34+
- '@command_bus'
35+
36+
command_bus:
37+
command_name_resolver_strategy: class_based
38+
logging: ~
39+
40+
event_bus:
41+
event_name_resolver_strategy: named_message
42+
logging: ~
43+
44+
monolog:
45+
handlers:
46+
main:
47+
type: stream
48+
path: %log_file%
49+
level: debug
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
imports:
2+
- { resource: config.yml }
3+
4+
services:
5+
auto_command_handler:
6+
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoCommandHandler
7+
tags:
8+
- { name: command_handler }
9+
10+
auto_event_subscriber:
11+
class: SimpleBus\SymfonyBridge\Tests\Functional\SmokeTest\Auto\AutoEventSubscriber
12+
tags:
13+
- { name: event_subscriber }

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.