Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.71% covered (warning)
85.71%
24 / 28
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
SyncCommandBus
85.71% covered (warning)
85.71%
24 / 28
66.67% covered (warning)
66.67%
2 / 3
6.10
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%
16 / 16
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                sprintf(
56                    'Handler not found for command %s. Expected class: %s',
57                    $commandClass,
58                    $handlerClass
59                )
60            );
61        }
62
63        $handler = $this->container->get($handlerClass);
64
65        if (!$handler instanceof CommandHandlerInterface) {
66            throw new InvalidArgumentException(sprintf(
67                'Handler must implement %s.',
68                CommandHandlerInterface::class
69            ));
70        }
71
72        return $handler;
73    }
74}