Completed
Push — master ( 3e3d3c...053aa5 )
by Olivier
01:44
created

HandlerProviderPass   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 96
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 7
lcom 1
cbo 6
dl 0
loc 96
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A process() 0 11 1
A collectHandlers() 0 38 5
1
<?php
2
3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ICanBoogie\MessageBus\Symfony;
13
14
use ICanBoogie\MessageBus\HandlerProvider;
15
use ICanBoogie\MessageBus\PSR\ContainerHandlerProvider;
16
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
17
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
18
use Symfony\Component\DependencyInjection\ContainerBuilder;
19
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
20
use Symfony\Component\DependencyInjection\Exception\LogicException;
21
use Symfony\Component\DependencyInjection\TypedReference;
22
23
use function is_string;
24
25
/**
26
 * Collect message handlers and register their provider.
27
 */
28
class HandlerProviderPass implements CompilerPassInterface
29
{
30
    public const DEFAULT_SERVICE_ID = HandlerProvider::class;
31
    public const DEFAULT_HANDLER_TAG = 'message_dispatcher.handler';
32
    public const DEFAULT_MESSAGE_PROPERTY = 'message';
33
    public const DEFAULT_PROVIDER_CLASS = ContainerHandlerProvider::class;
34
35
    /**
36
     * @var string
37
     */
38
    private $serviceId;
39
40
    /**
41
     * @var string
42
     */
43
    private $handlerTag;
44
45
    /**
46
     * @var string
47
     */
48
    private $messageProperty;
49
50
    /**
51
     * @var string
52
     */
53
    private $providerClass;
54
55
    public function __construct(
56
        string $serviceId = self::DEFAULT_SERVICE_ID,
57
        string $handlerTag = self::DEFAULT_HANDLER_TAG,
58
        string $messageProperty = self::DEFAULT_MESSAGE_PROPERTY,
59
        string $providerClass = self::DEFAULT_PROVIDER_CLASS
60
    ) {
61
        $this->serviceId = $serviceId;
62
        $this->handlerTag = $handlerTag;
63
        $this->messageProperty = $messageProperty;
64
        $this->providerClass = $providerClass;
65
    }
66
67
    /**
68
     * @inheritdoc
69
     */
70
    public function process(ContainerBuilder $container): void
71
    {
72
        [ $mapping, $refMap ] = $this->collectHandlers($container);
0 ignored issues
show
Bug introduced by
The variable $mapping does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $refMap does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
73
74
        $container
75
            ->register($this->serviceId, $this->providerClass)
76
            ->setArguments([
77
                ServiceLocatorTagPass::register($container, $refMap),
78
                $mapping
79
            ]);
80
    }
81
82
    /**
83
     * @return array{0: array<string, string>, 1: array<string, TypedReference>}
0 ignored issues
show
Documentation introduced by
The doc-type array{0: could not be parsed: Unknown type name "array{0:" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
84
     */
85
    private function collectHandlers(ContainerBuilder $container): array
86
    {
87
        $handlers = $container->findTaggedServiceIds($this->handlerTag, true);
88
        $messageProperty = $this->messageProperty;
89
        $mapping = [];
90
        $refMap = [];
91
92
        foreach ($handlers as $id => $tags) {
93
            assert(is_string($id));
94
95
            $command = $tags[0][$messageProperty] ?? null;
96
97
            if (!$command) {
98
                throw new InvalidArgumentException(
99
                    "The `$messageProperty` property is required for service `$id`."
100
                );
101
            }
102
103
            assert(is_string($command));
104
105
            if (isset($mapping[$command])) {
106
                throw new LogicException(
107
                    "The command `$command` already has an handler: `{$mapping[$command]}`."
108
                );
109
            }
110
111
            $class = $container->getDefinition($id)->getClass();
112
113
            if (!$class) {
114
                throw new LogicException("Unable to get class of service `$id`.");
115
            }
116
117
            $mapping[$command] = $id;
118
            $refMap[$id] = new TypedReference($id, $class);
119
        }
120
121
        return [ $mapping, $refMap ];
122
    }
123
}
124