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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

XmlFileLoader.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 28.41 KiB


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