Completed
Branch master (33bfe2)
by Martin
02:23
created

NeonFileLoader   F

Complexity

Total Complexity 143

Size/Duplication

Total Lines 543
Duplicated Lines 8.47 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 143
c 2
b 1
f 0
lcom 1
cbo 14
dl 46
loc 543
rs 2.6956

11 Methods

Rating   Name   Duplication   Size   Complexity  
A supports() 0 4 4
B load() 0 28 5
B loadFile() 0 22 5
C validate() 0 35 7
C parseImports() 6 39 13
A parseDefinitions() 0 14 4
F parseDefinition() 40 278 78
B parseFactory() 0 18 6
C resolveServices() 0 38 14
A loadFromExtensions() 0 15 4
A checkDefinition() 0 8 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like NeonFileLoader often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use NeonFileLoader, and based on these observations, apply Extract Interface, too.

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
    /**
57
     * {@inheritdoc}
58
     */
59
    public function supports($resource, $type = null)
60
    {
61
        return is_string($resource) && 'neon' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'neon' === $type);
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67
    public function load($resource, $type = null)
68
    {
69
        $path = $this->locator->locate($resource);
70
71
        $content = $this->loadFile($path);
72
73
        $this->container->addResource(new FileResource($path));
1 ignored issue
show
Bug introduced by
It seems like $path defined by $this->locator->locate($resource) on line 69 can also be of type array; however, Symfony\Component\Config...Resource::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
74
75
        if (null === $content) {
76
            return;
77
        }
78
79
        $this->parseImports($content, $path);
80
81
        if (isset($content['parameters'])) {
82
            if (!is_array($content['parameters'])) {
83
                throw new InvalidArgumentException(sprintf('The "parameters" key should contain an array in %s. Check your NEON syntax.', $resource));
84
            }
85
86
            foreach ($content['parameters'] as $key => $value) {
87
                $this->container->setParameter($key, $this->resolveServices($value));
88
            }
89
        }
90
91
        $this->loadFromExtensions($content);
92
93
        $this->parseDefinitions($content, $resource);
94
    }
95
96
    private function loadFile($file)
97
    {
98
        if (!class_exists('Nette\Neon\Neon')) {
99
            throw new RuntimeException('Unable to load NEON config files as the Nette Neon Component is not installed.');
100
        }
101
102
        if (!stream_is_local($file)) {
103
            throw new InvalidArgumentException(sprintf('This is not a local file "%s".', $file));
104
        }
105
106
        if (!file_exists($file)) {
107
            throw new InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file));
108
        }
109
110
        try {
111
            $configuration = Neon::decode(file_get_contents($file));
112
        } catch (\Exception $e) {
113
            throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid NEON.', $file), 0, $e);
114
        }
115
116
        return $this->validate($configuration, $file);
117
    }
118
119
    private function validate($content, $file)
120
    {
121
        if (null === $content) {
122
            return $content;
123
        }
124
125
        if (!is_array($content)) {
126
            throw new InvalidArgumentException(sprintf('The service file "%s" is not valid. It should contain an array. Check your NEON syntax.', $file));
127
        }
128
129
        foreach ($content as $namespace => $data) {
130
            if (in_array($namespace, ['imports', 'parameters', 'services'])) {
131
                continue;
132
            }
133
134
            if (!$this->container->hasExtension($namespace)) {
135
                $extensionNamespaces = array_filter(array_map(
136
                    function (ExtensionInterface $ext) {
137
                        return $ext->getAlias();
138
                    },
139
                    $this->container->getExtensions()
140
                ));
141
142
                throw new InvalidArgumentException(sprintf(
143
                    'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s',
144
                    $namespace,
145
                    $file,
146
                    $namespace,
147
                    $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
148
                ));
149
            }
150
        }
151
152
        return $content;
153
    }
154
155
    private function parseImports($content, $file)
