Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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: 09.10.2024, 12:56 - Dateigröße: 21.43 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\Resource\FileResource;
015  use Symfony\Component\Config\Util\XmlUtils;
016  use Symfony\Component\DependencyInjection\DefinitionDecorator;
017  use Symfony\Component\DependencyInjection\ContainerInterface;
018  use Symfony\Component\DependencyInjection\Alias;
019  use Symfony\Component\DependencyInjection\Definition;
020  use Symfony\Component\DependencyInjection\Reference;
021  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
022  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
023  use Symfony\Component\ExpressionLanguage\Expression;
024   
025  /**
026   * XmlFileLoader loads XML files service definitions.
027   *
028   * @author Fabien Potencier <fabien@symfony.com>
029   */
030  class XmlFileLoader extends FileLoader
031  {
032      const NS = 'http://symfony.com/schema/dic/services';
033   
034      /**
035       * {@inheritdoc}
036       */
037      public function load($resource, $type = null)
038      {
039          $path = $this->locator->locate($resource);
040   
041          $xml = $this->parseFileToDOM($path);
042   
043          $this->container->addResource(new FileResource($path));
044   
045          // anonymous services
046          $this->processAnonymousServices($xml, $path);
047   
048          // imports
049          $this->parseImports($xml, $path);
050   
051          // parameters
052          $this->parseParameters($xml);
053   
054          // extensions
055          $this->loadFromExtensions($xml);
056   
057          // services
058          $this->parseDefinitions($xml, $path);
059      }
060   
061      /**
062       * {@inheritdoc}
063       */
064      public function supports($resource, $type = null)
065      {
066          return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION);
067      }
068   
069      /**
070       * Parses parameters.
071       *
072       * @param \DOMDocument $xml
073       */
074      private function parseParameters(\DOMDocument $xml)
075      {
076          if ($parameters = $this->getChildren($xml->documentElement, 'parameters')) {
077              $this->container->getParameterBag()->add($this->getArgumentsAsPhp($parameters[0], 'parameter'));
078          }
079      }
080   
081      /**
082       * Parses imports.
083       *
084       * @param \DOMDocument $xml
085       * @param string       $file
086       */
087      private function parseImports(\DOMDocument $xml, $file)
088      {
089          $xpath = new \DOMXPath($xml);
090          $xpath->registerNamespace('container', self::NS);
091   
092          if (false === $imports = $xpath->query('//container:imports/container:import')) {
093              return;
094          }
095   
096          $defaultDirectory = dirname($file);
097          foreach ($imports as $import) {
098              $this->setCurrentDir($defaultDirectory);
099              $this->import($import->getAttribute('resource'), null, (bool) XmlUtils::phpize($import->getAttribute('ignore-errors')), $file);
100          }
101      }
102   
103      /**
104       * Parses multiple definitions.
105       *
106       * @param \DOMDocument $xml
107       * @param string       $file
108       */
109      private function parseDefinitions(\DOMDocument $xml, $file)
110      {
111          $xpath = new \DOMXPath($xml);
112          $xpath->registerNamespace('container', self::NS);
113   
114          if (false === $services = $xpath->query('//container:services/container:service')) {
115              return;
116          }
117   
118          foreach ($services as $service) {
119              if (null !== $definition = $this->parseDefinition($service, $file)) {
120                  $this->container->setDefinition((string) $service->getAttribute('id'), $definition);
121              }
122          }
123      }
124   
125      /**
126       * Parses an individual Definition.
127       *
128       * @param \DOMElement $service
129       * @param string      $file
130       *
131       * @return Definition|null
132       */
133      private function parseDefinition(\DOMElement $service, $file)
134      {
135          if ($alias = $service->getAttribute('alias')) {
136              $public = true;
137              if ($publicAttr = $service->getAttribute('public')) {
138                  $public = XmlUtils::phpize($publicAttr);
139              }
140              $this->container->setAlias((string) $service->getAttribute('id'), new Alias($alias, $public));
141   
142              return;
143          }
144   
145          if ($parent = $service->getAttribute('parent')) {
146              $definition = new DefinitionDecorator($parent);
147          } else {
148              $definition = new Definition();
149          }
150   
151          foreach (array('class', 'shared', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'lazy', 'abstract') as $key) {
152              if ($value = $service->getAttribute($key)) {
153                  if (in_array($key, array('factory-class', 'factory-method', 'factory-service'))) {
154                      @trigger_error(sprintf('The "%s" attribute of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use the "factory" element instead.', $key, (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
155                  }
156                  $method = 'set'.str_replace('-', '', $key);
157                  $definition->$method(XmlUtils::phpize($value));
158              }
159          }
160   
161          if ($value = $service->getAttribute('autowire')) {
162              $definition->setAutowired(XmlUtils::phpize($value));
163          }
164   
165          if ($value = $service->getAttribute('scope')) {
166              $triggerDeprecation = 'request' !== (string) $service->getAttribute('id');
167   
168              if ($triggerDeprecation) {
169                  @trigger_error(sprintf('The "scope" attribute of service "%s" in file "%s" is deprecated since version 2.8 and will be removed in 3.0.', (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
170              }
171   
172              $definition->setScope(XmlUtils::phpize($value), false);
173          }
174   
175          if ($value = $service->getAttribute('synchronized')) {
176              $triggerDeprecation = 'request' !== (string) $service->getAttribute('id');
177   
178              if ($triggerDeprecation) {
179                  @trigger_error(sprintf('The "synchronized" attribute of service "%s" in file "%s" is deprecated since version 2.7 and will be removed in 3.0.', (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
180              }
181   
182              $definition->setSynchronized(XmlUtils::phpize($value), $triggerDeprecation);
183          }
184   
185          if ($files = $this->getChildren($service, 'file')) {
186              $definition->setFile($files[0]->nodeValue);
187          }
188   
189          if ($deprecated = $this->getChildren($service, 'deprecated')) {
190              $definition->setDeprecated(true, $deprecated[0]->nodeValue ?: null);
191          }
192   
193          $definition->setArguments($this->getArgumentsAsPhp($service, 'argument'));
194          $definition->setProperties($this->getArgumentsAsPhp($service, 'property'));
195   
196          if ($factories = $this->getChildren($service, 'factory')) {
197              $factory = $factories[0];
198              if ($function = $factory->getAttribute('function')) {
199                  $definition->setFactory($function);
200              } else {
201                  $factoryService = $this->getChildren($factory, 'service');
202   
203                  if (isset($factoryService[0])) {
204                      $class = $this->parseDefinition($factoryService[0], $file);
205                  } elseif ($childService = $factory->getAttribute('service')) {
206                      $class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
207                  } else {
208                      $class = $factory->getAttribute('class');
209                  }
210   
211                  $definition->setFactory(array($class, $factory->getAttribute('method')));
212              }
213          }
214   
215          if ($configurators = $this->getChildren($service, 'configurator')) {
216              $configurator = $configurators[0];
217              if ($function = $configurator->getAttribute('function')) {
218                  $definition->setConfigurator($function);
219              } else {
220                  $configuratorService = $this->getChildren($configurator, 'service');
221   
222                  if (isset($configuratorService[0])) {
223                      $class = $this->parseDefinition($configuratorService[0], $file);
224                  } elseif ($childService = $configurator->getAttribute('service')) {
225                      $class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
226                  } else {
227                      $class = $configurator->getAttribute('class');
228                  }
229   
230                  $definition->setConfigurator(array($class, $configurator->getAttribute('method')));
231              }
232          }
233   
234          foreach ($this->getChildren($service, 'call') as $call) {
235              $definition->addMethodCall($call->getAttribute('method'), $this->getArgumentsAsPhp($call, 'argument'));
236          }
237   
238          foreach ($this->getChildren($service, 'tag') as $tag) {
239              $parameters = array();
240              foreach ($tag->attributes as $name => $node) {
241                  if ('name' === $name) {
242                      continue;
243                  }
244   
245                  if (false !== strpos($name, '-') && false === strpos($name, '_') && !array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) {
246                      $parameters[$normalizedName] = XmlUtils::phpize($node->nodeValue);
247                  }
248                  // keep not normalized key for BC too
249                  $parameters[$name] = XmlUtils::phpize($node->nodeValue);
250              }
251   
252              if ('' === $tag->getAttribute('name')) {
253                  throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', (string) $service->getAttribute('id'), $file));
254              }
255   
256              $definition->addTag($tag->getAttribute('name'), $parameters);
257          }
258   
259          foreach ($this->getChildren($service, 'autowiring-type') as $type) {
260              $definition->addAutowiringType($type->textContent);
261          }
262   
263          if ($value = $service->getAttribute('decorates')) {
264              $renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null;
265              $priority = $service->hasAttribute('decoration-priority') ? $service->getAttribute('decoration-priority') : 0;
266              $definition->setDecoratedService($value, $renameId, $priority);
267          }
268   
269          return $definition;
270      }
271   
272      /**
273       * Parses a XML file to a \DOMDocument.
274       *
275       * @param string $file Path to a file
276       *
277       * @return \DOMDocument
278       *
279       * @throws InvalidArgumentException When loading of XML file returns error
280       */
281      private function parseFileToDOM($file)
282      {
283          try {
284              $dom = XmlUtils::loadFile($file, array($this, 'validateSchema'));
285          } catch (\InvalidArgumentException $e) {
286              throw new InvalidArgumentException(sprintf('Unable to parse file "%s".', $file), $e->getCode(), $e);
287          }
288   
289          $this->validateExtensions($dom, $file);
290   
291          return $dom;
292      }
293   
294      /**
295       * Processes anonymous services.
296       *
297       * @param \DOMDocument $xml
298       * @param string       $file
299       */
300      private function processAnonymousServices(\DOMDocument $xml, $file)
301      {
302          $definitions = array();
303          $count = 0;
304   
305          $xpath = new \DOMXPath($xml);
306          $xpath->registerNamespace('container', self::NS);
307   
308          // anonymous services as arguments/properties
309          if (false !== $nodes = $xpath->query('//container:argument[@type="service"][not(@id)]|//container:property[@type="service"][not(@id)]')) {
310              foreach ($nodes as $node) {
311                  // give it a unique name
312                  $id = sprintf('%s_%d', hash('sha256', $file), ++$count);
313                  $node->setAttribute('id', $id);
314   
315                  if ($services = $this->getChildren($node, 'service')) {
316                      $definitions[$id] = array($services[0], $file, false);
317                      $services[0]->setAttribute('id', $id);
318   
319                      // anonymous services are always private
320                      // we could not use the constant false here, because of XML parsing
321                      $services[0]->setAttribute('public', 'false');
322                  }
323              }
324          }
325   
326          // anonymous services "in the wild"
327          if (false !== $nodes = $xpath->query('//container:services/container:service[not(@id)]')) {
328              foreach ($nodes as $node) {
329                  // give it a unique name
330                  $id = sprintf('%s_%d', hash('sha256', $file), ++$count);
331                  $node->setAttribute('id', $id);
332                  $definitions[$id] = array($node, $file, true);
333              }
334          }
335   
336          // resolve definitions
337          krsort($definitions);
338          foreach ($definitions as $id => $def) {
339              list($domElement, $file, $wild) = $def;
340   
341              if (null !== $definition = $this->parseDefinition($domElement, $file)) {
342                  $this->container->setDefinition($id, $definition);
343              }
344   
345              if (true === $wild) {
346                  $tmpDomElement = new \DOMElement('_services', null, self::NS);
347                  $domElement->parentNode->replaceChild($tmpDomElement, $domElement);
348                  $tmpDomElement->setAttribute('id', $id);
349              } else {
350                  $domElement->parentNode->removeChild($domElement);
351              }
352          }
353      }
354   
355      /**
356       * Returns arguments as valid php types.
357       *
358       * @param \DOMElement $node
359       * @param string      $name
360       * @param bool        $lowercase
361       *
362       * @return mixed
363       */
364      private function getArgumentsAsPhp(\DOMElement $node, $name, $lowercase = true)
365      {
366          $arguments = array();
367          foreach ($this->getChildren($node, $name) as $arg) {
368              if ($arg->hasAttribute('name')) {
369                  $arg->setAttribute('key', $arg->getAttribute('name'));
370              }
371   
372              if (!$arg->hasAttribute('key')) {
373                  $key = !$arguments ? 0 : max(array_keys($arguments)) + 1;
374              } else {
375                  $key = $arg->getAttribute('key');
376              }
377   
378              // parameter keys are case insensitive
379              if ('parameter' == $name && $lowercase) {
380                  $key = strtolower($key);
381              }
382   
383              // this is used by DefinitionDecorator to overwrite a specific
384              // argument of the parent definition
385              if ($arg->hasAttribute('index')) {
386                  $key = 'index_'.$arg->getAttribute('index');
387              }
388   
389              switch ($arg->getAttribute('type')) {
390                  case 'service':
391                      $onInvalid = $arg->getAttribute('on-invalid');
392                      $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
393                      if ('ignore' == $onInvalid) {
394                          $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
395                      } elseif ('null' == $onInvalid) {
396                          $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
397                      }
398   
399                      if ($strict = $arg->getAttribute('strict')) {
400                          $strict = XmlUtils::phpize($strict);
401                      } else {
402                          $strict = true;
403                      }
404   
405                      $arguments[$key] = new Reference($arg->getAttribute('id'), $invalidBehavior, $strict);
406                      break;
407                  case 'expression':
408                      $arguments[$key] = new Expression($arg->nodeValue);
409                      break;
410                  case 'collection':
411                      $arguments[$key] = $this->getArgumentsAsPhp($arg, $name, false);
412                      break;
413                  case 'string':
414                      $arguments[$key] = $arg->nodeValue;
415                      break;
416                  case 'constant':
417                      $arguments[$key] = constant(trim($arg->nodeValue));
418                      break;
419                  default:
420                      $arguments[$key] = XmlUtils::phpize($arg->nodeValue);
421              }
422          }
423   
424          return $arguments;
425      }
426   
427      /**
428       * Get child elements by name.
429       *
430       * @param \DOMNode $node
431       * @param mixed    $name
432       *
433       * @return array
434       */
435      private function getChildren(\DOMNode $node, $name)
436      {
437          $children = array();
438          foreach ($node->childNodes as $child) {
439              if ($child instanceof \DOMElement && $child->localName === $name && $child->namespaceURI === self::NS) {
440                  $children[] = $child;
441              }
442          }
443   
444          return $children;
445      }
446   
447      /**
448       * Validates a documents XML schema.
449       *
450       * @param \DOMDocument $dom
451       *
452       * @return bool
453       *
454       * @throws RuntimeException When extension references a non-existent XSD file
455       */
456      public function validateSchema(\DOMDocument $dom)
457      {
458          $schemaLocations = array('http://symfony.com/schema/dic/services' => str_replace('\\', '/', __DIR__.'/schema/dic/services/services-1.0.xsd'));
459   
460          if ($element = $dom->documentElement->getAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation')) {
461              $items = preg_split('/\s+/', $element);
462              for ($i = 0, $nb = count($items); $i < $nb; $i += 2) {
463                  if (!$this->container->hasExtension($items[$i])) {
464                      continue;
465                  }
466   
467                  if (($extension = $this->container->getExtension($items[$i])) && false !== $extension->getXsdValidationBasePath()) {
468                      $path = str_replace($extension->getNamespace(), str_replace('\\', '/', $extension->getXsdValidationBasePath()).'/', $items[$i + 1]);
469   
470                      if (!is_file($path)) {
471                          throw new RuntimeException(sprintf('Extension "%s" references a non-existent XSD file "%s"', get_class($extension), $path));
472                      }
473   
474                      $schemaLocations[$items[$i]] = $path;
475                  }
476              }
477          }
478   
479          $tmpfiles = array();
480          $imports = '';
481          foreach ($schemaLocations as $namespace => $location) {
482              $parts = explode('/', $location);
483              if (0 === stripos($location, 'phar://')) {
484                  $tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
485                  if ($tmpfile) {
486                      copy($location, $tmpfile);
487                      $tmpfiles[] = $tmpfile;
488                      $parts = explode('/', str_replace('\\', '/', $tmpfile));
489                  }
490              }
491              $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
492              $location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
493   
494              $imports .= sprintf('  <xsd:import namespace="%s" schemaLocation="%s" />'."\n", $namespace, $location);
495          }
496   
497          $source = <<<EOF
498  <?xml version="1.0" encoding="utf-8" ?>
499  <xsd:schema xmlns="http://symfony.com/schema"
500      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
501      targetNamespace="http://symfony.com/schema"
502      elementFormDefault="qualified">
503   
504      <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
505  $imports
506  </xsd:schema>
507  EOF
508          ;
509   
510          $disableEntities = libxml_disable_entity_loader(false);
511          $valid = @$dom->schemaValidateSource($source);
512          libxml_disable_entity_loader($disableEntities);
513   
514          foreach ($tmpfiles as $tmpfile) {
515              @unlink($tmpfile);
516          }
517   
518          return $valid;
519      }
520   
521      /**
522       * Validates an extension.
523       *
524       * @param \DOMDocument $dom
525       * @param string       $file
526       *
527       * @throws InvalidArgumentException When no extension is found corresponding to a tag
528       */
529      private function validateExtensions(\DOMDocument $dom, $file)
530      {
531          foreach ($dom->documentElement->childNodes as $node) {
532              if (!$node instanceof \DOMElement || 'http://symfony.com/schema/dic/services' === $node->namespaceURI) {
533                  continue;
534              }
535   
536              // can it be handled by an extension?
537              if (!$this->container->hasExtension($node->namespaceURI)) {
538                  $extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getNamespace(); }, $this->container->getExtensions()));
539                  throw new InvalidArgumentException(sprintf(
540                      'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s',
541                      $node->tagName,
542                      $file,
543                      $node->namespaceURI,
544                      $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
545                  ));
546              }
547          }
548      }
549   
550      /**
551       * Loads from an extension.
552       *
553       * @param \DOMDocument $xml
554       */
555      private function loadFromExtensions(\DOMDocument $xml)
556      {
557          foreach ($xml->documentElement->childNodes as $node) {
558              if (!$node instanceof \DOMElement || $node->namespaceURI === self::NS) {
559                  continue;
560              }
561   
562              $values = static::convertDomElementToArray($node);
563              if (!is_array($values)) {
564                  $values = array();
565              }
566   
567              $this->container->loadFromExtension($node->namespaceURI, $values);
568          }
569      }
570   
571      /**
572       * Converts a \DomElement object to a PHP array.
573       *
574       * The following rules applies during the conversion:
575       *
576       *  * Each tag is converted to a key value or an array
577       *    if there is more than one "value"
578       *
579       *  * The content of a tag is set under a "value" key (<foo>bar</foo>)
580       *    if the tag also has some nested tags
581       *
582       *  * The attributes are converted to keys (<foo foo="bar"/>)
583       *
584       *  * The nested-tags are converted to keys (<foo><foo>bar</foo></foo>)
585       *
586       * @param \DomElement $element A \DomElement instance
587       *
588       * @return array A PHP array
589       */
590      public static function convertDomElementToArray(\DOMElement $element)
591      {
592          return XmlUtils::convertDomElementToArray($element);
593      }
594  }
595