Skip to content
New issue

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

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

Already on GitHub? # to your account

fix(commandbus): disallow having two #[CommandHandler] for the same command #706

Merged
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
7 changes: 7 additions & 0 deletions src/Tempest/CommandBus/src/CommandBusConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@ public function __construct(
) {
}

/**
* @throws CommandHandlerAlreadyExists
*/
public function addHandler(CommandHandler $commandHandler, string $commandName, MethodReflector $handler): self
{
if (array_key_exists($commandName, $this->handlers)) {
throw new CommandHandlerAlreadyExists($commandName, new: $handler, existing: $this->handlers[$commandName]->handler);
}

$this->handlers[$commandName] = $commandHandler
->setCommandName($commandName)
->setHandler($handler);
Expand Down
16 changes: 16 additions & 0 deletions src/Tempest/CommandBus/src/CommandHandlerAlreadyExists.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Tempest\CommandBus;

use Exception;
use Tempest\Reflection\MethodReflector;

final class CommandHandlerAlreadyExists extends Exception
{
public function __construct(string $commandName, MethodReflector $new, MethodReflector $existing)
{
parent::__construct("Cannot add handler {$new->getShortName()}, {$existing->getShortName()} already handles {$commandName}.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ public function __invoke(CreateUserCommand $command): void
$this->firstName = $command->firstName;
$this->lastName = $command->lastName;
}

#[CommandHandler]
public function double(CreateUserCommand $command): void
{
// throws a CommandHandlerAlreadyExists exception since the command is already being handled by the __invoke method
}
}
26 changes: 22 additions & 4 deletions src/Tempest/CommandBus/tests/GenericCommandBusTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Tempest\CommandBus\CommandBus;
use Tempest\CommandBus\CommandBusConfig;
use Tempest\CommandBus\CommandHandler;
use Tempest\CommandBus\CommandHandlerAlreadyExists;
use Tempest\CommandBus\CommandHandlerNotFound;
use Tempest\CommandBus\GenericCommandBus;
use Tempest\CommandBus\Tests\Fixtures\CreateUserCommand;
Expand All @@ -21,6 +22,8 @@
*/
final class GenericCommandBusTest extends TestCase
{
private CommandBusConfig $config;

private CommandBus $commandBus;

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

public function test_exception_is_thrown_when_command_handler_already_exist(): void
{
$createUserCommandHandlerClass = new ClassReflector(CreateUserCommandHandler::class);
$createUserCommandHandlerMethod = $createUserCommandHandlerClass->getMethod('__invoke');
$createUserCommandHandler = $createUserCommandHandlerMethod->getAttribute(CommandHandler::class);

$this->expectException(CommandHandlerAlreadyExists::class);

$this->config->addHandler(
commandHandler: $createUserCommandHandler,
commandName: CreateUserCommand::class,
handler: $createUserCommandHandlerClass->getMethod('double'),
);
}

protected function setUp(): void
{
parent::setUp();

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

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

$config->addHandler(
$this->config->addHandler(
commandHandler: $createUserCommandHandler,
commandName: CreateUserCommand::class,
handler: $createUserCommandHandlerMethod
handler: $createUserCommandHandlerMethod,
);

$this->commandBus = new GenericCommandBus(
container: new GenericContainer(),
commandBusConfig: $config
commandBusConfig: $this->config,
);
}
}
Loading