156
    {
157
        // nette
158
        if (!isset($content['imports']) && !isset($content['includes'])) {
159
            return;
160
        }
161
162
        // nette
163
        if (isset($content['imports']) && isset($content['includes'])) {
164
            throw new InvalidArgumentException('The "imports" and "includes" keys cannot be used together. Checkyour NEON syntax.', $file);
165
        }
166
167 View Code Duplication
        if (isset($content['imports']) && !is_array($content['imports'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
168
            throw new InvalidArgumentException(sprintf('The "imports" key should contain an array in %s. Check your NEON syntax.', $file));
169
        }
170
171
        // nette
172 View Code Duplication
        if (isset($content['includes']) && !is_array($content['includes'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
173
            throw new InvalidArgumentException(sprintf('The "includes" key should contain an array in %s. Check your NEON syntax.', $file));
174
        }
175
176
        // nette
177
        $content = array_merge(['imports' => [], 'includes' => []], $content);
178
179
        foreach ($content['imports'] as $import) {
180
            if (!is_array($import)) {
181
                throw new InvalidArgumentException(sprintf('The values in the "imports" key should be arrays in %s. Check your NEON syntax.', $file));
182
            }
183
184
            $this->setCurrentDir(dirname($file));
185
            $this->import($import['resource'], null, isset($import['ignore_errors']) ? (bool) $import['ignore_errors'] : false, $file);
186
        }
187
188
        // nette
189
        foreach ($content['includes'] as $include) {
190
            $this->setCurrentDir(dirname($file));
191
            $this->import($include, null, false, $file);
192
        }
193
    }
194
195
    private function parseDefinitions($content, $file)
196
    {
197
        if (!isset($content['services'])) {
198
            return;
199
        }
200
201
        if (!is_array($content['services'])) {
202
            throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file));
203
        }
204
205
        foreach ($content['services'] as $id => $service) {
206
            $this->parseDefinition($id, $service, $file);
207
        }
208
    }
209
210
    private function parseDefinition($id, $service, $file)
211
    {
212
        // nette
213
        if ($service instanceof Entity) {
214
            $value = $service->value;
215
            $service = ['arguments' => $service->attributes];
216
            if (false === strpos($value, ':')) {
217
                $service['class'] = $value;
218
            } else {
219
                $service['factory'] = $value;
220
            }
221
        }
222
223
        // nette
224
        if (preg_match('#^(\S+)\s+<\s+(\S+)\z#', $id, $matches)) {
225 View Code Duplication
            if (isset($service['parent']) && $matches[2] !== $service['parent']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
226
                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));
227
            }
228
229
            $id = $matches[1];
230
            $parent = $matches[2];
231
        }
232
233
        // nette
234
        if (is_string($service) && false !== strpos($service, ':')) {
235
            $service = ['factory' => $this->parseFactory($service)];
236
        } elseif (is_string($service) && 0 === strpos($service, '@')) {
237
            $this->container->setAlias($id, substr($service, 1));
238
239
            return;
240
        } elseif (is_string($service)) {
241
            $service = ['class' => $service];
242
        }
243
244
        if (!is_array($service)) {
245
            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($service), $id, $file));
246
        }
247
248
        self::checkDefinition($id, $service, $file);
249
250
        if (isset($service['alias'])) {
251
            $public = !array_key_exists('public', $service) || (bool) $service['public'];
252
            $this->container->setAlias($id, new Alias($service['alias'], $public));
253
254
            foreach ($service as $key => $value) {
255
                if (!in_array($key, ['alias', 'public'])) {
256
                    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));
257
                }
258
            }
259
260
            return;
261
        }
262
263
        // nette
264
        if (isset($parent)) {
265
            $service['parent'] = $parent;
266
        }
267
268
        if (isset($service['parent'])) {
269
            $definition = new DefinitionDecorator($service['parent']);
270
        } else {
271
            $definition = new Definition();
272
        }
