The final middleware in the pipeline that resolves and executes the appropriate command handler.
CommandHandlerMiddleware is the terminal middleware that bridges the middleware pipeline with actual command handlers. It uses the CommandHandlerFactory to resolve the appropriate handler for each command and executes it.
final class CommandHandlerMiddleware implements MiddlewareInterface, CommandHandlerInterface
{
public function __construct(private readonly CommandHandlerFactory $factory);
public function process(CommandInterface $command, CommandHandlerInterface $handler): mixed;
public function handle(CommandInterface $command): mixed;
}The middleware implements both MiddlewareInterface and CommandHandlerInterface:
- As Middleware - Resolves handlers and processes commands
- As Handler - Can be used directly as a command handler
// config/autoload/commandbus.global.php
return [
// other config
Webware\CommandBus\CommandBusInterface::class => [
'command_map' => [
App\Command\CreateUserCommand::class => App\Handler\CreateUserHandler::class,
App\Command\UpdateUserCommand::class => App\Handler\UpdateUserHandler::class,
App\Command\DeleteUserCommand::class => App\Handler\DeleteUserHandler::class,
],
],
// other config
];class CustomCommandHandlerMiddleware extends CommandHandlerMiddleware
{
public function process(CommandInterface $command, CommandHandlerInterface $handler): mixed
{
// Add custom logic before handler resolution
$this->validateCommand($command);
// Resolve and execute handler
$result = parent::process($command, $handler);
// Add custom logic after execution
$this->logResult($command, $result);
return $result;
}
private function validateCommand(CommandInterface $command): void
{
if ($command instanceof ValidatableCommand && !$command->isValid()) {
throw new ValidationException('Command validation failed');
}
}
private function logResult(CommandInterface $command, mixed $result): void
{
$this->logger->info('Command executed successfully', [
'command' => $command::class,
'result_type' => is_object($result) ? $result::class : gettype($result)
]);
}
}Each command should map to exactly one handler:
// ✅ Good - one-to-one mapping
'command_map' => [
CreateUserCommand::class => CreateUserHandler::class,
UpdateUserCommand::class => UpdateUserHandler::class,
]- MiddlewareInterface - Interface this class implements
- CommandHandlerInterface - Interface for the handlers this middleware executes
- CommandHandlerMiddlewareFactory - Factory for creating instances