Skip to content

Commit f3054f9

Browse files
authored
fix(commandbus): disallow having two #[CommandHandler] for the same command (#706)
1 parent 32aaff4 commit f3054f9

File tree

4 files changed

+51
-4
lines changed

4 files changed

+51
-4
lines changed

src/Tempest/CommandBus/src/CommandBusConfig.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,15 @@ public function __construct(
1717
) {
1818
}
1919

20+
/**
21+
* @throws CommandHandlerAlreadyExists
22+
*/
2023
public function addHandler(CommandHandler $commandHandler, string $commandName, MethodReflector $handler): self
2124
{
25+
if (array_key_exists($commandName, $this->handlers)) {
26+
throw new CommandHandlerAlreadyExists($commandName, new: $handler, existing: $this->handlers[$commandName]->handler);
27+
}
28+
2229
$this->handlers[$commandName] = $commandHandler
2330
->setCommandName($commandName)
2431
->setHandler($handler);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\CommandBus;
6+
7+
use Exception;
8+
use Tempest\Reflection\MethodReflector;
9+
10+
final class CommandHandlerAlreadyExists extends Exception
11+
{
12+
public function __construct(string $commandName, MethodReflector $new, MethodReflector $existing)
13+
{
14+
parent::__construct("Cannot add handler {$new->getShortName()}, {$existing->getShortName()} already handles {$commandName}.");
15+
}
16+
}

src/Tempest/CommandBus/tests/Fixtures/CreateUserCommandHandler.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,10 @@ public function __invoke(CreateUserCommand $command): void
1818
$this->firstName = $command->firstName;
1919
$this->lastName = $command->lastName;
2020
}
21+
22+
#[CommandHandler]
23+
public function double(CreateUserCommand $command): void
24+
{
25+
// throws a CommandHandlerAlreadyExists exception since the command is already being handled by the __invoke method
26+
}
2127
}

src/Tempest/CommandBus/tests/GenericCommandBusTest.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Tempest\CommandBus\CommandBus;
99
use Tempest\CommandBus\CommandBusConfig;
1010
use Tempest\CommandBus\CommandHandler;
11+
use Tempest\CommandBus\CommandHandlerAlreadyExists;
1112
use Tempest\CommandBus\CommandHandlerNotFound;
1213
use Tempest\CommandBus\GenericCommandBus;
1314
use Tempest\CommandBus\Tests\Fixtures\CreateUserCommand;
@@ -21,6 +22,8 @@
2122
*/
2223
final class GenericCommandBusTest extends TestCase
2324
{
25+
private CommandBusConfig $config;
26+
2427
private CommandBus $commandBus;
2528

2629
public function test_getting_command_handler_that_exists(): void
@@ -44,26 +47,41 @@ public function test_exception_is_thrown_when_command_handler_doesnt_exist(): vo
4447
$this->commandBus->dispatch($command);
4548
}
4649

50+
public function test_exception_is_thrown_when_command_handler_already_exist(): void
51+
{
52+
$createUserCommandHandlerClass = new ClassReflector(CreateUserCommandHandler::class);
53+
$createUserCommandHandlerMethod = $createUserCommandHandlerClass->getMethod('__invoke');
54+
$createUserCommandHandler = $createUserCommandHandlerMethod->getAttribute(CommandHandler::class);
55+
56+
$this->expectException(CommandHandlerAlreadyExists::class);
57+
58+
$this->config->addHandler(
59+
commandHandler: $createUserCommandHandler,
60+
commandName: CreateUserCommand::class,
61+
handler: $createUserCommandHandlerClass->getMethod('double'),
62+
);
63+
}
64+
4765
protected function setUp(): void
4866
{
4967
parent::setUp();
5068

5169
// TODO: I'd like to make this easier to setup.
52-
$config = new CommandBusConfig();
70+
$this->config = new CommandBusConfig();
5371

5472
$createUserCommandHandlerClass = new ClassReflector(CreateUserCommandHandler::class);
5573
$createUserCommandHandlerMethod = $createUserCommandHandlerClass->getMethod('__invoke');
5674
$createUserCommandHandler = $createUserCommandHandlerMethod->getAttribute(CommandHandler::class);
5775

58-
$config->addHandler(
76+
$this->config->addHandler(
5977
commandHandler: $createUserCommandHandler,
6078
commandName: CreateUserCommand::class,
61-
handler: $createUserCommandHandlerMethod
79+
handler: $createUserCommandHandlerMethod,
6280
);
6381

6482
$this->commandBus = new GenericCommandBus(
6583
container: new GenericContainer(),
66-
commandBusConfig: $config
84+
commandBusConfig: $this->config,
6785
);
6886
}
6987
}

0 commit comments

Comments
 (0)