Completed
Push — master ( 0e324f...947448 )
by Kamil
03:42
created

copyParameters()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 4
nc 3
nop 1
1
<?php
2
3
namespace FriendsOfBehat\CrossContainerExtension;
4
5
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
6
use Symfony\Component\DependencyInjection\ContainerBuilder;
7
use Symfony\Component\DependencyInjection\Definition;
8
use Symfony\Component\DependencyInjection\Reference;
9
10
final class ResolveCrossContainerReferencesPass implements CompilerPassInterface
11
{
12
    /**
13
     * @var ContainerAccessor[]
14
     */
15
    private $containerAccessors;
16
17
    /**
18
     * @param ContainerAccessor[] $containerAccessors
19
     */
20
    public function __construct(array $containerAccessors)
21
    {
22
        $this->containerAccessors = $containerAccessors;
23
    }
24
25
    /**
26
     * {@inheritdoc}
27
     */
28
    public function process(ContainerBuilder $container)
29
    {
30
        foreach ($container->getDefinitions() as $identifier => $definition) {
31
            $container->setDefinition($identifier, $this->resolveDefinition($container, $definition));
32
        }
33
34
        $this->copyParameters($container);
35
    }
36
37
    /**
38
     * @param ContainerBuilder $container
39
     * @param Definition $definition
40
     *
41
     * @return Definition
42
     */
43
    private function resolveDefinition(ContainerBuilder $container, Definition $definition)
44
    {
45
        $definition->setArguments($this->resolveArguments($container, $definition->getArguments()));
46
47
        return $definition;
48
    }
49
50
    /**
51
     * @param ContainerBuilder $container
52
     * @param array $arguments
53
     *
54
     * @return array
55
     */
56
    private function resolveArguments(ContainerBuilder $container, array $arguments)
57
    {
58
        return array_map(function ($argument) use ($container) {
59
            return $this->resolveArgument($container, $argument);
60
        }, $arguments);
61
    }
62
63
    /**
64
     * @param ContainerBuilder $container
65
     * @param mixed $argument
66
     *
67
     * @return mixed
68
     */
69
    private function resolveArgument(ContainerBuilder $container, $argument)
70
    {
71
        if ($argument instanceof Definition) {
72
            return $this->resolveDefinition($container, $argument);
73
        }
74
75
        if ($argument instanceof Reference) {
76
            return $this->resolveReference($container, $argument);
77
        }
78
79
        if (is_array($argument)) {
80
            return $this->resolveArguments($container, $argument);
81
        }
82
83
        return $argument;
84
    }
85
86
    /**
87
     * @param ContainerBuilder $container
88
     * @param Reference $reference
89
     *
90
     * @return Definition|Reference
91
     */
92
    private function resolveReference(ContainerBuilder $container, Reference $reference)
93
    {
94
        $containerIdentifier = preg_replace('/^__([^_]+)__\..+$/', '$1', (string) $reference);
95
96
        if (!isset($this->containerAccessors[$containerIdentifier])) {
97
            return $reference;
98
        }
99
100
        $serviceIdentifier = preg_replace('/^__[^_]+__\.(.+)$/', '$1', (string) $reference);
101
102
        return $this->transformReferenceToDefinition($container, $containerIdentifier, $serviceIdentifier);
103
    }
104
105
    /**
106
     * @param ContainerBuilder $container
107
     * @param string $containerIdentifier
108
     * @param string $serviceIdentifier
109
     *
110
     * @return Definition
111
     */
112
    private function transformReferenceToDefinition(ContainerBuilder $container, $containerIdentifier, $serviceIdentifier)
113
    {
114
        $containerAccessorIdentifier = sprintf('__%s__', $containerIdentifier);
115
        if (!$container->has($containerAccessorIdentifier)) {
116
            $container->set($containerAccessorIdentifier, $this->containerAccessors[$containerIdentifier]);
117
        }
118
119
        $definition = new Definition(null, [$serviceIdentifier]);
120
        $definition->setFactory([new Reference($containerAccessorIdentifier), 'getService']);
121
122
        return $definition;
123
    }
124
125
    /**
126
     * @param ContainerBuilder $container
127
     */
128
    private function copyParameters(ContainerBuilder $container)
129
    {
130
        foreach ($this->containerAccessors as $containerIdentifier => $containerAccessor) {
131
            foreach ($containerAccessor->getParameters() as $name => $value) {
132
                $container->setParameter(sprintf('__%s__.%s', $containerIdentifier, $name), $value);
133
            }
134
        }
135
    }
136
}
137