ContainerHandlersLocator   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 76
Duplicated Lines 0 %

Test Coverage

Coverage 97.22%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 32
c 2
b 0
f 0
dl 0
loc 76
ccs 35
cts 36
cp 0.9722
rs 10
wmc 13

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B getHandlers() 0 25 8
A listTypes() 0 9 1
A shouldHandle() 0 13 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace TMV\Messenger\Handler;
6
7
use function class_implements;
8
use function class_parents;
9
use function get_class;
10
use function in_array;
11
use function is_callable;
12
use function is_string;
13
use Psr\Container\ContainerInterface;
14
use Symfony\Component\Messenger\Envelope;
15
use Symfony\Component\Messenger\Handler\HandlerDescriptor;
16
use Symfony\Component\Messenger\Handler\HandlersLocatorInterface;
17
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
18
use TMV\Messenger\Exception\InvalidArgumentException;
19
20
final class ContainerHandlersLocator implements HandlersLocatorInterface
21
{
22
    /** @var ContainerInterface */
23
    private $container;
24
25
    /** @var string[][]|array<string, array<string|callable>>> */
26
    private $handlers;
27
28
    /**
29
     * @param ContainerInterface $container
30
     * @param string[][]|array<string, array<string|callable>> $handlers
31
     */
32 7
    public function __construct(ContainerInterface $container, array $handlers)
33
    {
34 7
        $this->container = $container;
35 7
        $this->handlers = $handlers;
36 7
    }
37
38 3
    public function getHandlers(Envelope $envelope): iterable
39
    {
40 3
        $seen = [];
41 3
        foreach (self::listTypes($envelope) as $type) {
42 3
            foreach ($this->handlers[$type] ?? [] as $handlerDescriptor) {
43 3
                if (is_callable($handlerDescriptor)) {
44
                    /** @psalm-suppress PossiblyInvalidArgument */
45 1
                    $handlerDescriptor = new HandlerDescriptor($handlerDescriptor);
46 2
                } elseif (is_string($handlerDescriptor)) {
47 1
                    $handlerDescriptor = new HandlerDescriptor($this->container->get($handlerDescriptor));
48
                }
49
50 3
                if (! $handlerDescriptor instanceof HandlerDescriptor) {
51
                    throw new InvalidArgumentException('Invalid handler descriptor provided');
52
                }
53
54 3
                if (! $this->shouldHandle($envelope, $handlerDescriptor)) {
55 1
                    continue;
56
                }
57 3
                $name = $handlerDescriptor->getName();
58 3
                if (in_array($name, $seen, true)) {
59 1
                    continue;
60
                }
61 3
                $seen[] = $name;
62 3
                yield $handlerDescriptor;
63
            }
64
        }
65 3
    }
66
67
    /**
68
     * @param Envelope $envelope
69
     *
70
     * @return array<string, string>
71
     */
72 3
    private static function listTypes(Envelope $envelope): array
73
    {
74
        /** @var string $class */
75 3
        $class = get_class($envelope->getMessage());
76
77 3
        return [$class => $class]
78 3
            + class_parents($class)
79 3
            + class_implements($class)
80 3
            + ['*' => '*'];
81
    }
82
83 3
    private function shouldHandle(Envelope $envelope, HandlerDescriptor $handlerDescriptor): bool
84
    {
85
        /** @var ReceivedStamp|null $received */
86 3
        $received = $envelope->last(ReceivedStamp::class);
87 3
        if ($received === null) {
88 2
            return true;
89
        }
90 1
        $expectedTransport = $handlerDescriptor->getOption('from_transport');
91 1
        if ($expectedTransport === null) {
92 1
            return true;
93
        }
94
95 1
        return $received->getTransportName() === $expectedTransport;
96
    }
97
}
98