Completed
Push — master ( 9b8a13...c5dce3 )
by Kamil
06:38
created

src/CrossContainerProcessor.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the CrossContainerExtension package.
5
 *
6
 * (c) Kamil Kokot <[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 FriendsOfBehat\CrossContainerExtension;
13
14
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15
use Symfony\Component\DependencyInjection\ContainerBuilder;
16
use Symfony\Component\DependencyInjection\Definition;
17
use Symfony\Component\DependencyInjection\Reference;
18
19
final class CrossContainerProcessor implements CompilerPassInterface
20
{
21
    /**
22
     * @var ContainerAccessor[]
23
     */
24
    private $containerAccessors;
25
26
    /**
27
     * @param ContainerAccessor[] $containerAccessors
28
     */
29
    public function __construct(array $containerAccessors = [])
30
    {
31
        foreach ($containerAccessors as $containerIdentifier => $containerAccessor) {
32
            $this->addContainerAccessor($containerIdentifier, $containerAccessor);
33
        }
34
    }
35
36
    /**
37
     * @param string $containerIdentifier
38
     * @param ContainerAccessor $containerAccessor
39
     */
40
    public function addContainerAccessor($containerIdentifier, ContainerAccessor $containerAccessor)
41
    {
42
        $this->containerAccessors[$containerIdentifier] = $containerAccessor;
43
    }
44
45
    /**
46
     * {@inheritdoc}
47
     */
48
    public function process(ContainerBuilder $container)
49
    {
50
        foreach ($container->getDefinitions() as $identifier => $definition) {
51
            $container->setDefinition($identifier, $this->resolveDefinition($definition));
52
        }
53
54
        $this->copyParameters($container);
55
    }
56
57
    /**
58
     * @param Definition $definition
59
     *
60
     * @return Definition
61
     */
62
    private function resolveDefinition(Definition $definition)
63
    {
64
        $definition->setArguments($this->resolveArguments($definition->getArguments()));
65
        $definition->setFactory($this->resolveFactory($definition->getFactory()));
0 ignored issues
show
It seems like $definition->getFactory() targeting Symfony\Component\Depend...efinition::getFactory() can also be of type string; however, FriendsOfBehat\CrossCont...essor::resolveFactory() does only seem to accept array|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
It seems like $this->resolveFactory($definition->getFactory()) targeting FriendsOfBehat\CrossCont...essor::resolveFactory() can also be of type null; however, Symfony\Component\Depend...efinition::setFactory() does only seem to accept string|array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
66
67
        return $definition;
68
    }
69
70
    /**
71
     * @param array|null $factory
72
     *
73
     * @return array|null
74
     */
75
    private function resolveFactory($factory)
76
    {
77
        if ([] === $factory) {
78
            return [];
79
        }
80
81
        if (isset($factory[0]) && $factory[0] instanceof Reference) {
82
            $factory[0] = $this->resolveReference($factory[0]);
83
        }
84
85
        return $factory;
86
    }
87
88
    /**
89
     * @param array $arguments
90
     *
91
     * @return array
92
     */
93
    private function resolveArguments(array $arguments)
94
    {
95
        return array_map(function ($argument){
96
            return $this->resolveArgument($argument);
97
        }, $arguments);
98
    }
99
100
    /**
101
     * @param mixed $argument
102
     *
103
     * @return mixed
104
     */
105
    private function resolveArgument($argument)
106
    {
107
        if ($argument instanceof Definition) {
108
            return $this->resolveDefinition($argument);
109
        }
110
111
        if ($argument instanceof Reference) {
112
            return $this->resolveReference($argument);
113
        }
114
115
        if (is_array($argument)) {
116
            return $this->resolveArguments($argument);
117
        }
118
119
        return $argument;
120
    }
121
122
    /**
123
     * @param Reference $reference
124
     *
125
     * @return Definition|Reference
126
     */
127
    private function resolveReference(Reference $reference)
128
    {
129
        if (!ExternalReference::isValid($reference)) {
130
            return $reference;
131
        }
132
133
        return $this->transformReferenceToDefinition(new ExternalReference($reference));
134
    }
135
136
    /**
137
     * @param ExternalReference $externalReference
138
     *
139
     * @return Definition
140
     */
141
    private function transformReferenceToDefinition(ExternalReference $externalReference)
142
    {
143
        $this->assertExternalReferenceHasKnownContainer($externalReference);
144
145
        $definition = new Definition(null, [$externalReference->serviceIdentifier()]);
146
        $definition->setFactory([$this->containerAccessors[$externalReference->containerIdentifier()], 'getService']);
147
148
        return $definition;
149
    }
150
151
    /**
152
     * @param ExternalReference $externalReference
153
     *
154
     * @throws \DomainException
155
     */
156
    private function assertExternalReferenceHasKnownContainer(ExternalReference $externalReference)
157
    {
158
        if (!isset($this->containerAccessors[$externalReference->containerIdentifier()])) {
159
            throw new \DomainException(sprintf(
160
                'External container with identifier "%s" does not exist.',
161
                $externalReference->containerIdentifier()
162
            ));
163
        }
164
    }
165
166
    /**
167
     * @param ContainerBuilder $container
168
     */
169
    private function copyParameters(ContainerBuilder $container)
170
    {
171
        foreach ($this->containerAccessors as $containerIdentifier => $containerAccessor) {
172
            foreach ($containerAccessor->getParameters() as $name => $value) {
173
                $container->setParameter(sprintf('__%s__.%s', $containerIdentifier, $name), $value);
174
            }
175
        }
176
    }
177
}
178