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

ContainerHandlersLocator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
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