ArrayServiceLoader::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/*
3
 * This file is part of the Borobudur-DependencyInjection package.
4
 *
5
 * (c) Hexacodelabs <http://hexacodelabs.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Borobudur\DependencyInjection;
12
13
use Borobudur\DependencyInjection\Exception\InvalidArgumentException;
14
use Borobudur\DependencyInjection\ParameterBag\Resolver;
15
16
/**
17
 * @author      Iqbal Maulana <[email protected]>
18
 * @created     8/16/15
19
 */
20
class ArrayServiceLoader
21
{
22
    /**
23
     * @var ContainerBuilder
24
     */
25
    private $container;
26
27
    /**
28
     * @param ContainerBuilder $container
29
     */
30
    public function __construct(ContainerBuilder $container)
31
    {
32
        $this->container = $container;
33
    }
34
35
    /**
36
     * Load service from array.
37
     *
38
     * @param array $services
39
     */
40
    public function load(array $services)
41
    {
42
        foreach ($services as $id => $service) {
43
            if ('services' === $id) {
44
                $this->load($service);
45
                continue;
46
            }
47
48
            if (is_int($id) || !$this->isArrayService($service)) {
49
                continue;
50
            }
51
52
            $this->container->setDefinition($id, $this->buildDefinitionFromArray($id, $service));
53
54
            // Build service immediately when eager is true.
55
            if (isset($service['eager']) && true === $service['eager']) {
56
                $this->container->get($id);
57
            }
58
        }
59
    }
60
61
    /**
62
     * Build definition from array.
63
     *
64
     * @param string $id
65
     * @param array  $service
66
     *
67
     * @return Definition
68
     */
69
    private function buildDefinitionFromArray($id, array $service)
70
    {
71
        $definition = new Definition($service['class'], $this->normalizeParameters($service, 'arguments'));
72
        $definition->setAbstract($this->getArrayServiceAbstract($service));
73
        $this->addDefinitionTagsFromArray($definition, $id, $service);
74
        $this->addDefinitionCallsFromArray($definition, $service);
75
76
        if (isset($service['share']) && true === $service['share']) {
77
            $definition->share();
78
        }
79
80
        return $definition;
81
    }
82
83
    /**
84
     * Add method calls on definition.
85
     *
86
     * @param Definition $definition
87
     * @param array      $service
88
     */
89
    private function addDefinitionCallsFromArray(Definition &$definition, array $service)
90
    {
91
        if ($this->isArrayServiceHasCalls($service)) {
92
            foreach ($service['calls'] as $method => $parameters) {
93
                if (is_int($method)) {
94
                    $definition->addMethodCall($parameters);
95
                    continue;
96
                }
97
98
                $definition->addMethodCall($method, $this->normalizeParameters($service['calls'], $method));
99
            }
100
        }
101
    }
102
103
    /**
104
     * Add tags on definition.
105
     *
106
     * @param Definition $definition
107
     * @param string     $id
108
     * @param array      $service
109
     */
110
    private function addDefinitionTagsFromArray(Definition &$definition, $id, array $service)
111
    {
112
        if ($this->isArrayServiceHasTags($service)) {
113
            foreach ($service['tags'] as $tag) {
114
                if (!isset($tag['name'])) {
115
                    throw new InvalidArgumentException(sprintf('Undefined tag name on service "%s"', $id));
116
                }
117
118
                $name = $tag['name'];
119
                unset ($tag['name']);
120
121
                $definition->addTag($name, $tag);
122
            }
123
        }
124
    }
125
126
    /**
127
     * Normalize array service parameters.
128
     *
129
     * @param array  $service
130
     * @param string $index
131
     *
132
     * @return array
133
     */
134
    private function normalizeParameters(array $service, $index)
135
    {
136
        if (!$this->isValidArrayParameters($service, $index)) {
137
            return array();
138
        }
139
140
        $resolver = $this->container->getParameterBag()->getResolver();
141
        $normalized = array();
142
        foreach ($service[$index] as $index => $value) {
143
            $normalized[$index] = $this->computeValue($value, $resolver);
144
        }
145
146
        return $resolver->resolveValue($normalized);
147
    }
148
149
    /**
150
     * Compute value.
151
     *
152
     * @param string   $value
153
     * @param Resolver $resolver
154
     *
155
     * @return array|Reference|mixed
156
     */
157
    private function computeValue($value, Resolver $resolver)
158
    {
159
        if (is_string($value)) {
160
            if (0 === strrpos($value, '@')) {
161
                $value = new Reference(substr($value, 1));
162
            } else {
163
                $value = $resolver->unescapeValue($value);
164
            }
165
        } elseif (is_array($value)) {
166
            foreach ($value as $index => $val) {
167
                $value[$index] = $this->computeValue($val, $resolver);
168
            }
169
        }
170
171
        return $value;
172
    }
173
174
    /**
175
     * Check if array service parameters is valid.
176
     *
177
     * @param array  $service
178
     * @param string $index
179
     *
180
     * @return bool
181
     */
182
    private function isValidArrayParameters(array $service, $index)
183
    {
184
        return isset($service[$index]) && is_array($service[$index]);
185
    }
186
187
    /**
188
     * Get abstract on array service.
189
     *
190
     * @param array $service
191
     *
192
     * @return string|null
193
     */
194
    private function getArrayServiceAbstract(array $service)
195
    {
196
        return isset($service['abstract']) ? $service['abstract'] : null;
197
    }
198
199
    /**
200
     * Check if array service has calls.
201
     *
202
     * @param array $service
203
     *
204
     * @return bool
205
     */
206
    private function isArrayServiceHasCalls(array $service)
207
    {
208
        return isset($service['calls']) && is_array($service['calls']);
209
    }
210
211
    /**
212
     * Check if array service has tags.
213
     *
214
     * @param array $service
215
     *
216
     * @return bool
217
     */
218
    private function isArrayServiceHasTags(array $service)
219
    {
220
        return isset($service['tags']) && is_array($service['tags']);
221
    }
222
223
    /**
224
     * Check if array is service.
225
     *
226
     * @param mixed $service
227
     *
228
     * @return bool
229
     */
230
    private function isArrayService($service)
231
    {
232
        return is_array($service) && isset($service['class']);
233
    }
234
}
235