Lines 100.00% 19 / 19
Functions and Methods 100.00% 4 / 4
Classes and Traits 100.00% 1 / 1
Name Lines Functions and Methods CRAP Classes and Traits
MessageHandlerIndex 100.00% 19 / 19 100.00% 4 / 4 8 100.00% 1 / 1
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 fromHandlers 100.00% 13 / 13 100.00% 1 / 1 3
 findHandlerFor 100.00% 1 / 1 100.00% 1 / 1 1
 findHandlerByInterfaceOf 100.00% 4 / 4 100.00% 1 / 1 3
1<?php
2
3declare(strict_types=1);
4
5namespace Stewart\Runtime\Ipc;
6
7use Stewart\Runtime\Exception\ContainerError;
8use Stewart\Runtime\Exception\ContainerException;
9
10/** @template THandler of MessageHandler */
11final readonly class MessageHandlerIndex
12{
13    /** @param array<class-string, THandler> $handlersByMessageClass */
14    private function __construct(private array $handlersByMessageClass) {}
15
16    /**
17     * @template TIndexed of MessageHandler
18     *
19     * @param iterable<TIndexed> $handlers
20     *
21     * @return self<TIndexed>
22     *
23     * @throws ContainerException
24     */
25    public static function fromHandlers(iterable $handlers): self
26    {
27        $handlersByMessageClass = [];
28
29        foreach ($handlers as $handler) {
30            $messageClass = $handler->handledMessageClass();
31            $registered = $handlersByMessageClass[$messageClass] ?? null;
32
33            if ($registered !== null) {
34                throw ContainerException::createForReason(
35                    ContainerError::MessageHandlerDuplicated,
36                    messageClass: $messageClass,
37                    firstHandler: $registered::class,
38                    secondHandler: $handler::class,
39                );
40            }
41
42            $handlersByMessageClass[$messageClass] = $handler;
43        }
44
45        return new self($handlersByMessageClass);
46    }
47
48    /** @return THandler|null */
49    public function findHandlerFor(object $message): ?MessageHandler
50    {
51        return $this->handlersByMessageClass[$message::class] ?? $this->findHandlerByInterfaceOf($message);
52    }
53
54    /** @return THandler|null */
55    private function findHandlerByInterfaceOf(object $message): ?MessageHandler
56    {
57        foreach (class_implements($message) as $interface) {
58            if (isset($this->handlersByMessageClass[$interface])) {
59                return $this->handlersByMessageClass[$interface];
60            }
61        }
62
63        return null;
64    }
65}