Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
83.33% covered (warning)
83.33%
20 / 24
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
SyncCommandBus
83.33% covered (warning)
83.33%
20 / 24
66.67% covered (warning)
66.67%
2 / 3
6.17
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 dispatch
63.64% covered (warning)
63.64%
7 / 11
0.00% covered (danger)
0.00%
0 / 1
2.19
 resolveHandler
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3// ╔════════════════════════════════════════════════════════════╗
4// ║ MIT Licence (#Expat) - https://opensource.org/licenses/MIT ║
5// ║ Copyright 2026 Frederic Poeydomenge <dyno@phexium.com>     ║
6// ╚════════════════════════════════════════════════════════════╝
7
8declare(strict_types=1);
9
10namespace Phexium\Plugin\CommandBus\Adapter;
11
12use InvalidArgumentException;
13use Override;
14use Phexium\Application\Command\CommandHandlerInterface;
15use Phexium\Application\Command\CommandInterface;
16use Phexium\Plugin\CommandBus\Internal\CommandHandlerNamingConvention;
17use Phexium\Plugin\CommandBus\Port\CommandBusInterface;
18use Phexium\Plugin\Logger\Port\LoggerInterface;
19use Psr\Container\ContainerInterface;
20
21final readonly class SyncCommandBus implements CommandBusInterface
22{
23    public function __construct(
24        private ContainerInterface $container,
25        private LoggerInterface $logger
26    ) {}
27
28    #[Override]
29    public function dispatch(CommandInterface $command): void
30    {
31        $commandClass = $command::class;
32
33        $this->logger->debug('CommandBus: Dispatching command', [
34            'command' => $commandClass,
35        ]);
36
37        $handler = $this->resolveHandler($commandClass);
38
39        if (!is_callable($handler)) {
40            throw new InvalidArgumentException(sprintf(
41                'Handler %s must be invokable.',
42                $handler::class
43            ));
44        }
45
46        $handler($command);
47    }
48
49    private function resolveHandler(string $commandClass): CommandHandlerInterface
50    {
51        $handlerClass = CommandHandlerNamingConvention::resolveHandlerClass($commandClass);
52
53        if (!class_exists($handlerClass)) {
54            throw new InvalidArgumentException(
55                "Handler not found for command {$commandClass}. Expected class: {$handlerClass}"
56            );
57        }
58
59        $handler = $this->container->get($handlerClass);
60
61        if (!$handler instanceof CommandHandlerInterface) {
62            throw new InvalidArgumentException(sprintf(
63                'Handler must implement %s.',
64                CommandHandlerInterface::class
65            ));
66        }
67
68        return $handler;
69    }
70}