Registry::createService()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Bnf\SymfonyServiceProviderCompilerPass;
4
5
use Interop\Container\ServiceProviderInterface;
6
use Psr\Container\ContainerInterface;
7
8
/**
9
 * A class that holds the list of service providers of a project.
10
 * This class is designed so that service provider do not need to be instantiated each time the registry is filled.
11
 * They can be lazily instantiated if needed.
12
 */
13
class Registry implements \ArrayAccess, \Iterator
14
{
15
    /**
16
     * The array with lazy values.
17
     *
18
     * @var array
19
     */
20
    private $lazyArray;
21
22
    /**
23
     * The array with constructed values.
24
     *
25
     * @var array
26
     */
27
    private $constructedArray = [];
28
29
    /**
30
     * An array of service factories (the result of the call to 'getFactories'),
31
     * indexed by service provider.
32
     *
33
     * @var array An array<key, array<servicename, callable>>
34
     */
35
    private $serviceFactories = [];
36
37
    /**
38
     * An array of service extensions (the result of the call to 'getExtensions'),
39
     * indexed by service provider.
40
     *
41
     * @var array An array<key, array<servicename, callable>>
42
     */
43
    private $serviceExtensions = [];
44
45
    private $position = 0;
46
47
    /**
48
     * Initializes the registry from a list of service providers.
49
     * This list of service providers can be passed as ServiceProvider instances, or simply class name,
50
     * or an array of [class name, [constructor params]].
51
     *
52
     * @param array          $lazyArray The array with lazy values
53
     */
54
    public function __construct(array $lazyArray = [])
55
    {
56
        $this->lazyArray = $lazyArray;
57
    }
58
59
    /**
60
     * @param string|object $className The FQCN or the instance to put in the array
61
     * @param array ...$params The parameters passed to the constructor.
62
     *
63
     * @throws \InvalidArgumentException
64
     */
65
    public function push($className, ...$params)
66
    {
67
        if ($className instanceof ServiceProviderInterface) {
68
            $this->lazyArray[] = $className;
69
        } elseif (is_string($className)) {
70
            $this->lazyArray[] = [$className, $params];
71
        } else {
72
            throw new \InvalidArgumentException('Push expects first parameter to be a fully qualified class name or an instance of Interop\\Container\\ServiceProviderInterface');
73
        }
74
    }
75
76
    /**
77
     * Whether a offset exists.
78
     *
79
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
80
     *
81
     * @param mixed $offset <p>
82
     *                      An offset to check for.
83
     *                      </p>
84
     *
85
     * @return bool true on success or false on failure.
86
     *              </p>
87
     *              <p>
88
     *              The return value will be casted to boolean if non-boolean was returned.
89
     *
90
     * @since 5.0.0
91
     */
92
    public function offsetExists($offset)
93
    {
94
        return isset($this->lazyArray[$offset]);
95
    }
96
97
    /**
98
     * Offset to retrieve.
99
     *
100
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
101
     *
102
     * @param mixed $offset <p>
103
     *                      The offset to retrieve.
104
     *                      </p>
105
     *
106
     * @return mixed Can return all value types.
107
     *
108
     * @since 5.0.0
109
     */
110
    public function offsetGet($offset)
111
    {
112
        if (isset($this->constructedArray[$offset])) {
113
            return $this->constructedArray[$offset];
114
        }
115
        $item = $this->lazyArray[$offset];
116
        if ($item instanceof ServiceProviderInterface) {
117
            $this->constructedArray[$offset] = $item;
118
119
            return $item;
120
        }
121
122
        if (is_array($item)) {
123
            $className = $item[0];
124
            $params = isset($item[1]) ? $item[1] : [];
125
        } elseif (is_string($item)) {
126
            $className = $item;
127
            $params = [];
128
        } else {
129
            throw new \InvalidArgumentException('lazyArray elements are expected to be a fully qualified class name or an instance of Interop\\Container\\ServiceProviderInterface');
130
        }
131
132
        $this->constructedArray[$offset] = new $className(...$params);
133
134
        return $this->constructedArray[$offset];
135
    }
136
137
    /**
138
     * Offset to set.
139
     *
140
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
141
     *
142
     * @param mixed $offset <p>
143
     *                      The offset to assign the value to.
144
     *                      </p>
145
     * @param mixed $value  <p>
146
     *                      The value to set.
147
     *                      </p>
148
     *
149
     * @since 5.0.0
150
     */
151
    public function offsetSet($offset, $value)
152
    {
153
        throw new \LogicException('Not implemented');
154
    }
155
    /**
156
     * Offset to unset.
157
     *
158
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
159
     *
160
     * @param mixed $offset <p>
161
     *                      The offset to unset.
162
     *                      </p>
163
     *
164
     * @since 5.0.0
165
     */
166
    public function offsetUnset($offset)
167
    {
168
        unset($this->lazyArray[$offset]);
169
        unset($this->constructedArray[$offset]);
170
    }
171
172
    /**
173
     * Returns the result of the getFactories call on service provider whose key in the registry is $offset.
174
     * The result is cached in the registry so 2 successive calls will trigger `getFactories` only once.
175
     *
176
     * @param string $offset Key of the service provider in the registry
177
     *
178
     * @return array
179
     */
180
    public function getFactories($offset): array
181
    {
182
        if (!isset($this->serviceFactories[$offset])) {
183
            $this->serviceFactories[$offset] = $this->offsetGet($offset)->getFactories();
184
        }
185
186
        return $this->serviceFactories[$offset];
187
    }
188
189
    /**
190
     * Returns the result of the getExtensions call on service provider whose key in the registry is $offset.
191
     * The result is cached in the registry so 2 successive calls will trigger `getExtensions` only once.
192
     *
193
     * @param string $offset Key of the service provider in the registry
194
     *
195
     * @return array
196
     */
197
    public function getExtensions($offset): array
198
    {
199
        if (!isset($this->serviceExtensions[$offset])) {
200
            $this->serviceExtensions[$offset] = $this->offsetGet($offset)->getExtensions();
201
        }
202
203
        return $this->serviceExtensions[$offset];
204
    }
205
206
    /**
207
     * @param string             $offset      Key of the service provider in the registry
208
     * @param string             $serviceName Name of the service to fetch
209
     * @param ContainerInterface $container
210
     *
211
     * @return mixed
212
     */
213
    public function createService($offset, string $serviceName, ContainerInterface $container)
214
    {
215
        return call_user_func($this->getFactories($offset)[$serviceName], $container);
216
    }
217
218
    /**
219
     * @param string             $offset      Key of the service provider in the registry
220
     * @param string             $serviceName Name of the service to fetch
221
     * @param ContainerInterface $container
222
     * @param mixed              $previous
223
     *
224
     * @return mixed
225
     */
226
    public function extendService($offset, string $serviceName, ContainerInterface $container, $previous)
227
    {
228
        return call_user_func($this->getExtensions($offset)[$serviceName], $container, $previous);
229
    }
230
231
    /**
232
     * Return the current element.
233
     *
234
     * @link http://php.net/manual/en/iterator.current.php
235
     *
236
     * @return mixed Can return any type.
237
     *
238
     * @since 5.0.0
239
     */
240
    public function current()
241
    {
242
        return $this->offsetGet($this->position);
243
    }
244
245
    /**
246
     * Move forward to next element.
247
     *
248
     * @link http://php.net/manual/en/iterator.next.php
249
     * @since 5.0.0
250
     */
251
    public function next()
252
    {
253
        ++$this->position;
254
    }
255
256
    /**
257
     * Return the key of the current element.
258
     *
259
     * @link http://php.net/manual/en/iterator.key.php
260
     *
261
     * @return mixed scalar on success, or null on failure.
262
     *
263
     * @since 5.0.0
264
     */
265
    public function key()
266
    {
267
        return $this->position;
268
    }
269
270
    /**
271
     * Checks if current position is valid.
272
     *
273
     * @link http://php.net/manual/en/iterator.valid.php
274
     *
275
     * @return bool The return value will be casted to boolean and then evaluated.
276
     *              Returns true on success or false on failure.
277
     *
278
     * @since 5.0.0
279
     */
280
    public function valid()
281
    {
282
        return $this->offsetExists($this->position);
283
    }
284
285
    /**
286
     * Rewind the Iterator to the first element.
287
     *
288
     * @link http://php.net/manual/en/iterator.rewind.php
289
     * @since 5.0.0
290
     */
291
    public function rewind()
292
    {
293
        $this->position = 0;
294
    }
295
}
296