Skip to content

Commit 782a7aa

Browse files
committed
add command bus service
1 parent e676bce commit 782a7aa

5 files changed

Lines changed: 134 additions & 7 deletions

File tree

docs/pages/configuration.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ These handlers allow you to use your aggregates as command handlers.
418418

419419
```yaml
420420
patchlevel_event_sourcing:
421-
aggregate_handlers: ~
421+
command_bus: ~
422422
```
423423
!!! note
424424

@@ -428,6 +428,8 @@ Default the handlers will be registered for all buses.
428428
You can also specify a specific bus.
429429
Before you have to define the bus in the messenger configuration.
430430

431+
### Symfony Messenger
432+
431433
```yaml
432434
framework:
433435
messenger:
@@ -443,9 +445,10 @@ And then you can specify the bus in the configuration.
443445

444446
```yaml
445447
patchlevel_event_sourcing:
446-
aggregate_handlers:
447-
bus: command.bus
448+
command_bus:
449+
service: command.bus
448450
```
451+
449452
## Event Bus
450453

451454
You can enable the event bus to listen for events and messages synchronously.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Patchlevel\EventSourcingBundle\CommandBus;
4+
5+
use Patchlevel\EventSourcing\CommandBus\CommandBus;
6+
use Symfony\Component\Messenger\MessageBusInterface;
7+
8+
final class SymfonyCommandBus implements CommandBus
9+
{
10+
public function __construct(
11+
private readonly MessageBusInterface $messageBus,
12+
) {
13+
}
14+
15+
public function dispatch(object $command): void
16+
{
17+
$this->messageBus->dispatch($command);
18+
}
19+
}

src/DependencyInjection/Configuration.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
/**
1111
* @psalm-type Config = array{
1212
* event_bus: array{enabled: bool, type: string, service: string},
13+
* command_bus: array{enabled: bool, message_bus: string},
1314
* subscription: array{
1415
* store: array{type: string, service: string|null},
1516
* retry_strategy: array{base_delay: int, delay_factor: int, max_attempts: int},
@@ -232,12 +233,26 @@ public function getConfigTreeBuilder(): TreeBuilder
232233
->end()
233234
->end()
234235

236+
->arrayNode('command_bus')
237+
->canBeEnabled()
238+
->addDefaultsIfNotSet()
239+
->children()
240+
->scalarNode('service')->defaultNull()->end()
241+
->booleanNode('register_aggregate_handlers')->defaultTrue()->end()
242+
->end()
243+
->end()
244+
235245
->arrayNode('aggregate_handlers')
236246
->canBeEnabled()
237247
->addDefaultsIfNotSet()
238248
->children()
239249
->scalarNode('bus')->defaultNull()->end()
240250
->end()
251+
->setDeprecated(
252+
'patchlevel/event-sourcing-bundle',
253+
'3.9',
254+
'The "%node%" option is deprecated and will be removed in 4.0. Use "patchlevel_event_sourcing.command_bus" instead.'
255+
)
241256
->end()
242257

243258
->end();

src/DependencyInjection/PatchlevelEventSourcingExtension.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Patchlevel\EventSourcing\Attribute\Subscriber;
2222
use Patchlevel\EventSourcing\Clock\FrozenClock;
2323
use Patchlevel\EventSourcing\Clock\SystemClock;
24+
use Patchlevel\EventSourcing\CommandBus\CommandBus;
2425
use Patchlevel\EventSourcing\Console\Command\DatabaseCreateCommand;
2526
use Patchlevel\EventSourcing\Console\Command\DatabaseDropCommand;
2627
use Patchlevel\EventSourcing\Console\Command\DebugCommand;
@@ -107,6 +108,7 @@
107108
use Patchlevel\EventSourcing\Subscription\Subscriber\SubscriberHelper;
108109
use Patchlevel\EventSourcingBundle\Attribute\AsListener;
109110
use Patchlevel\EventSourcingBundle\Command\StoreMigrateCommand;
111+
use Patchlevel\EventSourcingBundle\CommandBus\SymfonyCommandBus;
110112
use Patchlevel\EventSourcingBundle\DataCollector\EventSourcingCollector;
111113
use Patchlevel\EventSourcingBundle\DataCollector\MessageCollectorEventBus;
112114
use Patchlevel\EventSourcingBundle\Doctrine\DbalConnectionFactory;
@@ -135,7 +137,6 @@
135137
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
136138
use Symfony\Component\DependencyInjection\Extension\Extension;
137139
use Symfony\Component\DependencyInjection\Reference;
138-
139140
use function class_exists;
140141
use function sprintf;
141142

@@ -158,7 +159,7 @@ public function load(array $configs, ContainerBuilder $container): void
158159
$this->configureUpcaster($container);
159160
$this->configureSerializer($config, $container);
160161
$this->configureMessageDecorator($container);
161-
$this->configureAggregateHandlers($config, $container);
162+
$this->configureCommandBus($config, $container);
162163
$this->configureEventBus($config, $container);
163164
$this->configureConnection($config, $container);
164165
$this->configureStore($config, $container);
@@ -218,13 +219,36 @@ private function configureSerializer(array $config, ContainerBuilder $container)
218219
}
219220

220221
/** @param Config $config */
221-
private function configureAggregateHandlers(array $config, ContainerBuilder $container): void
222+
private function configureCommandBus(array $config, ContainerBuilder $container): void
222223
{
224+
if ($config['command_bus']['enabled'] && $config['aggregate_handlers']['enabled']) {
225+
throw new InvalidArgumentException('Remove legacy aggregate_handlers configuration when using command_bus');
226+
}
227+
228+
if ($config['command_bus']['enabled']) {
229+
$container->register(SymfonyCommandBus::class)
230+
->setArguments([
231+
new Reference($config['command_bus']['service']),
232+
]);
233+
234+
$container->setAlias(CommandBus::class, SymfonyCommandBus::class);
235+
236+
$container->setParameter(
237+
'patchlevel_event_sourcing.aggregate_handlers.bus',
238+
$config['command_bus']['service']
239+
);
240+
241+
return;
242+
}
243+
223244
if (!$config['aggregate_handlers']['enabled']) {
224245
return;
225246
}
226247

227-
$container->setParameter('patchlevel_event_sourcing.aggregate_handlers.bus', $config['aggregate_handlers']['bus']);
248+
$container->setParameter(
249+
'patchlevel_event_sourcing.aggregate_handlers.bus',
250+
$config['aggregate_handlers']['bus']
251+
);
228252
}
229253

230254
/** @param Config $config */

tests/Unit/PatchlevelEventSourcingBundleTest.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Patchlevel\EventSourcing\Aggregate\CustomId;
1313
use Patchlevel\EventSourcing\Clock\FrozenClock;
1414
use Patchlevel\EventSourcing\Clock\SystemClock;
15+
use Patchlevel\EventSourcing\CommandBus\CommandBus;
1516
use Patchlevel\EventSourcing\CommandBus\Handler\CreateAggregateHandler;
1617
use Patchlevel\EventSourcing\Console\Command\DatabaseCreateCommand;
1718
use Patchlevel\EventSourcing\Console\Command\DatabaseDropCommand;
@@ -70,6 +71,7 @@
7071
use Patchlevel\EventSourcing\Subscription\Store\SubscriptionStore;
7172
use Patchlevel\EventSourcing\Subscription\Subscriber\MetadataSubscriberAccessorRepository;
7273
use Patchlevel\EventSourcingBundle\Command\StoreMigrateCommand;
74+
use Patchlevel\EventSourcingBundle\CommandBus\SymfonyCommandBus;
7375
use Patchlevel\EventSourcingBundle\DependencyInjection\PatchlevelEventSourcingExtension;
7476
use Patchlevel\EventSourcingBundle\EventBus\SymfonyEventBus;
7577
use Patchlevel\EventSourcingBundle\PatchlevelEventSourcingBundle;
@@ -547,6 +549,69 @@ public function testCommandHandler(): void
547549
self::assertEquals('command.bus', $tag['bus']);
548550
}
549551

552+
public function testCommandBusAndLegacyConfigurationNotAllowed(): void
553+
{
554+
$container = new ContainerBuilder();
555+
556+
$this->expectException(InvalidArgumentException::class);
557+
$this->expectExceptionMessage('Remove legacy aggregate_handlers configuration when using command_bus');
558+
559+
$this->compileContainer(
560+
$container,
561+
[
562+
'patchlevel_event_sourcing' => [
563+
'connection' => [
564+
'service' => 'doctrine.dbal.eventstore_connection',
565+
],
566+
'aggregates' => [__DIR__ . '/../Fixtures'],
567+
'aggregate_handlers' => [
568+
'bus' => 'command.bus',
569+
],
570+
'command_bus' => [
571+
'service' => 'command.bus',
572+
],
573+
],
574+
]
575+
);
576+
}
577+
578+
public function testCommandBus(): void
579+
{
580+
$container = new ContainerBuilder();
581+
582+
$this->compileContainer(
583+
$container,
584+
[
585+
'patchlevel_event_sourcing' => [
586+
'connection' => [
587+
'service' => 'doctrine.dbal.eventstore_connection',
588+
],
589+
'aggregates' => [__DIR__ . '/../Fixtures'],
590+
'command_bus' => [
591+
'service' => 'command.bus',
592+
],
593+
],
594+
]
595+
);
596+
597+
$handler = $container->get('event_sourcing.handler.profile.create');
598+
599+
self::assertInstanceOf(CreateAggregateHandler::class, $handler);
600+
601+
$handler(new CreateProfile(CustomId::fromString('1')));
602+
603+
$definition = $container->getDefinition('event_sourcing.handler.profile.create');
604+
$tags = $definition->getTag('messenger.message_handler');
605+
606+
self::assertCount(1, $tags);
607+
608+
$tag = $tags[0];
609+
610+
self::assertEquals(CreateProfile::class, $tag['handles']);
611+
self::assertEquals('command.bus', $tag['bus']);
612+
self::assertInstanceOf(SymfonyCommandBus::class, $container->get(CommandBus::class));
613+
}
614+
550615
public function testSnapshotStore(): void
551616
{
552617
$container = new ContainerBuilder();
@@ -1222,6 +1287,7 @@ private function compileContainer(ContainerBuilder $container, array $config): v
12221287

12231288
$container->set('doctrine.dbal.eventstore_connection', $this->prophesize(Connection::class)->reveal());
12241289
$container->set('event.bus', $this->prophesize(MessageBusInterface::class)->reveal());
1290+
$container->set('command.bus', $this->prophesize(MessageBusInterface::class)->reveal());
12251291
$container->set('cache.default', $this->prophesize(CacheItemPoolInterface::class)->reveal());
12261292
$container->set('event_dispatcher', $this->prophesize(EventDispatcherInterface::class)->reveal());
12271293
$container->set('services_resetter', $this->prophesize(ServicesResetter::class)->reveal());

0 commit comments

Comments
 (0)