QueryHandlerLocator::getQueryMap()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
nc 2
nop 1
dl 0
loc 17
rs 9.9666
c 1
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 Gears\DTO\DTO;
21
use Symfony\Component\Messenger\Envelope;
22
use Symfony\Component\Messenger\Handler\HandlerDescriptor;
23
use Symfony\Component\Messenger\Handler\HandlersLocatorInterface;
24
25
class QueryHandlerLocator implements HandlersLocatorInterface
26
{
27
    /**
28
     * Query handlers map.
29
     *
30
     * @var mixed[]
31
     */
32
    protected $handlersMap;
33
34
    /**
35
     * QueryHandlerLocator constructor.
36
     *
37
     * @param mixed[] $handlers
38
     */
39
    public function __construct(array $handlers)
40
    {
41
        $handlers = \array_map(
42
            function ($handler) {
43
                if (!\is_array($handler)) {
44
                    $handler = [$handler];
45
                }
46
47
                if (\count($handler) !== 1) {
48
                    throw new InvalidQueryHandlerException(\sprintf(
49
                        'Only one query handler allowed, %s given.',
50
                        \count($handler)
51
                    ));
52
                }
53
54
                return $handler;
55
            },
56
            $handlers
57
        );
58
59
        $this->handlersMap = $handlers;
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     *
65
     * @throws InvalidQueryHandlerException
66
     */
67
    public function getHandlers(Envelope $envelope): iterable
68
    {
69
        $seen = [];
70
71
        foreach ($this->getQueryMap($envelope) as $type) {
72
            foreach ($this->handlersMap[$type] ?? [] as $alias => $handler) {
73
                if (!$handler instanceof QueryHandler) {
74
                    throw new InvalidQueryHandlerException(\sprintf(
75
                        'Query handler must implement "%s" interface, "%s" given.',
76
                        QueryHandler::class,
77
                        \is_object($handler) ? \get_class($handler) : \gettype($handler)
78
                    ));
79
                }
80
81
                $handlerCallable = function (Query $query) use ($handler): DTO {
82
                    return $handler->handle($query);
83
                };
84
85
                if (!\in_array($handlerCallable, $seen, true)) {
86
                    $seen[] = $handlerCallable;
87
88
                    yield $alias => new HandlerDescriptor($handlerCallable);
89
                }
90
            }
91
        }
92
    }
93
94
    /**
95
     * Get command mapping.
96
     *
97
     * @param Envelope $envelope
98
     *
99
     * @throws InvalidQueryException
100
     *
101
     * @return mixed[]
102
     */
103
    final protected function getQueryMap(Envelope $envelope): array
104
    {
105
        /** @var mixed $query */
106
        $query = $envelope->getMessage();
107
108
        if (!$query instanceof Query) {
109
            throw new InvalidQueryException(\sprintf(
110
                'Query must implement "%s" interface, "%s" given.',
111
                Query::class,
112
                \is_object($query) ? \get_class($query) : \gettype($query)
113
            ));
114
        }
115
116
        $type = $query->getQueryType();
117
118
        return [$type => $type]
119
            + ['*' => '*'];
120
    }
121
}
122