Passed
Push — master ( f8f613...c5dee8 )
by Thomas Mauro
03:31
created

ContainerHandlersLocator   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Test Coverage

Coverage 97.22%

Importance

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

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A listTypes() 0 9 1
B getHandlers() 0 24 8
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 1
                    $handlerDescriptor = new HandlerDescriptor($handlerDescriptor);
45 2
                } elseif (is_string($handlerDescriptor)) {
46 1
                    $handlerDescriptor = new HandlerDescriptor($this->container->get($handlerDescriptor));
47
                }
48
49 3
                if (! $handlerDescriptor instanceof HandlerDescriptor) {
50
                    throw new InvalidArgumentException('Invalid handler descriptor provided');
51
                }
52
53 3
                if (! $this->shouldHandle($envelope, $handlerDescriptor)) {
54 1
                    continue;
55
                }
56 3
                $name = $handlerDescriptor->getName();
57 3
                if (in_array($name, $seen, true)) {
58 1
                    continue;
59
                }
60 3
                $seen[] = $name;
61 3
                yield $handlerDescriptor;
62
            }
63
        }
64 3
    }
65
66
    /**
67
     * @param Envelope $envelope
68
     *
69
     * @return array<string, string>
70
     */
71 3
    private static function listTypes(Envelope $envelope): array
72
    {
73
        /** @var string $class */
74 3
        $class = get_class($envelope->getMessage());
75
76 3
        return [$class => $class]
77 3
            + class_parents($class)
78 3
            + class_implements($class)
79 3
            + ['*' => '*'];
80
    }
81
82 3
    private function shouldHandle(Envelope $envelope, HandlerDescriptor $handlerDescriptor): bool
83
    {
84
        /** @var ReceivedStamp|null $received */
85 3
        $received = $envelope->last(ReceivedStamp::class);
86 3
        if ($received === null) {
87 2
            return true;
88
        }
89 1
        $expectedTransport = $handlerDescriptor->getOption('from_transport');
90 1
        if ($expectedTransport === null) {
91 1
            return true;
92
        }
93
94 1
        return $received->getTransportName() === $expectedTransport;
95
    }
96
}
97