[ Index ]

PHP Cross Reference of phpBB-3.3.2-deutsch

title

Body

[close]

/vendor/symfony/dependency-injection/Loader/ -> XmlFileLoader.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the Symfony package.
   5   *
   6   * (c) Fabien Potencier <fabien@symfony.com>
   7   *
   8   * For the full copyright and license information, please view the LICENSE
   9   * file that was distributed with this source code.
  10   */
  11  
  12  namespace Symfony\Component\DependencyInjection\Loader;
  13  
  14  use Symfony\Component\Config\Util\XmlUtils;
  15  use Symfony\Component\DependencyInjection\Alias;
  16  use Symfony\Component\DependencyInjection\Argument\BoundArgument;
  17  use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
  18  use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
  19  use Symfony\Component\DependencyInjection\ChildDefinition;
  20  use Symfony\Component\DependencyInjection\ContainerBuilder;
  21  use Symfony\Component\DependencyInjection\ContainerInterface;
  22  use Symfony\Component\DependencyInjection\Definition;
  23  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  24  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  25  use Symfony\Component\DependencyInjection\Reference;
  26  use Symfony\Component\ExpressionLanguage\Expression;
  27  
  28  /**
  29   * XmlFileLoader loads XML files service definitions.
  30   *
  31   * @author Fabien Potencier <fabien@symfony.com>
  32   */
  33  class XmlFileLoader extends FileLoader
  34  {
  35      const NS = 'http://symfony.com/schema/dic/services';
  36  
  37      /**
  38       * {@inheritdoc}
  39       */
  40      public function load($resource, $type = null)
  41      {
  42          $path = $this->locator->locate($resource);
  43  
  44          $xml = $this->parseFileToDOM($path);
  45  
  46          $this->container->fileExists($path);
  47  
  48          $defaults = $this->getServiceDefaults($xml, $path);
  49  
  50          // anonymous services
  51          $this->processAnonymousServices($xml, $path, $defaults);
  52  
  53          // imports
  54          $this->parseImports($xml, $path);
  55  
  56          // parameters
  57          $this->parseParameters($xml, $path);
  58  
  59          // extensions
  60          $this->loadFromExtensions($xml);
  61  
  62          // services
  63          try {
  64              $this->parseDefinitions($xml, $path, $defaults);
  65          } finally {
  66              $this->instanceof = [];
  67          }
  68      }
  69  
  70      /**
  71       * {@inheritdoc}
  72       */
  73      public function supports($resource, $type = null)
  74      {
  75          if (!\is_string($resource)) {
  76              return false;
  77          }
  78  
  79          if (null === $type && 'xml' === pathinfo($resource, \PATHINFO_EXTENSION)) {
  80              return true;
  81          }
  82  
  83          return 'xml' === $type;
  84      }
  85  
  86      /**
  87       * Parses parameters.
  88       *
  89       * @param string $file
  90       */
  91      private function parseParameters(\DOMDocument $xml, $file)
  92      {
  93          if ($parameters = $this->getChildren($xml->documentElement, 'parameters')) {
  94              $this->container->getParameterBag()->add($this->getArgumentsAsPhp($parameters[0], 'parameter', $file));
  95          }
  96      }
  97  
  98      /**
  99       * 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  }


Generated: Wed Nov 11 20:28:18 2020 Cross-referenced by PHPXref 0.7.1