Completed
Push — master ( 5eee1b...1a95a1 )
by Kamil
04:48
created

assertExternalReferenceHasKnownContainer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
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
        $this->containerAccessors = $containerAccessors;
32
    }
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function process(ContainerBuilder $container)
38
    {
39
        foreach ($container->getDefinitions() as $identifier => $definition) {
40
            $container->setDefinition($identifier, $this->resolveDefinition($container, $definition));
41
        }
42
43
        $this->copyParameters($container);
44
    }
45
46
    /**
47
     * @param ContainerBuilder $container
48
     * @param Definition $definition
49
     *
50
     * @return Definition
51
     */
52
    private function resolveDefinition(ContainerBuilder $container, Definition $definition)
53
    {
54
        $definition->setArguments($this->resolveArguments($container, $definition->getArguments()));
55
56
        return $definition;
57
    }
58
59
    /**
60
     * @param ContainerBuilder $container
61
     * @param array $arguments
62
     *
63
     * @return array
64
     */
65
    private function resolveArguments(ContainerBuilder $container, array $arguments)
66
    {
67
        return array_map(function ($argument) use ($container) {
68
            return $this->resolveArgument($container, $argument);
69
        }, $arguments);
70
    }
71
72
    /**
73
     * @param ContainerBuilder $container
74
     * @param mixed $argument
75
     *
76
     * @return mixed
77
     */
78
    private function resolveArgument(ContainerBuilder $container, $argument)
79
    {
80
        if ($argument instanceof Definition) {
81
            return $this->resolveDefinition($container, $argument);
82
        }
83
84
        if ($argument instanceof Reference) {
85
            return $this->resolveReference($container, $argument);
86
        }
87
88
        if (is_array($argument)) {
89
            return $this->resolveArguments($container, $argument);
90
        }
91
92
        return $argument;
93
    }
94
95
    /**
96
     * @param ContainerBuilder $container
97
     * @param Reference $reference
98
     *
99
     * @return Definition|Reference
100
     */
101
    private function resolveReference(ContainerBuilder $container, Reference $reference)
102
    {
103
        if (!ExternalReference::isValid($reference)) {
104
            return $reference;
105
        }
106
107
        return $this->transformReferenceToDefinition($container, new ExternalReference($reference));
108
    }
109
110
    /**
111
     * @param ContainerBuilder $container
112
     * @param ExternalReference $externalReference
113
     *
114
     * @return Definition
115
     */
116
    private function transformReferenceToDefinition(ContainerBuilder $container, ExternalReference $externalReference)
117
    {
118
        $this->assertExternalReferenceHasKnownContainer($externalReference);
119
120
        $containerAccessorIdentifier = sprintf('__%s__', $externalReference->containerIdentifier());
121
        if (!$container->has($containerAccessorIdentifier)) {
122
            $container->set($containerAccessorIdentifier, $this->containerAccessors[$externalReference->containerIdentifier()]);
123
        }
124
125
        $definition = new Definition(null, [$externalReference->serviceIdentifier()]);
126
        $definition->setFactory([new Reference($containerAccessorIdentifier), 'getService']);
127
128
        return $definition;
129
    }
130
131
    /**
132
     * @param ExternalReference $externalReference
133
     *
134
     * @throws \DomainException
135
     */
136
    private function assertExternalReferenceHasKnownContainer(ExternalReference $externalReference)
137
    {
138
        if (!isset($this->containerAccessors[$externalReference->containerIdentifier()])) {
139
            throw new \DomainException(sprintf(
140
                'External container with identifier "%s" does not exist.',
141
                $externalReference->containerIdentifier()
142
            ));
143
        }
144
    }
145
146
    /**
147
     * @param ContainerBuilder $container
148
     */
149
    private function copyParameters(ContainerBuilder $container)
150
    {
151
        foreach ($this->containerAccessors as $containerIdentifier => $containerAccessor) {
152
            foreach ($containerAccessor->getParameters() as $name => $value) {
153
                $container->setParameter(sprintf('__%s__.%s', $containerIdentifier, $name), $value);
154
            }
155
        }
156
    }
157
}
158