273
274 View Code Duplication
        if (isset($service['class'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
275
            $class = $service['class'];
276
277
            // nette
278
            if ($class instanceof Entity) {
279
                if (isset($service['arguments']) && !empty($class->attributes)) {
280
                    throw new InvalidArgumentException(sprintf('Duplicated definition of arguments for service "%s" in "%s". Check you NEON syntax.', $id, $file));
281
                }
282
283
                $service['arguments'] = $class->attributes;
284
                $class = $class->value;
285
            }
286
287
            $definition->setClass($class);
288
        }
289
290
        if (isset($service['shared'])) {
291
            $definition->setShared($service['shared']);
292
        }
293
294
        if (isset($service['synthetic'])) {
295
            $definition->setSynthetic($service['synthetic']);
296
        }
297
298
        if (isset($service['lazy'])) {
299
            $definition->setLazy($service['lazy']);
300
        }
301
302
        if (isset($service['public'])) {
303
            $definition->setPublic($service['public']);
304
        }
305
306
        if (isset($service['abstract'])) {
307
            $definition->setAbstract($service['abstract']);
308
        }
309
310
        if (array_key_exists('deprecated', $service)) {
311
            $definition->setDeprecated(true, $service['deprecated']);
312
        }
313
314 View Code Duplication
        if (isset($service['factory'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
315
            $factory = $service['factory'];
316
317
            //nette
318
            if ($factory instanceof Entity) {
319
                if (isset($service['arguments']) && !empty($factory->attributes)) {
320
                    throw new InvalidArgumentException(sprintf('Duplicated definition of arguments for service "%s" in "%s". Check you NEON syntax.', $id, $file));
321
                }
322
323
                $service['arguments'] = $factory->attributes;
324
                $factory = $factory->value;
325
            }
326
327
            $definition->setFactory($this->parseFactory($factory));
328
        }
329
330
        if (isset($service['file'])) {
331
            $definition->setFile($service['file']);
332
        }
333
334
        if (isset($service['arguments'])) {
335
            $autowired = false;
336
            array_walk($service['arguments'], function (&$value) use (&$autowired) {
337
                if ('...' === $value) {
338
                    $value = '';
339
                    $autowired = true;
340
                }
341
342
                return $value;
343
            });
344
345
            $definition->setAutowired($autowired);
346
            $definition->setArguments($this->resolveServices($service['arguments']));
347
        }
348
349
        // nette
350
        if (isset($service['setup'])) {
351
            foreach ($service['setup'] as $setup) {
352
                if ($setup instanceof Entity) {
353
                    $name = $setup->value;
354
                    $args = $setup->attributes;
355
                } elseif (is_array($setup)) {
356
                    $name = $setup[0];
357
                    $args = isset($setup[1]) ? $setup[1] : [];
358
                } else {
359
                    $name = $setup;
360
                    $args = [];
361
                }
362
363
                if ('$' === $name[0]) {
364
                    $service['properties'][substr($name, 1)] = $args;
365
                } else {
366
                    $service['calls'][] = [$name, $args];
367
                }
368
            }
369
        }
370
371
        if (isset($service['properties'])) {
372
            $definition->setProperties($this->resolveServices($service['properties']));
373
        }
374
375
        if (isset($service['configurator'])) {
376
            if (is_string($service['configurator'])) {
377
                $definition->setConfigurator($service['configurator']);
378
            } else {
379
                $definition->setConfigurator([$this->resolveServices($service['configurator'][0]), $service['configurator'][1]]);
380
            }
381
        }
382
383
        if (isset($service['calls'])) {
384
            if (!is_array($service['calls'])) {
385
                throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in %s. Check your NEON syntax.', $id, $file));
386
            }
387
388
            foreach ($service['calls'] as $call) {
389
                if ($call instanceof Entity) { // nette
390
                    $method = $call->value;
391
                    $args = $this->resolveServices($call->attributes);
392
                } elseif (isset($call['method'])) {
393
                    $method = $call['method'];
394
                    $args = isset($call['arguments']) ? $this->resolveServices($call['arguments']) : [];
395
                } elseif (is_array($call)) {
396
                    $method = $call[0];
397
                    $args = isset($call[1]) ? $this->resolveServices($call[1]) : [];
398
                } else { // nette
399
                    $method = $call;
400
                    $args = [];
401
                }
402
403
                $definition->addMethodCall($method, $args);
404
            }
405
        }
406
407
        if (isset($service['tags'])) {
408
            if (!is_array($service['tags'])) {
409
                throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s. Check your NEON syntax.', $id, $file));
410
            }
411
412
            foreach ($service['tags'] as $tag) {
413
                if ($tag instanceof Entity) {
414
                    $tag = ['name' => $tag->value] + $tag->attributes;
415
                } elseif (is_string($tag)) {
416
                    $tag = ['name' => $tag];
417
                }
418
419
                if (!is_array($tag)) {
420
                    throw new InvalidArgumentException(sprintf('A "tags" entry must be an array for service "%s" in %s. Check your NEON syntax.', $id, $file));
421
                }
422
423
                if (!isset($tag['name'])) {
424
                    throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
425
                }
426
427
                if (!is_string($tag['name']) || '' === $tag['name']) {
428
                    throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', $id, $file));
429
                }
430
431
                $name = $tag['name'];
432
                unset($tag['name']);
433
434
                foreach ($tag as $attribute => $value) {
435
                    if (!is_scalar($value) && null !== $value) {
436
                        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));
437
                    }
438
                }
439
440
                $definition->addTag($name, $tag);
441
            }
442
        }
443
444
        if (isset($service['decorates'])) {
445
            $renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null;
446
            $priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0;
447
            $definition->setDecoratedService($service['decorates'], $renameId, $priority);
448
        }
449
450
        // nette
451 View Code Duplication
        if (isset($service['autowired'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
452
            if (isset($service['autowire']) && $service['autowire'] !== $service['autowired']) {
453
                throw new InvalidArgumentException(sprintf('Contradictory definition of autowiring for service "%s" in "%s". Check you NEON syntax.', $id, $file));
454
            }
455
456
            $service['autowire'] = $service['autowired'];
457
        }
458
459
        if (isset($service['autowire'])) {
460
            // nette
461
            if ($definition->isAutowired() && !$service['autowire']) {
462
                throw new InvalidArgumentException(sprintf('Contradictory definition of autowiring for service "%s" in "%s". Check you NEON syntax.', $id, $file));
463
            }
464
465
            $definition->setAutowired($service['autowire']);
466
        }
467
468
        if (isset($service['autowiring_types'])) {
469
            if (is_string($service['autowiring_types'])) {
470
                $definition->addAutowiringType($service['autowiring_types']);
471
            } else {
472
                if (!is_array($service['autowiring_types'])) {
473
                    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));
474
                }
475
476
                foreach ($service['autowiring_types'] as $autowiringType) {
477
                    if (!is_string($autowiringType)) {
478
                        throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your NEON syntax.', $id, $file));
479
                    }
480
481
                    $definition->addAutowiringType($autowiringType);
482
                }
483
            }
484
        }
485
486
        $this->container->setDefinition($id, $definition);
487
    }
488
489
    private function parseFactory($factory)
490
    {
491
        if (is_string($factory)) {
492
            if (strpos($factory, '::') !== false) {
493
                $parts = explode('::', $factory, 2);
494
495
                return ['@' === $parts[0][0] ? $this->resolveServices($parts[0]) : $parts[0], $parts[1]];
496
            } elseif (strpos($factory, ':') !== false) {
497
                $parts = explode(':', $factory, 2);
498
499
                return [$this->resolveServices(('@' === $parts[0][0] ?: '@').$parts[0]), $parts[1]];
500
            } else {
501
                return $factory;
502
            }
503
        } else {
504
            return [$this->resolveServices($factory[0]), $factory[1]];
505
        }
506
    }
507
508
    private function resolveServices($value)
509
    {
510
        // nette
511
        if ($value instanceof Entity) {
512
            if ('expression' === $value->value || 'expr' === $value->value) {
513
                return new Expression(reset($value->attributes));
514
            } elseif (0 === strpos($value->value, '@')) {
515
                $value = $value->value;
516
            }
517
        }
518
519
        if (is_array($value)) {
520
            $value = array_map([$this, 'resolveServices'], $value);
521
        } elseif (is_string($value) &&  0 === strpos($value, '@=')) {
522
            return new Expression(substr($value, 2));
523
        } elseif (is_string($value) &&  0 === strpos($value, '@')) {
524
            if (0 === strpos($value, '@@')) {
525
                $value = substr($value, 1);
526
                $invalidBehavior = null;
527
            } elseif (0 === strpos($value, '@?')) {
528
                $value = substr($value, 2);
529
                $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
530
            } else {
531
                $value = substr($value, 1);
532
                $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
533
            }
534
535
            if ('=' === substr($value, -1)) {
536
                $value = substr($value, 0, -1);
537
            }
538
539
            if (null !== $invalidBehavior) {
540
                $value = new Reference($value, $invalidBehavior);
541
            }
542
        }
543
544
        return $value;
545
    }
546
547
    private function loadFromExtensions($content)
548
    {
549
        foreach ($content as $namespace => $values) {
550
            // nette
551
            if (in_array($namespace, ['imports', 'includes', 'parameters', 'services'])) {
552
                continue;
553
            }
554
555
            if (!is_array($values)) {
556
                $values = [];
557
            }
558
559
            $this->container->loadFromExtension($namespace, $values);
560
        }
561
    }
562
563
    private static function checkDefinition($id, array $definition, $file)
564
    {
565
        foreach ($definition as $key => $value) {
566
            if (!isset(self::$keywords[$key])) {
567
                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)));
568
            }
569
        }
570
    }
571
}
572