ContainerHandlersLocator::shouldHandle()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 13
ccs 7
cts 7
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 2
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace TMV\Laminas\Messenger\Handler;
6
7
use Psr\Container\ContainerInterface;
8
use Symfony\Component\Messenger\Envelope;
9
use Symfony\Component\Messenger\Handler\HandlerDescriptor;
10
use Symfony\Component\Messenger\Handler\HandlersLocatorInterface;
11
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
12
use TMV\Laminas\Messenger\Exception\InvalidArgumentException;
13
14
use function class_implements;
15
use function class_parents;
16
use function get_class;
17
use function in_array;
18
use function is_callable;
19
use function is_string;
20
21
final class ContainerHandlersLocator implements HandlersLocatorInterface
22
{
23
    /** @var ContainerInterface */
24
    private $container;
25
26
    /** @var string[][]|array<string, array<string|callable>>> */
27
    private $handlers;
28
29
    /**
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
     * @return array<string, string>
69
     */
70
    private static function listTypes(Envelope $envelope): array
71
    {
72 3
        /** @var string $class */
73
        $class = get_class($envelope->getMessage());
74
75 3
        return [$class => $class]
76
            + class_parents($class)
77 3
            + class_implements($class)
78 3
            + ['*' => '*'];
79 3
    }
80 3
81
    private function shouldHandle(Envelope $envelope, HandlerDescriptor $handlerDescriptor): bool
82
    {
83 3
        /** @var ReceivedStamp|null $received */
84
        $received = $envelope->last(ReceivedStamp::class);
85
        if ($received === null) {
86 3
            return true;
87 3
        }
88 2
        $expectedTransport = $handlerDescriptor->getOption('from_transport');
89
        if ($expectedTransport === null) {
90 1
            return true;
91 1
        }
92 1
93
        return $received->getTransportName() === $expectedTransport;
94
    }
95
}
96