Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
XmlFileLoader.php
001 <?php
002
003 /*
004 * This file is part of the Symfony package.
005 *
006 * (c) Fabien Potencier <fabien@symfony.com>
007 *
008 * For the full copyright and license information, please view the LICENSE
009 * file that was distributed with this source code.
010 */
011
012 namespace Symfony\Component\DependencyInjection\Loader;
013
014 use Symfony\Component\Config\Util\XmlUtils;
015 use Symfony\Component\DependencyInjection\Alias;
016 use Symfony\Component\DependencyInjection\Argument\BoundArgument;
017 use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
018 use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
019 use Symfony\Component\DependencyInjection\ChildDefinition;
020 use Symfony\Component\DependencyInjection\ContainerBuilder;
021 use Symfony\Component\DependencyInjection\ContainerInterface;
022 use Symfony\Component\DependencyInjection\Definition;
023 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
024 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
025 use Symfony\Component\DependencyInjection\Reference;
026 use Symfony\Component\ExpressionLanguage\Expression;
027
028 /**
029 * XmlFileLoader loads XML files service definitions.
030 *
031 * @author Fabien Potencier <fabien@symfony.com>
032 */
033 class XmlFileLoader extends FileLoader
034 {
035 const NS = 'http://symfony.com/schema/dic/services';
036
037 /**
038 * {@inheritdoc}
039 */
040 public function load($resource, $type = null)
041 {
042 $path = $this->locator->locate($resource);
043
044 $xml = $this->parseFileToDOM($path);
045
046 $this->container->fileExists($path);
047
048 $defaults = $this->getServiceDefaults($xml, $path);
049
050 // anonymous services
051 $this->processAnonymousServices($xml, $path, $defaults);
052
053 // imports
054 $this->parseImports($xml, $path);
055
056 // parameters
057 $this->parseParameters($xml, $path);
058
059 // extensions
060 $this->loadFromExtensions($xml);
061
062 // services
063 try {
064 $this->parseDefinitions($xml, $path, $defaults);
065 } finally {
066 $this->instanceof = [];
067 }
068 }
069
070 /**
071 * {@inheritdoc}
072 */
073 public function supports($resource, $type = null)
074 {
075 if (!\is_string($resource)) {
076 return false;
077 }
078
079 if (null === $type && 'xml' === pathinfo($resource, \PATHINFO_EXTENSION)) {
080 return true;
081 }
082
083 return 'xml' === $type;
084 }
085
086 /**
087 * Parses parameters.
088 *
089 * @param string $file
090 */
091 private function parseParameters(\DOMDocument $xml, $file)
092 {
093 if ($parameters = $this->getChildren($xml->documentElement, 'parameters')) {
094 $this->container->getParameterBag()->add($this->getArgumentsAsPhp($parameters[0], 'parameter', $file));
095 }
096 }
097
098 /**
099 * Parses imports.
100 *
101 * @param string $file
102 */
103 private function parseImports(\DOMDocument $xml, $file)
104 {
105 $xpath = new \DOMXPath($xml);
106 $xpath->registerNamespace('container', self::NS);
107
108 if (false === $imports = $xpath->query('//container:imports/container:import')) {
109 return;
110 }
111
112 $defaultDirectory = \dirname($file);
113 foreach ($imports as $import) {
114 $this->setCurrentDir($defaultDirectory);
115 $this->import($import->getAttribute('resource'), XmlUtils::phpize($import->getAttribute('type')) ?: null, (bool) XmlUtils::phpize($import->getAttribute('ignore-errors')), $file);
116 }
117 }
118
119 /**
120 * Parses multiple definitions.
121 *
122 * @param string $file
123 */
124 private function parseDefinitions(\DOMDocument $xml, $file, $defaults)
125 {
126 $xpath = new \DOMXPath($xml);
127 $xpath->registerNamespace('container', self::NS);
128
129 if (false === $services = $xpath->query('//container:services/container:service|//container:services/container:prototype')) {
130 return;
131 }
132 $this->setCurrentDir(\dirname($file));
133
134 $this->instanceof = [];
135 $this->isLoadingInstanceof = true;
136 $instanceof = $xpath->query('//container:services/container:instanceof');
137 foreach ($instanceof as $service) {
138 $this->setDefinition((string) $service->getAttribute('id'), $this->parseDefinition($service, $file, []));
139 }
140
141 $this->isLoadingInstanceof = false;
142 foreach ($services as $service) {
143 if (null !== $definition = $this->parseDefinition($service, $file, $defaults)) {
144 if ('prototype' === $service->tagName) {
145 $this->registerClasses($definition, (string) $service->getAttribute('namespace'), (string) $service->getAttribute('resource'), (string) $service->getAttribute('exclude'));
146 } else {
147 $this->setDefinition((string) $service->getAttribute('id'), $definition);
148 }
149 }
150 }
151 }
152
153 /**
154 * Get service defaults.
155 *
156 * @return array
157 */
158 private function getServiceDefaults(\DOMDocument $xml, $file)
159 {
160 $xpath = new \DOMXPath($xml);
161 $xpath->registerNamespace('container', self::NS);
162
163 if (null === $defaultsNode = $xpath->query('//container:services/container:defaults')->item(0)) {
164 return [];
165 }
166 $defaults = [
167 'tags' => $this->getChildren($defaultsNode, 'tag'),
168 'bind' => array_map(function ($v) { return new BoundArgument($v); }, $this->getArgumentsAsPhp($defaultsNode, 'bind', $file)),
169 ];
170
171 foreach ($defaults['tags'] as $tag) {
172 if ('' === $tag->getAttribute('name')) {
173 throw new InvalidArgumentException(sprintf('The tag name for tag "<defaults>" in "%s" must be a non-empty string.', $file));
174 }
175 }
176
177 if ($defaultsNode->hasAttribute('autowire')) {
178 $defaults['autowire'] = XmlUtils::phpize($defaultsNode->getAttribute('autowire'));
179 }
180 if ($defaultsNode->hasAttribute('public')) {
181 $defaults['public'] = XmlUtils::phpize($defaultsNode->getAttribute('public'));
182 }
183 if ($defaultsNode->hasAttribute('autoconfigure')) {
184 $defaults['autoconfigure'] = XmlUtils::phpize($defaultsNode->getAttribute('autoconfigure'));
185 }
186
187 return $defaults;
188 }
189
190 /**
191 * Parses an individual Definition.
192 *
193 * @param string $file
194 *
195 * @return Definition|null
196 */
197 private function parseDefinition(\DOMElement $service, $file, array $defaults)
198 {
199 if ($alias = $service->getAttribute('alias')) {
200 $this->validateAlias($service, $file);
201
202 $this->container->setAlias((string) $service->getAttribute('id'), $alias = new Alias($alias));
203 if ($publicAttr = $service->getAttribute('public')) {
204 $alias->setPublic(XmlUtils::phpize($publicAttr));
205 } elseif (isset($defaults['public'])) {
206 $alias->setPublic($defaults['public']);
207 }
208
209 return null;
210 }
211
212 if ($this->isLoadingInstanceof) {
213 $definition = new ChildDefinition('');
214 } elseif ($parent = $service->getAttribute('parent')) {
215 if (!empty($this->instanceof)) {
216 throw new InvalidArgumentException(sprintf('The service "%s" cannot use the "parent" option in the same file where "instanceof" configuration is defined as using both is not supported. Move your child definitions to a separate file.', $service->getAttribute('id')));
217 }
218
219 foreach ($defaults as $k => $v) {
220 if ('tags' === $k) {
221 // since tags are never inherited from parents, there is no confusion
222 // thus we can safely add them as defaults to ChildDefinition
223 continue;
224 }
225 if ('bind' === $k) {
226 if ($defaults['bind']) {
227 throw new InvalidArgumentException(sprintf('Bound values on service "%s" cannot be inherited from "defaults" when a "parent" is set. Move your child definitions to a separate file.', $service->getAttribute('id')));
228 }
229
230 continue;
231 }
232 if (!$service->hasAttribute($k)) {
233 throw new InvalidArgumentException(sprintf('Attribute "%s" on service "%s" cannot be inherited from "defaults" when a "parent" is set. Move your child definitions to a separate file or define this attribute explicitly.', $k, $service->getAttribute('id')));
234 }
235 }
236
237 $definition = new ChildDefinition($parent);
238 } else {
239 $definition = new Definition();
240
241 if (isset($defaults['public'])) {
242 $definition->setPublic($defaults['public']);
243 }
244 if (isset($defaults['autowire'])) {
245 $definition->setAutowired($defaults['autowire']);
246 }
247 if (isset($defaults['autoconfigure'])) {
248 $definition->setAutoconfigured($defaults['autoconfigure']);
249 }
250
251 $definition->setChanges([]);
252 }
253
254 foreach (['class', 'public', 'shared', 'synthetic', 'lazy', 'abstract'] as $key) {
255 if ($value = $service->getAttribute($key)) {
256 $method = 'set'.$key;
257 $definition->$method(XmlUtils::phpize($value));
258 }
259 }
260
261 if ($value = $service->getAttribute('autowire')) {
262 $definition->setAutowired(XmlUtils::phpize($value));
263 }
264
265 if ($value = $service->getAttribute('autoconfigure')) {
266 if (!$definition instanceof ChildDefinition) {
267 $definition->setAutoconfigured(XmlUtils::phpize($value));
268 } elseif ($value = XmlUtils::phpize($value)) {
269 throw new InvalidArgumentException(sprintf('The service "%s" cannot have a "parent" and also have "autoconfigure". Try setting autoconfigure="false" for the service.', $service->getAttribute('id')));
270 }
271 }
272
273 if ($files = $this->getChildren($service, 'file')) {
274 $definition->setFile($files[0]->nodeValue);
275 }
276
277 if ($deprecated = $this->getChildren($service, 'deprecated')) {
278 $definition->setDeprecated(true, $deprecated[0]->nodeValue ?: null);
279 }
280
281 $definition->setArguments($this->getArgumentsAsPhp($service, 'argument', $file, $definition instanceof ChildDefinition));
282 $definition->setProperties($this->getArgumentsAsPhp($service, 'property', $file));
283
284 if ($factories = $this->getChildren($service, 'factory')) {
285 $factory = $factories[0];
286 if ($function = $factory->getAttribute('function')) {
287 $definition->setFactory($function);
288 } else {
289 if ($childService = $factory->getAttribute('service')) {
290 $class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
291 } else {
292 $class = $factory->hasAttribute('class') ? $factory->getAttribute('class') : null;
293 }
294
295 $definition->setFactory([$class, $factory->getAttribute('method')]);
296 }
297 }
298
299 if ($configurators = $this->getChildren($service, 'configurator')) {
300 $configurator = $configurators[0];
301 if ($function = $configurator->getAttribute('function')) {
302 $definition->setConfigurator($function);
303 } else {
304 if ($childService = $configurator->getAttribute('service')) {
305 $class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
306 } else {
307 $class = $configurator->getAttribute('class');
308 }
309
310 $definition->setConfigurator([$class, $configurator->getAttribute('method')]);
311 }
312 }
313
314 foreach ($this->getChildren($service, 'call') as $call) {
315 $definition->addMethodCall($call->getAttribute('method'), $this->getArgumentsAsPhp($call, 'argument', $file));
316 }
317
318 $tags = $this->getChildren($service, 'tag');
319
320 if (!empty($defaults['tags'])) {
321 $tags = array_merge($tags, $defaults['tags']);
322 }
323
324 foreach ($tags as $tag) {
325 $parameters = [];
326 foreach ($tag->attributes as $name => $node) {
327 if ('name' === $name) {
328 continue;
329 }
330
331 if (false !== strpos($name, '-') && false === strpos($name, '_') && !\array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) {
332 $parameters[$normalizedName] = XmlUtils::phpize($node->nodeValue);
333 }
334 // keep not normalized key
335 $parameters[$name] = XmlUtils::phpize($node->nodeValue);
336 }
337
338 if ('' === $tag->getAttribute('name')) {
339 throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', (string) $service->getAttribute('id'), $file));
340 }
341
342 $definition->addTag($tag->getAttribute('name'), $parameters);
343 }
344
345 foreach ($this->getChildren($service, 'autowiring-type') as $type) {
346 $definition->addAutowiringType($type->textContent);
347 }
348
349 $bindings = $this->getArgumentsAsPhp($service, 'bind', $file);
350 if (isset($defaults['bind'])) {
351 // deep clone, to avoid multiple process of the same instance in the passes
352 $bindings = array_merge(unserialize(serialize($defaults['bind'])), $bindings);
353 }
354 if ($bindings) {
355 $definition->setBindings($bindings);
356 }
357
358 if ($value = $service->getAttribute('decorates')) {
359 $renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null;
360 $priority = $service->hasAttribute('decoration-priority') ? $service->getAttribute('decoration-priority') : 0;
361 $definition->setDecoratedService($value, $renameId, $priority);
362 }
363
364 return $definition;
365 }
366
367 /**
368 * Parses a XML file to a \DOMDocument.
369 *
370 * @param string $file Path to a file
371 *
372 * @return \DOMDocument
373 *
374 * @throws InvalidArgumentException When loading of XML file returns error
375 */
376 private function parseFileToDOM($file)
377 {
378 try {
379 $dom = XmlUtils::loadFile($file, [$this, 'validateSchema']);
380 } catch (\InvalidArgumentException $e) {
381 throw new InvalidArgumentException(sprintf('Unable to parse file "%s": ', $file).$e->getMessage(), $e->getCode(), $e);
382 }
383
384 $this->validateExtensions($dom, $file);
385
386 return $dom;
387 }
388
389 /**
390 * Processes anonymous services.
391 *
392 * @param string $file
393 * @param array $defaults
394 */
395 private function processAnonymousServices(\DOMDocument $xml, $file, $defaults)
396 {
397 $definitions = [];
398 $count = 0;
399 $suffix = '~'.ContainerBuilder::hash($file);
400
401 $xpath = new \DOMXPath($xml);
402 $xpath->registerNamespace('container', self::NS);
403
404 // anonymous services as arguments/properties
405 if (false !== $nodes = $xpath->query('//container:argument[@type="service"][not(@id)]|//container:property[@type="service"][not(@id)]|//container:bind[not(@id)]|//container:factory[not(@service)]|//container:configurator[not(@service)]')) {
406 foreach ($nodes as $node) {
407 if ($services = $this->getChildren($node, 'service')) {
408 // give it a unique name
409 $id = sprintf('%d_%s', ++$count, preg_replace('/^.*\\\\/', '', $services[0]->getAttribute('class')).$suffix);
410 $node->setAttribute('id', $id);
411 $node->setAttribute('service', $id);
412
413 $definitions[$id] = [$services[0], $file, false];
414 $services[0]->setAttribute('id', $id);
415
416 // anonymous services are always private
417 // we could not use the constant false here, because of XML parsing
418 $services[0]->setAttribute('public', 'false');
419 }
420 }
421 }
422
423 // anonymous services "in the wild"
424 if (false !== $nodes = $xpath->query('//container:services/container:service[not(@id)]')) {
425 foreach ($nodes as $node) {
426 @trigger_error(sprintf('Top-level anonymous services are deprecated since Symfony 3.4, the "id" attribute will be required in version 4.0 in %s at line %d.', $file, $node->getLineNo()), \E_USER_DEPRECATED);
427
428 // give it a unique name
429 $id = sprintf('%d_%s', ++$count, preg_replace('/^.*\\\\/', '', $node->getAttribute('class')).$suffix);
430 $node->setAttribute('id', $id);
431 $definitions[$id] = [$node, $file, true];
432 }
433 }
434
435 // resolve definitions
436 uksort($definitions, 'strnatcmp');
437 foreach (array_reverse($definitions) as $id => list($domElement, $file, $wild)) {
438 if (null !== $definition = $this->parseDefinition($domElement, $file, $wild ? $defaults : [])) {
439 $this->setDefinition($id, $definition);
440 }
441
442 if (true === $wild) {
443 $tmpDomElement = new \DOMElement('_services', null, self::NS);
444 $domElement->parentNode->replaceChild($tmpDomElement, $domElement);
445 $tmpDomElement->setAttribute('id', $id);
446 }
447 }
448 }
449
450 /**
451 * Returns arguments as valid php types.
452 *
453 * @param string $name
454 * @param string $file
455 *
456 * @return mixed
457 */
458 private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $isChildDefinition = false)
459 {
460 $arguments = [];
461 foreach ($this->getChildren($node, $name) as $arg) {
462 if ($arg->hasAttribute('name')) {
463 $arg->setAttribute('key', $arg->getAttribute('name'));
464 }
465
466 // this is used by ChildDefinition to overwrite a specific
467 // argument of the parent definition
468 if ($arg->hasAttribute('index')) {
469 $key = ($isChildDefinition ? 'index_' : '').$arg->getAttribute('index');
470 } elseif (!$arg->hasAttribute('key')) {
471 // Append an empty argument, then fetch its key to overwrite it later
472 $arguments[] = null;
473 $keys = array_keys($arguments);
474 $key = array_pop($keys);
475 } else {
476 $key = $arg->getAttribute('key');
477 }
478
479 $onInvalid = $arg->getAttribute('on-invalid');
480 $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
481 if ('ignore' == $onInvalid) {
482 $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
483 } elseif ('ignore_uninitialized' == $onInvalid) {
484 $invalidBehavior = ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE;
485 } elseif ('null' == $onInvalid) {
486 $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
487 }
488
489 switch ($arg->getAttribute('type')) {
490 case 'service':
491 if ('' === $arg->getAttribute('id')) {
492 throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service" has no or empty "id" attribute in "%s".', $name, $file));
493 }
494 if ($arg->hasAttribute('strict')) {
495 @trigger_error(sprintf('The "strict" attribute used when referencing the "%s" service is deprecated since Symfony 3.3 and will be removed in 4.0.', $arg->getAttribute('id')), \E_USER_DEPRECATED);
496 }
497
498 $arguments[$key] = new Reference($arg->getAttribute('id'), $invalidBehavior);
499 break;
500 case 'expression':
501 if (!class_exists(Expression::class)) {
502 throw new \LogicException(sprintf('The type="expression" attribute cannot be used without the ExpressionLanguage component. Try running "composer require symfony/expression-language".'));
503 }
504
505 $arguments[$key] = new Expression($arg->nodeValue);
506 break;
507 case 'collection':
508 $arguments[$key] = $this->getArgumentsAsPhp($arg, $name, $file);
509 break;
510 case 'iterator':
511 $arg = $this->getArgumentsAsPhp($arg, $name, $file);
512 try {
513 $arguments[$key] = new IteratorArgument($arg);
514 } catch (InvalidArgumentException $e) {
515 throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="iterator" only accepts collections of type="service" references in "%s".', $name, $file));
516 }
517 break;
518 case 'tagged':
519 if (!$arg->getAttribute('tag')) {
520 throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file));
521 }
522 $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'));
523 break;
524 case 'string':
525 $arguments[$key] = $arg->nodeValue;
526 break;
527 case 'constant':
528 $arguments[$key] = \constant(trim($arg->nodeValue));
529 break;
530 default:
531 $arguments[$key] = XmlUtils::phpize($arg->nodeValue);
532 }
533 }
534
535 return $arguments;
536 }
537
538 /**
539 * Get child elements by name.
540 *
541 * @param mixed $name
542 *
543 * @return \DOMElement[]
544 */
545 private function getChildren(\DOMNode $node, $name)
546 {
547 $children = [];
548 foreach ($node->childNodes as $child) {
549 if ($child instanceof \DOMElement && $child->localName === $name && self::NS === $child->namespaceURI) {
550 $children[] = $child;
551 }
552 }
553
554 return $children;
555 }
556
557 /**
558 * Validates a documents XML schema.
559 *
560 * @return bool
561 *
562 * @throws RuntimeException When extension references a non-existent XSD file
563 */
564 public function validateSchema(\DOMDocument $dom)
565 {
566 $schemaLocations = ['http://symfony.com/schema/dic/services' => str_replace('\\', '/', __DIR__.'/schema/dic/services/services-1.0.xsd')];
567
568 if ($element = $dom->documentElement->getAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation')) {
569 $items = preg_split('/\s+/', $element);
570 for ($i = 0, $nb = \count($items); $i < $nb; $i += 2) {
571 if (!$this->container->hasExtension($items[$i])) {
572 continue;
573 }
574
575 if (($extension = $this->container->getExtension($items[$i])) && false !== $extension->getXsdValidationBasePath()) {
576 $ns = $extension->getNamespace();
577 $path = str_replace([$ns, str_replace('http://', 'https://', $ns)], str_replace('\\', '/', $extension->getXsdValidationBasePath()).'/', $items[$i + 1]);
578
579 if (!is_file($path)) {
580 throw new RuntimeException(sprintf('Extension "%s" references a non-existent XSD file "%s".', \get_class($extension), $path));
581 }
582
583 $schemaLocations[$items[$i]] = $path;
584 }
585 }
586 }
587
588 $tmpfiles = [];
589 $imports = '';
590 foreach ($schemaLocations as $namespace => $location) {
591 $parts = explode('/', $location);
592 $locationstart = 'file:///';
593 if (0 === stripos($location, 'phar://')) {
594 $tmpfile = tempnam(sys_get_temp_dir(), 'symfony');
595 if ($tmpfile) {
596 copy($location, $tmpfile);
597 $tmpfiles[] = $tmpfile;
598 $parts = explode('/', str_replace('\\', '/', $tmpfile));
599 } else {
600 array_shift($parts);
601 $locationstart = 'phar:///';
602 }
603 }
604 $drive = '\\' === \DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
605 $location = $locationstart.$drive.implode('/', array_map('rawurlencode', $parts));
606
607 $imports .= sprintf(' <xsd:import namespace="%s" schemaLocation="%s" />'."\n", $namespace, $location);
608 }
609
610 $source = <<<EOF
611 <?xml version="1.0" encoding="utf-8" ?>
612 <xsd:schema xmlns="http://symfony.com/schema"
613 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
614 targetNamespace="http://symfony.com/schema"
615 elementFormDefault="qualified">
616
617 <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
618 $imports
619 </xsd:schema>
620 EOF
621 ;
622
623 if (\LIBXML_VERSION < 20900) {
624 $disableEntities = libxml_disable_entity_loader(false);
625 $valid = @$dom->schemaValidateSource($source);
626 libxml_disable_entity_loader($disableEntities);
627 } else {
628 $valid = @$dom->schemaValidateSource($source);
629 }
630
631 foreach ($tmpfiles as $tmpfile) {
632 @unlink($tmpfile);
633 }
634
635 return $valid;
636 }
637
638 /**
639 * Validates an alias.
640 *
641 * @param string $file
642 */
643 private function validateAlias(\DOMElement $alias, $file)
644 {
645 foreach ($alias->attributes as $name => $node) {
646 if (!\in_array($name, ['alias', 'id', 'public'])) {
647 @trigger_error(sprintf('Using the attribute "%s" is deprecated for the service "%s" which is defined as an alias in "%s". Allowed attributes for service aliases are "alias", "id" and "public". The XmlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported attributes.', $name, $alias->getAttribute('id'), $file), \E_USER_DEPRECATED);
648 }
649 }
650
651 foreach ($alias->childNodes as $child) {
652 if ($child instanceof \DOMElement && self::NS === $child->namespaceURI) {
653 @trigger_error(sprintf('Using the element "%s" is deprecated for the service "%s" which is defined as an alias in "%s". The XmlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported elements.', $child->localName, $alias->getAttribute('id'), $file), \E_USER_DEPRECATED);
654 }
655 }
656 }
657
658 /**
659 * Validates an extension.
660 *
661 * @param string $file
662 *
663 * @throws InvalidArgumentException When no extension is found corresponding to a tag
664 */
665 private function validateExtensions(\DOMDocument $dom, $file)
666 {
667 foreach ($dom->documentElement->childNodes as $node) {
668 if (!$node instanceof \DOMElement || 'http://symfony.com/schema/dic/services' === $node->namespaceURI) {
669 continue;
670 }
671
672 // can it be handled by an extension?
673 if (!$this->container->hasExtension($node->namespaceURI)) {
674 $extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getNamespace(); }, $this->container->getExtensions()));
675 throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $node->tagName, $file, $node->namespaceURI, $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'));
676 }
677 }
678 }
679
680 /**
681 * Loads from an extension.
682 */
683 private function loadFromExtensions(\DOMDocument $xml)
684 {
685 foreach ($xml->documentElement->childNodes as $node) {
686 if (!$node instanceof \DOMElement || self::NS === $node->namespaceURI) {
687 continue;
688 }
689
690 $values = static::convertDomElementToArray($node);
691 if (!\is_array($values)) {
692 $values = [];
693 }
694
695 $this->container->loadFromExtension($node->namespaceURI, $values);
696 }
697 }
698
699 /**
700 * Converts a \DOMElement object to a PHP array.
701 *
702 * The following rules applies during the conversion:
703 *
704 * * Each tag is converted to a key value or an array
705 * if there is more than one "value"
706 *
707 * * The content of a tag is set under a "value" key (<foo>bar</foo>)
708 * if the tag also has some nested tags
709 *
710 * * The attributes are converted to keys (<foo foo="bar"/>)
711 *
712 * * The nested-tags are converted to keys (<foo><foo>bar</foo></foo>)
713 *
714 * @param \DOMElement $element A \DOMElement instance
715 *
716 * @return mixed
717 */
718 public static function convertDomElementToArray(\DOMElement $element)
719 {
720 return XmlUtils::convertDomElementToArray($element);
721 }
722 }
723