Passed
Push — master ( 602db7...ce95a6 )
by Julián
06:51
created

QueryHandlerLocator::getHandlers()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 5
nop 1
dl 0
loc 22
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * cqrs-symfony-messenger (https://github.com/phpgears/cqrs-symfony-messenger).
5
 * CQRS implementation with Symfony's Messenger.
6
 *
7
 * @license MIT
8
 * @link https://github.com/phpgears/cqrs-symfony-messenger
9
 * @author Julián Gutiérrez <[email protected]>
10
 */
11
12
declare(strict_types=1);
13
14
namespace Gears\CQRS\Symfony\Messenger;
15
16
use Gears\CQRS\Exception\InvalidQueryException;
17
use Gears\CQRS\Exception\InvalidQueryHandlerException;
18
use Gears\CQRS\Query;
19
use Gears\CQRS\QueryHandler;
20
use Symfony\Component\Messenger\Envelope;
21
use Symfony\Component\Messenger\Handler\HandlerDescriptor;
22
use Symfony\Component\Messenger\Handler\HandlersLocatorInterface;
23
24
class QueryHandlerLocator implements HandlersLocatorInterface
25
{
26
    /**
27
     * Query handlers map.
28
     *
29
     * @var mixed[]
30
     */
31
    protected $handlersMap;
32
33
    /**
34
     * QueryHandlerLocator constructor.
35
     *
36
     * @param mixed[] $handlers
37
     */
38
    public function __construct(array $handlers)
39
    {
40
        $handlers = \array_map(
41
            function ($handler) {
42
                if (!\is_array($handler)) {
43
                    $handler = [$handler];
44
                }
45
46
                if (\count($handler) !== 1) {
47
                    throw new InvalidQueryHandlerException(\sprintf(
48
                        'Only one query handler allowed, %s given',
49
                        \count($handler)
50
                    ));
51
                }
52
53
                return $handler;
54
            },
55
            $handlers
56
        );
57
58
        $this->handlersMap = $handlers;
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     *
64
     * @throws InvalidQueryHandlerException
65
     */
66
    public function getHandlers(Envelope $envelope): iterable
67
    {
68
        $seen = [];
69
70
        foreach ($this->getQueryMap($envelope) as $type) {
71
            foreach ($this->handlersMap[$type] ?? [] as $alias => $handler) {
72
                if (!$handler instanceof QueryHandler) {
73
                    throw new InvalidQueryHandlerException(\sprintf(
74
                        'Query handler must implement %s interface, %s given',
75
                        QueryHandler::class,
76
                        \is_object($handler) ? \get_class($handler) : \gettype($handler)
77
                    ));
78
                }
79
80
                $handlerCallable = function (Query $query) use ($handler) {
81
                    return $handler->handle($query);
82
                };
83
84
                if (!\in_array($handlerCallable, $seen, true)) {
85
                    $seen[] = $handlerCallable;
86
87
                    yield $alias => new HandlerDescriptor($handlerCallable);
88
                }
89
            }
90
        }
91
    }
92
93
    /**
94
     * Get command mapping.
95
     *
96
     * @param Envelope $envelope
97
     *
98
     * @throws InvalidQueryException
99
     *
100
     * @return mixed[]
101
     */
102
    final protected function getQueryMap(Envelope $envelope): array
103
    {
104
        /** @var mixed $query */
105
        $query = $envelope->getMessage();
106
107
        if (!$query instanceof Query) {
108
            throw new InvalidQueryException(\sprintf(
109
                'Query must implement %s interface, %s given',
110
                Query::class,
111
                \is_object($query) ? \get_class($query) : \gettype($query)
112
            ));
113
        }
114
115
        $class = \get_class($query);
116
117
        return [$class => $class]
118
            + ['*' => '*'];
119
    }
120
}
121