1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This is part of the symfonette/neon-integration package. |
5
|
|
|
* |
6
|
|
|
* (c) Martin Hasoň <[email protected]> |
7
|
|
|
* (c) Webuni s.r.o. <[email protected]> |
8
|
|
|
* |
9
|
|
|
* For the full copyright and license information, please view the LICENSE |
10
|
|
|
* file that was distributed with this source code. |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace Symfonette\NeonIntegration\DependencyInjection; |
14
|
|
|
|
15
|
|
|
use Nette\Neon\Entity; |
16
|
|
|
use Nette\Neon\Neon; |
17
|
|
|
use Symfony\Component\Config\Resource\FileResource; |
18
|
|
|
use Symfony\Component\DependencyInjection\Alias; |
19
|
|
|
use Symfony\Component\DependencyInjection\ContainerInterface; |
20
|
|
|
use Symfony\Component\DependencyInjection\Definition; |
21
|
|
|
use Symfony\Component\DependencyInjection\DefinitionDecorator; |
22
|
|
|
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; |
23
|
|
|
use Symfony\Component\DependencyInjection\Exception\RuntimeException; |
24
|
|
|
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; |
25
|
|
|
use Symfony\Component\DependencyInjection\Loader\FileLoader; |
26
|
|
|
use Symfony\Component\DependencyInjection\Reference; |
27
|
|
|
use Symfony\Component\ExpressionLanguage\Expression; |
28
|
|
|
|
29
|
|
|
class NeonFileLoader extends FileLoader |
30
|
|
|
{ |
31
|
|
|
private static $keywords = [ |
32
|
|
|
'alias' => 'alias', |
33
|
|
|
'parent' => 'parent', |
34
|
|
|
'class' => 'class', |
35
|
|
|
'shared' => 'shared', |
36
|
|
|
'synthetic' => 'synthetic', |
37
|
|
|
'lazy' => 'lazy', |
38
|
|
|
'public' => 'public', |
39
|
|
|
'abstract' => 'abstract', |
40
|
|
|
'deprecated' => 'deprecated', |
41
|
|
|
'factory' => 'factory', |
42
|
|
|
'file' => 'file', |
43
|
|
|
'arguments' => 'arguments', |
44
|
|
|
'properties' => 'properties', |
45
|
|
|
'configurator' => 'configurator', |
46
|
|
|
'calls' => 'calls', |
47
|
|
|
'tags' => 'tags', |
48
|
|
|
'decorates' => 'decorates', |
49
|
|
|
'decoration_inner_name' => 'decoration_inner_name', |
50
|
|
|
'decoration_priority' => 'decoration_priority', |
51
|
|
|
'autowire' => 'autowire', |
52
|
|
|
'autowiring_types' => 'autowiring_types', |
53
|
|
|
'setup' => 'setup', // nette |
54
|
|
|
]; |
55
|
|
|
|
56
|
|
|
private $anonymousServicesCount; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* {@inheritdoc} |
60
|
|
|
*/ |
61
|
|
|
public function supports($resource, $type = null) |
62
|
|
|
{ |
63
|
|
|
return is_string($resource) && 'neon' === pathinfo($resource, PATHINFO_EXTENSION) && (null === $type || 'neon' === $type); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* {@inheritdoc} |
68
|
|
|
*/ |
69
|
|
|
public function load($resource, $type = null) |
70
|
|
|
{ |
71
|
|
|
$path = $this->locator->locate($resource); |
72
|
|
|
|
73
|
|
|
$content = $this->loadFile($path); |
74
|
|
|
|
75
|
|
|
$this->container->addResource(new FileResource($path)); |
76
|
|
|
|
77
|
|
|
if (null === $content) { |
78
|
|
|
return; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
$this->parseImports($content, $path); |
82
|
|
|
|
83
|
|
|
if (isset($content['parameters'])) { |
84
|
|
|
if (!is_array($content['parameters'])) { |
85
|
|
|
throw new InvalidArgumentException(sprintf('The "parameters" key should contain an array in %s. Check your NEON syntax.', $resource)); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
foreach ($content['parameters'] as $key => $value) { |
89
|
|
|
$this->container->setParameter($key, $this->resolveServices($value, $path)); |
90
|
|
|
} |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
$this->loadFromExtensions($content); |
94
|
|
|
|
95
|
|
|
$this->parseDefinitions($content, $resource); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
private function loadFile($file) |
99
|
|
|
{ |
100
|
|
|
if (!class_exists('Nette\Neon\Neon')) { |
101
|
|
|
throw new RuntimeException('Unable to load NEON config files as the Nette Neon Component is not installed.'); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
if (!stream_is_local($file)) { |
105
|
|
|
throw new InvalidArgumentException(sprintf('This is not a local file "%s".', $file)); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
if (!file_exists($file)) { |
109
|
|
|
throw new InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file)); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
try { |
113
|
|
|
$configuration = Neon::decode(file_get_contents($file)); |
114
|
|
|
} catch (\Exception $e) { |
115
|
|
|
throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid NEON.', $file), 0, $e); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
return $this->validateFile($configuration, $file); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
private function validateFile($content, $file) |
122
|
|
|
{ |
123
|
|
|
if (null === $content) { |
124
|
|
|
return $content; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
if (!is_array($content)) { |
128
|
|
|
throw new InvalidArgumentException(sprintf('The service file "%s" is not valid. It should contain an array. Check your NEON syntax.', $file)); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
foreach ($content as $namespace => $data) { |
132
|
|
|
if (in_array($namespace, ['imports', 'includes', 'parameters', 'services'])) { |
133
|
|
|
continue; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
if (!$this->container->hasExtension($namespace)) { |
137
|
|
|
$extensionNamespaces = array_filter(array_map( |
138
|
|
|
function (ExtensionInterface $ext) { |
139
|
|
|
return $ext->getAlias(); |
140
|
|
|
}, |
141
|
|
|
$this->container->getExtensions() |
142
|
|
|
)); |
143
|
|
|
|
144
|
|
|
throw new InvalidArgumentException(sprintf( |
145
|
|
|
'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s', |
146
|
|
|
$namespace, |
147
|
|
|
$file, |
148
|
|
|
$namespace, |
149
|
|
|
$extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none' |
150
|
|
|
)); |
151
|
|
|
} |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
return $content; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
private function parseImports($content, $file) |
158
|
|
|
{ |
159
|
|
|
// nette |
160
|
|
|
if (!isset($content['imports']) && !isset($content['includes'])) { |
161
|
|
|
return; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
foreach (['imports', 'includes'] as $key) { |
165
|
|
|
if (isset($content[$key]) && !is_array($content[$key])) { |
166
|
|
|
throw new InvalidArgumentException(sprintf('The "%s" key should contain an array in %s. Check your NEON syntax.', $key, $file)); |
167
|
|
|
} |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
// nette |
171
|
|
|
$content = array_merge(['imports' => [], 'includes' => []], $content); |
172
|
|
|
$imports = array_merge($content['imports'], $content['includes']); |
173
|
|
|
|
174
|
|
|
foreach ($imports as $import) { |
175
|
|
|
$this->setCurrentDir(dirname($file)); |
176
|
|
|
if (is_array($import)) { |
177
|
|
|
$this->import($import['resource'], null, isset($import['ignore_errors']) ? (bool) $import['ignore_errors'] : false, $file); |
178
|
|
|
} else { |
179
|
|
|
$this->import($import, null, false, $file); // nette |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
private function parseDefinitions($content, $file) |
185
|
|
|
{ |
186
|
|
|
if (!isset($content['services'])) { |
187
|
|
|
return; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
if (!is_array($content['services'])) { |
191
|
|
|
throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file)); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
$this->anonymousServicesCount = 0; |
195
|
|
|
foreach ($content['services'] as $id => $service) { |
196
|
|
|
if (is_int($id)) { |
197
|
|
|
$id = $this->generateAnonymousServiceId($file); |
198
|
|
|
} |
199
|
|
|
$this->parseDefinition($id, $service, $file); |
200
|
|
|
} |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
private function parseDefinition($id, $service, $file) |
204
|
|
|
{ |
205
|
|
|
if ($this->processService($id, $service, $file)) { |
206
|
|
|
return; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
$this->checkDefinition($id, $service, $file); |
210
|
|
|
|
211
|
|
|
if ($this->processAlias($id, $service, $file)) { |
212
|
|
|
return; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
$definition = isset($service['parent']) ? new DefinitionDecorator($service['parent']) : new Definition(); |
216
|
|
|
|
217
|
|
|
$this->processClass($id, $service, $definition, $file); |
218
|
|
|
|
219
|
|
|
if (isset($service['shared'])) { |
220
|
|
|
$definition->setShared($service['shared']); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
if (isset($service['synthetic'])) { |
224
|
|
|
$definition->setSynthetic($service['synthetic']); |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
if (isset($service['lazy'])) { |
228
|
|
|
$definition->setLazy($service['lazy']); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
if (isset($service['public'])) { |
232
|
|
|
$definition->setPublic($service['public']); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
if (isset($service['abstract'])) { |
236
|
|
|
$definition->setAbstract($service['abstract']); |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
if (array_key_exists('deprecated', $service)) { |
240
|
|
|
$definition->setDeprecated(true, $service['deprecated']); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
$this->processFactory($id, $service, $definition, $file); |
244
|
|
|
|
245
|
|
|
if (isset($service['file'])) { |
246
|
|
|
$definition->setFile($service['file']); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
$this->processArguments($service, $definition, $file); |
250
|
|
|
|
251
|
|
|
// nette |
252
|
|
|
$this->processSetup($service); |
253
|
|
|
|
254
|
|
|
if (isset($service['properties'])) { |
255
|
|
|
$definition->setProperties($this->resolveServices($service['properties'], $file)); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
if (isset($service['configurator'])) { |
259
|
|
|
if (is_string($service['configurator'])) { |
260
|
|
|
$definition->setConfigurator($service['configurator']); |
261
|
|
|
} else { |
262
|
|
|
$definition->setConfigurator([$this->resolveServices($service['configurator'][0], $file), $service['configurator'][1]]); |
263
|
|
|
} |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
$this->processCalls($id, $service, $definition, $file); |
267
|
|
|
$this->processTags($id, $service, $definition, $file); |
268
|
|
|
|
269
|
|
|
if (isset($service['decorates'])) { |
270
|
|
|
$renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null; |
271
|
|
|
$priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0; |
272
|
|
|
$definition->setDecoratedService($service['decorates'], $renameId, $priority); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
$this->processAutowire($id, $service, $definition, $file); |
276
|
|
|
$this->processAutowiringTypes($id, $service, $definition, $file); |
277
|
|
|
|
278
|
|
|
$this->container->setDefinition($id, $definition); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
private function processService(&$id, &$service, $file) |
282
|
|
|
{ |
283
|
|
|
// nette |
284
|
|
|
if ($service instanceof Entity) { |
285
|
|
|
$value = $service->value; |
286
|
|
|
$service = ['arguments' => $service->attributes]; |
287
|
|
|
if (false === strpos($value, ':')) { |
288
|
|
|
$service['class'] = $value; |
289
|
|
|
} else { |
290
|
|
|
$service['factory'] = $value; |
291
|
|
|
} |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
// nette |
295
|
|
|
if (preg_match('#^(\S+)\s+<\s+(\S+)\z#', $id, $matches)) { |
296
|
|
View Code Duplication |
if (isset($service['parent']) && $matches[2] !== $service['parent']) { |
|
|
|
|
297
|
|
|
throw new InvalidArgumentException(sprintf('Two parent services "%s" and "%s" are defined for service "%s" in "%s". Check your NEON syntax.', $service['parent'], $matches[2], $matches[1], $file)); |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
$id = $matches[1]; |
301
|
|
|
$parent = $matches[2]; |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
// nette |
305
|
|
|
if (is_string($service) && false !== strpos($service, ':')) { |
306
|
|
|
$service = ['factory' => $this->parseFactory($service, $file)]; |
307
|
|
|
} elseif (is_string($service) && 0 === strpos($service, '@')) { |
308
|
|
|
$this->container->setAlias($id, substr($service, 1)); |
309
|
|
|
|
310
|
|
|
return true; |
311
|
|
|
} elseif (is_string($service)) { |
312
|
|
|
$service = ['class' => $service]; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
// nette |
316
|
|
|
if (isset($parent)) { |
317
|
|
|
$service['parent'] = $parent; |
318
|
|
|
} |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
private function processAlias($id, array &$service, $file) |
322
|
|
|
{ |
323
|
|
|
if (!isset($service['alias'])) { |
324
|
|
|
return; |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
$public = !array_key_exists('public', $service) || (bool) $service['public']; |
328
|
|
|
$this->container->setAlias($id, new Alias($service['alias'], $public)); |
329
|
|
|
|
330
|
|
|
foreach ($service as $key => $value) { |
331
|
|
|
if (!in_array($key, ['alias', 'public'])) { |
332
|
|
|
throw new InvalidArgumentException(sprintf('The configuration key "%s" is unsupported for alias definition "%s" in "%s". Allowed configuration keys are "alias" and "public".', $key, $id, $file)); |
333
|
|
|
} |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
return true; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
View Code Duplication |
private function processClass($id, &$service, Definition $definition, $file) |
|
|
|
|
340
|
|
|
{ |
341
|
|
|
if (!isset($service['class'])) { |
342
|
|
|
return; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
$class = $service['class']; |
346
|
|
|
|
347
|
|
|
// nette |
348
|
|
|
if ($class instanceof Entity) { |
349
|
|
|
if (isset($service['arguments']) && !empty($class->attributes)) { |
350
|
|
|
throw new InvalidArgumentException(sprintf('Duplicated definition of arguments for service "%s" in "%s". Check you NEON syntax.', $id, $file)); |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
$service['arguments'] = $class->attributes; |
354
|
|
|
$class = $class->value; |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
$definition->setClass($class); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
View Code Duplication |
private function processFactory($id, array &$service, Definition $definition, $file) |
|
|
|
|
361
|
|
|
{ |
362
|
|
|
if (!isset($service['factory'])) { |
363
|
|
|
return; |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
$factory = $service['factory']; |
367
|
|
|
|
368
|
|
|
//nette |
369
|
|
|
if ($factory instanceof Entity) { |
370
|
|
|
if (isset($service['arguments']) && !empty($factory->attributes)) { |
371
|
|
|
throw new InvalidArgumentException(sprintf('Duplicated definition of arguments for service "%s" in "%s". Check you NEON syntax.', $id, $file)); |
372
|
|
|
} |
373
|
|
|
|
374
|
|
|
$service['arguments'] = $factory->attributes; |
375
|
|
|
$factory = $factory->value; |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
$definition->setFactory($this->parseFactory($factory, $file)); |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
private function processArguments(array &$service, Definition $definition, $file) |
382
|
|
|
{ |
383
|
|
|
if (!isset($service['arguments'])) { |
384
|
|
|
return; |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
$autowired = false; |
388
|
|
|
array_walk($service['arguments'], function (&$value) use (&$autowired) { |
389
|
|
|
if ('...' === $value) { |
390
|
|
|
$value = ''; |
391
|
|
|
$autowired = true; |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
return $value; |
395
|
|
|
}); |
396
|
|
|
|
397
|
|
|
$definition->setAutowired($autowired); |
398
|
|
|
$definition->setArguments($this->resolveServices($service['arguments'], $file)); |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
private function processSetup(array &$service) |
402
|
|
|
{ |
403
|
|
|
if (!isset($service['setup'])) { |
404
|
|
|
return; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
foreach ($service['setup'] as $setup) { |
408
|
|
|
if ($setup instanceof Entity) { |
409
|
|
|
$name = $setup->value; |
410
|
|
|
$args = $setup->attributes; |
411
|
|
|
} elseif (is_array($setup)) { |
412
|
|
|
$name = $setup[0]; |
413
|
|
|
$args = isset($setup[1]) ? $setup[1] : []; |
414
|
|
|
} else { |
415
|
|
|
$name = $setup; |
416
|
|
|
$args = []; |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
if ('$' === $name[0]) { |
420
|
|
|
$service['properties'][substr($name, 1)] = $args; |
421
|
|
|
} else { |
422
|
|
|
$service['calls'][] = [$name, $args]; |
423
|
|
|
} |
424
|
|
|
} |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
private function processCalls($id, array &$service, Definition $definition, $file) |
428
|
|
|
{ |
429
|
|
|
if (!isset($service['calls'])) { |
430
|
|
|
return; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
if (!is_array($service['calls'])) { |
434
|
|
|
throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in %s. Check your NEON syntax.', $id, $file)); |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
foreach ($service['calls'] as $call) { |
438
|
|
|
if ($call instanceof Entity) { // nette |
439
|
|
|
$method = $call->value; |
440
|
|
|
$args = $this->resolveServices($call->attributes, $file); |
441
|
|
|
} elseif (isset($call['method'])) { |
442
|
|
|
$method = $call['method']; |
443
|
|
|
$args = isset($call['arguments']) ? $this->resolveServices($call['arguments'], $file) : []; |
444
|
|
|
} elseif (is_array($call)) { |
445
|
|
|
$method = $call[0]; |
446
|
|
|
$args = isset($call[1]) ? $this->resolveServices($call[1], $file) : []; |
447
|
|
|
} else { // nette |
448
|
|
|
$method = $call; |
449
|
|
|
$args = []; |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
$definition->addMethodCall($method, $args); |
453
|
|
|
} |
454
|
|
|
} |
455
|
|
|
|
456
|
|
|
private function processTags($id, array &$service, Definition $definition, $file) |
457
|
|
|
{ |
458
|
|
|
if (!isset($service['tags'])) { |
459
|
|
|
return; |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
if (!is_array($service['tags'])) { |
463
|
|
|
throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s. Check your NEON syntax.', $id, $file)); |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
foreach ($service['tags'] as $tag) { |
467
|
|
|
if ($tag instanceof Entity) { |
468
|
|
|
$tag = ['name' => $tag->value] + $tag->attributes; |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
if (is_string($tag)) { |
472
|
|
|
$tag = ['name' => $tag]; |
473
|
|
|
} |
474
|
|
|
|
475
|
|
|
if (!is_array($tag)) { |
476
|
|
|
throw new InvalidArgumentException(sprintf('A "tags" entry must be an array for service "%s" in %s. Check your NEON syntax.', $id, $file)); |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
if (!isset($tag['name'])) { |
480
|
|
|
throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file)); |
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
if (!is_string($tag['name']) || '' === $tag['name']) { |
484
|
|
|
throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', $id, $file)); |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
$name = $tag['name']; |
488
|
|
|
unset($tag['name']); |
489
|
|
|
|
490
|
|
|
foreach ($tag as $attribute => $value) { |
491
|
|
|
if (!is_scalar($value) && null !== $value) { |
492
|
|
|
throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s" in %s. Check your NEON syntax.', $id, $name, $attribute, $file)); |
493
|
|
|
} |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
$definition->addTag($name, $tag); |
497
|
|
|
} |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
private function processAutowire($id, array &$service, Definition $definition, $file) |
501
|
|
|
{ |
502
|
|
|
// nette |
503
|
|
View Code Duplication |
if (isset($service['autowired'])) { |
|
|
|
|
504
|
|
|
if (isset($service['autowire']) && $service['autowire'] !== $service['autowired']) { |
505
|
|
|
throw new InvalidArgumentException(sprintf('Contradictory definition of autowiring for service "%s" in "%s". Check you NEON syntax.', $id, $file)); |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
$service['autowire'] = $service['autowired']; |
509
|
|
|
} |
510
|
|
|
|
511
|
|
|
if (isset($service['autowire'])) { |
512
|
|
|
// nette |
513
|
|
|
if ($definition->isAutowired() && !$service['autowire']) { |
514
|
|
|
throw new InvalidArgumentException(sprintf('Contradictory definition of autowiring for service "%s" in "%s". Check you NEON syntax.', $id, $file)); |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
$definition->setAutowired($service['autowire']); |
518
|
|
|
} |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
private function processAutowiringTypes($id, array &$service, Definition $definition, $file) |
522
|
|
|
{ |
523
|
|
|
if (!isset($service['autowiring_types'])) { |
524
|
|
|
return; |
525
|
|
|
} |
526
|
|
|
|
527
|
|
|
if (is_string($service['autowiring_types'])) { |
528
|
|
|
$definition->addAutowiringType($service['autowiring_types']); |
529
|
|
|
return; |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
if (!is_array($service['autowiring_types'])) { |
533
|
|
|
throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be a string or an array for service "%s" in %s. Check your NEON syntax.', $id, $file)); |
534
|
|
|
} |
535
|
|
|
|
536
|
|
|
foreach ($service['autowiring_types'] as $autowiringType) { |
537
|
|
|
if (!is_string($autowiringType)) { |
538
|
|
|
throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your NEON syntax.', $id, $file)); |
539
|
|
|
} |
540
|
|
|
|
541
|
|
|
$definition->addAutowiringType($autowiringType); |
542
|
|
|
} |
543
|
|
|
} |
544
|
|
|
|
545
|
|
|
private function parseFactory($factory, $file) |
546
|
|
|
{ |
547
|
|
|
if (!is_string($factory)) { |
548
|
|
|
return [$this->resolveServices($factory[0], $file), $factory[1]]; |
549
|
|
|
} |
550
|
|
|
|
551
|
|
|
if (false === strpos($factory, ':')) { |
552
|
|
|
return $factory; |
553
|
|
|
} |
554
|
|
|
|
555
|
|
|
$parts = explode(':', $factory, 2); |
556
|
|
|
|
557
|
|
|
if (':' === $parts[1][0]) { |
558
|
|
|
return ['@' === $parts[0][0] ? $this->resolveServices($parts[0], $file) : $parts[0], substr($parts[1], 1)]; |
559
|
|
|
} |
560
|
|
|
|
561
|
|
|
return [$this->resolveServices(('@' === $parts[0][0] ?: '@').$parts[0], $file), $parts[1]]; |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
private function resolveServices($value, $file) |
565
|
|
|
{ |
566
|
|
|
// nette |
567
|
|
|
if ($value instanceof Entity) { |
568
|
|
|
if ('expression' === $value->value || 'expr' === $value->value) { |
569
|
|
|
return new Expression(reset($value->attributes)); |
570
|
|
|
} elseif (0 === strpos($value->value, '@')) { |
571
|
|
|
$value = $value->value; |
572
|
|
|
} else { |
573
|
|
|
$id = $this->generateAnonymousServiceId($file); |
574
|
|
|
$this->parseDefinition($id, $value, $file); |
575
|
|
|
$value = new Reference($id); |
576
|
|
|
} |
577
|
|
|
} |
578
|
|
|
|
579
|
|
|
if (is_array($value)) { |
580
|
|
|
$value = array_map(function ($value) use ($file) { |
581
|
|
|
return $this->resolveServices($value, $file); |
582
|
|
|
}, $value); |
583
|
|
|
} elseif (is_string($value) && 0 === strpos($value, '@=')) { |
584
|
|
|
return new Expression(substr($value, 2)); |
585
|
|
|
} elseif (is_string($value) && 0 === strpos($value, '@')) { |
586
|
|
|
if (0 === strpos($value, '@@')) { |
587
|
|
|
$value = substr($value, 1); |
588
|
|
|
$invalidBehavior = null; |
589
|
|
|
} elseif (0 === strpos($value, '@?')) { |
590
|
|
|
$value = substr($value, 2); |
591
|
|
|
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; |
592
|
|
|
} else { |
593
|
|
|
$value = substr($value, 1); |
594
|
|
|
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; |
595
|
|
|
} |
596
|
|
|
|
597
|
|
|
if ('=' === substr($value, -1)) { |
598
|
|
|
$value = substr($value, 0, -1); |
599
|
|
|
} |
600
|
|
|
|
601
|
|
|
if (null !== $invalidBehavior) { |
602
|
|
|
$value = new Reference($value, $invalidBehavior); |
603
|
|
|
} |
604
|
|
|
} |
605
|
|
|
|
606
|
|
|
return $value; |
607
|
|
|
} |
608
|
|
|
|
609
|
|
|
private function loadFromExtensions($content) |
610
|
|
|
{ |
611
|
|
|
foreach ($content as $namespace => $values) { |
612
|
|
|
// nette |
613
|
|
|
if (in_array($namespace, ['imports', 'includes', 'parameters', 'services'])) { |
614
|
|
|
continue; |
615
|
|
|
} |
616
|
|
|
|
617
|
|
|
if (!is_array($values)) { |
618
|
|
|
$values = []; |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
$this->container->loadFromExtension($namespace, $values); |
622
|
|
|
} |
623
|
|
|
} |
624
|
|
|
|
625
|
|
|
private function generateAnonymousServiceId($file) |
626
|
|
|
{ |
627
|
|
|
return sprintf('%s_%d', hash('sha256', $file), ++$this->anonymousServicesCount); |
628
|
|
|
} |
629
|
|
|
|
630
|
|
|
private function checkDefinition($id, array $definition, $file) |
631
|
|
|
{ |
632
|
|
|
if (!is_array($definition)) { |
633
|
|
|
throw new InvalidArgumentException(sprintf('A service definition must be an array or a string starting with "@" or a NEON entity but %s found for service "%s" in %s. Check your NEON syntax.', gettype($definition), $id, $file)); |
634
|
|
|
} |
635
|
|
|
|
636
|
|
|
foreach ($definition as $key => $value) { |
637
|
|
|
if (!isset(self::$keywords[$key])) { |
638
|
|
|
throw new InvalidArgumentException(sprintf('The configuration key "%s" is unsupported for service definition "%s" in "%s". Allowed configuration keys are "%s".', $key, $id, $file, implode('", "', self::$keywords))); |
639
|
|
|
} |
640
|
|
|
} |
641
|
|
|
} |
642
|
|
|
} |
643
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.