[ Index ]

PHP Cross Reference of phpBB-3.3.2-deutsch

title

Body

[close]

/vendor/symfony/dependency-injection/Loader/ -> YamlFileLoader.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\DependencyInjection\Alias;
  15  use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
  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  use Symfony\Component\Yaml\Exception\ParseException;
  28  use Symfony\Component\Yaml\Parser as YamlParser;
  29  use Symfony\Component\Yaml\Tag\TaggedValue;
  30  use Symfony\Component\Yaml\Yaml;
  31  
  32  /**
  33   * YamlFileLoader loads YAML files service definitions.
  34   *
  35   * @author Fabien Potencier <fabien@symfony.com>
  36   */
  37  class YamlFileLoader extends FileLoader
  38  {
  39      private static $serviceKeywords = [
  40          'alias' => 'alias',
  41          'parent' => 'parent',
  42          'class' => 'class',
  43          'shared' => 'shared',
  44          'synthetic' => 'synthetic',
  45          'lazy' => 'lazy',
  46          'public' => 'public',
  47          'abstract' => 'abstract',
  48          'deprecated' => 'deprecated',
  49          'factory' => 'factory',
  50          'file' => 'file',
  51          'arguments' => 'arguments',
  52          'properties' => 'properties',
  53          'configurator' => 'configurator',
  54          'calls' => 'calls',
  55          'tags' => 'tags',
  56          'decorates' => 'decorates',
  57          'decoration_inner_name' => 'decoration_inner_name',
  58          'decoration_priority' => 'decoration_priority',
  59          'autowire' => 'autowire',
  60          'autowiring_types' => 'autowiring_types',
  61          'autoconfigure' => 'autoconfigure',
  62          'bind' => 'bind',
  63      ];
  64  
  65      private static $prototypeKeywords = [
  66          'resource' => 'resource',
  67          'namespace' => 'namespace',
  68          'exclude' => 'exclude',
  69          'parent' => 'parent',
  70          'shared' => 'shared',
  71          'lazy' => 'lazy',
  72          'public' => 'public',
  73          'abstract' => 'abstract',
  74          'deprecated' => 'deprecated',
  75          'factory' => 'factory',
  76          'arguments' => 'arguments',
  77          'properties' => 'properties',
  78          'configurator' => 'configurator',
  79          'calls' => 'calls',
  80          'tags' => 'tags',
  81          'autowire' => 'autowire',
  82          'autoconfigure' => 'autoconfigure',
  83          'bind' => 'bind',
  84      ];
  85  
  86      private static $instanceofKeywords = [
  87          'shared' => 'shared',
  88          'lazy' => 'lazy',
  89          'public' => 'public',
  90          'properties' => 'properties',
  91          'configurator' => 'configurator',
  92          'calls' => 'calls',
  93          'tags' => 'tags',
  94          'autowire' => 'autowire',
  95      ];
  96  
  97      private static $defaultsKeywords = [
  98          'public' => 'public',
  99          'tags' => 'tags',
 100          'autowire' => 'autowire',
 101          'autoconfigure' => 'autoconfigure',
 102          'bind' => 'bind',
 103      ];
 104  
 105      private $yamlParser;
 106  
 107      private $anonymousServicesCount;
 108      private $anonymousServicesSuffix;
 109  
 110      /**
 111       * {@inheritdoc}
 112       */
 113      public function load($resource, $type = null)
 114      {
 115          $path = $this->locator->locate($resource);
 116  
 117          $content = $this->loadFile($path);
 118  
 119          $this->container->fileExists($path);
 120  
 121          // empty file
 122          if (null === $content) {
 123              return;
 124          }
 125  
 126          // imports
 127          $this->parseImports($content, $path);
 128  
 129          // parameters
 130          if (isset($content['parameters'])) {
 131              if (!\is_array($content['parameters'])) {
 132                  throw new InvalidArgumentException(sprintf('The "parameters" key should contain an array in "%s". Check your YAML syntax.', $path));
 133              }
 134  
 135              foreach ($content['parameters'] as $key => $value) {
 136                  $this->container->setParameter($key, $this->resolveServices($value, $path, true));
 137              }
 138          }
 139  
 140          // extensions
 141          $this->loadFromExtensions($content);
 142  
 143          // services
 144          $this->anonymousServicesCount = 0;
 145          $this->anonymousServicesSuffix = '~'.ContainerBuilder::hash($path);
 146          $this->setCurrentDir(\dirname($path));
 147          try {
 148              $this->parseDefinitions($content, $path);
 149          } finally {
 150              $this->instanceof = [];
 151          }
 152      }
 153  
 154      /**
 155       * {@inheritdoc}
 156       */
 157      public function supports($resource, $type = null)
 158      {
 159          if (!\is_string($resource)) {
 160              return false;
 161          }
 162  
 163          if (null === $type && \in_array(pathinfo($resource, \PATHINFO_EXTENSION), ['yaml', 'yml'], true)) {
 164              return true;
 165          }
 166  
 167          return \in_array($type, ['yaml', 'yml'], true);
 168      }
 169  
 170      /**
 171       * Parses all imports.
 172       *
 173       * @param string $file
 174       */
 175      private function parseImports(array $content, $file)
 176      {
 177          if (!isset($content['imports'])) {
 178              return;
 179          }
 180  
 181          if (!\is_array($content['imports'])) {
 182              throw new InvalidArgumentException(sprintf('The "imports" key should contain an array in "%s". Check your YAML syntax.', $file));
 183          }
 184  
 185          $defaultDirectory = \dirname($file);
 186          foreach ($content['imports'] as $import) {
 187              if (!\is_array($import)) {
 188                  $import = ['resource' => $import];
 189              }
 190              if (!isset($import['resource'])) {
 191                  throw new InvalidArgumentException(sprintf('An import should provide a resource in "%s". Check your YAML syntax.', $file));
 192              }
 193  
 194              $this->setCurrentDir($defaultDirectory);
 195              $this->import($import['resource'], isset($import['type']) ? $import['type'] : null, isset($import['ignore_errors']) ? (bool) $import['ignore_errors'] : false, $file);
 196          }
 197      }
 198  
 199      /**
 200       * Parses definitions.
 201       *
 202       * @param string $file
 203       */
 204      private function parseDefinitions(array $content, $file)
 205      {
 206          if (!isset($content['services'])) {
 207              return;
 208          }
 209  
 210          if (!\is_array($content['services'])) {
 211              throw new InvalidArgumentException(sprintf('The "services" key should contain an array in "%s". Check your YAML syntax.', $file));
 212          }
 213  
 214          if (\array_key_exists('_instanceof', $content['services'])) {
 215              $instanceof = $content['services']['_instanceof'];
 216              unset($content['services']['_instanceof']);
 217  
 218              if (!\is_array($instanceof)) {
 219                  throw new InvalidArgumentException(sprintf('Service "_instanceof" key must be an array, "%s" given in "%s".', \gettype($instanceof), $file));
 220              }
 221              $this->instanceof = [];
 222              $this->isLoadingInstanceof = true;
 223              foreach ($instanceof as $id => $service) {
 224                  if (!$service || !\is_array($service)) {
 225                      throw new InvalidArgumentException(sprintf('Type definition "%s" must be a non-empty array within "_instanceof" in "%s". Check your YAML syntax.', $id, $file));
 226                  }
 227                  if (\is_string($service) && 0 === strpos($service, '@')) {
 228                      throw new InvalidArgumentException(sprintf('Type definition "%s" cannot be an alias within "_instanceof" in "%s". Check your YAML syntax.', $id, $file));
 229                  }
 230                  $this->parseDefinition($id, $service, $file, []);
 231              }
 232          }
 233  
 234          $this->isLoadingInstanceof = false;
 235          $defaults = $this->parseDefaults($content, $file);
 236          foreach ($content['services'] as $id => $service) {
 237              $this->parseDefinition($id, $service, $file, $defaults);
 238          }
 239      }
 240  
 241      /**
 242       * @param string $file
 243       *
 244       * @return array
 245       *
 246       * @throws InvalidArgumentException
 247       */
 248      private function parseDefaults(array &$content, $file)
 249      {
 250          if (!\array_key_exists('_defaults', $content['services'])) {
 251              return [];
 252          }
 253          $defaults = $content['services']['_defaults'];
 254          unset($content['services']['_defaults']);
 255  
 256          if (!\is_array($defaults)) {
 257              throw new InvalidArgumentException(sprintf('Service "_defaults" key must be an array, "%s" given in "%s".', \gettype($defaults), $file));
 258          }
 259  
 260          foreach ($defaults as $key => $default) {
 261              if (!isset(self::$defaultsKeywords[$key])) {
 262                  throw new InvalidArgumentException(sprintf('The configuration key "%s" cannot be used to define a default value in "%s". Allowed keys are "%s".', $key, $file, implode('", "', self::$defaultsKeywords)));
 263              }
 264          }
 265  
 266          if (isset($defaults['tags'])) {
 267              if (!\is_array($tags = $defaults['tags'])) {
 268                  throw new InvalidArgumentException(sprintf('Parameter "tags" in "_defaults" must be an array in "%s". Check your YAML syntax.', $file));
 269              }
 270  
 271              foreach ($tags as $tag) {
 272                  if (!\is_array($tag)) {
 273                      $tag = ['name' => $tag];
 274                  }
 275  
 276                  if (!isset($tag['name'])) {
 277                      throw new InvalidArgumentException(sprintf('A "tags" entry in "_defaults" is missing a "name" key in "%s".', $file));
 278                  }
 279                  $name = $tag['name'];
 280                  unset($tag['name']);
 281  
 282                  if (!\is_string($name) || '' === $name) {
 283                      throw new InvalidArgumentException(sprintf('The tag name in "_defaults" must be a non-empty string in "%s".', $file));
 284                  }
 285  
 286                  foreach ($tag as $attribute => $value) {
 287                      if (!is_scalar($value) && null !== $value) {
 288                          throw new InvalidArgumentException(sprintf('Tag "%s", attribute "%s" in "_defaults" must be of a scalar-type in "%s". Check your YAML syntax.', $name, $attribute, $file));
 289                      }
 290                  }
 291              }
 292          }
 293  
 294          if (isset($defaults['bind'])) {
 295              if (!\is_array($defaults['bind'])) {
 296                  throw new InvalidArgumentException(sprintf('Parameter "bind" in "_defaults" must be an array in "%s". Check your YAML syntax.', $file));
 297              }
 298  
 299              $defaults['bind'] = array_map(function ($v) { return new BoundArgument($v); }, $this->resolveServices($defaults['bind'], $file));
 300          }
 301  
 302          return $defaults;
 303      }
 304  
 305      /**
 306       * @return bool
 307       */
 308      private function isUsingShortSyntax(array $service)
 309      {
 310          foreach ($service as $key => $value) {
 311              if (\is_string($key) && ('' === $key || '$' !== $key[0])) {
 312                  return false;
 313              }
 314          }
 315  
 316          return true;
 317      }
 318  
 319      /**
 320       * Parses a definition.
 321       *
 322       * @param string       $id
 323       * @param array|string $service
 324       * @param string       $file
 325       *
 326       * @throws InvalidArgumentException When tags are invalid
 327       */
 328      private function parseDefinition($id, $service, $file, array $defaults)
 329      {
 330          if (preg_match('/^_[a-zA-Z0-9_]*$/', $id)) {
 331              @trigger_error(sprintf('Service names that start with an underscore are deprecated since Symfony 3.3 and will be reserved in 4.0. Rename the "%s" service or define it in XML instead.', $id), \E_USER_DEPRECATED);
 332          }
 333          if (\is_string($service) && 0 === strpos($service, '@')) {
 334              $this->container->setAlias($id, $alias = new Alias(substr($service, 1)));
 335              if (isset($defaults['public'])) {
 336                  $alias->setPublic($defaults['public']);
 337              }
 338  
 339              return;
 340          }
 341  
 342          if (\is_array($service) && $this->isUsingShortSyntax($service)) {
 343              $service = ['arguments' => $service];
 344          }
 345  
 346          if (null === $service) {
 347              $service = [];
 348          }
 349  
 350          if (!\is_array($service)) {
 351              throw new InvalidArgumentException(sprintf('A service definition must be an array or a string starting with "@" but "%s" found for service "%s" in "%s". Check your YAML syntax.', \gettype($service), $id, $file));
 352          }
 353  
 354          $this->checkDefinition($id, $service, $file);
 355  
 356          if (isset($service['alias'])) {
 357              $this->container->setAlias($id, $alias = new Alias($service['alias']));
 358              if (isset($service['public'])) {
 359                  $alias->setPublic($service['public']);
 360              } elseif (isset($defaults['public'])) {
 361                  $alias->setPublic($defaults['public']);
 362              }
 363  
 364              foreach ($service as $key => $value) {
 365                  if (!\in_array($key, ['alias', 'public'])) {
 366                      @trigger_error(sprintf('The configuration key "%s" is unsupported for the service "%s" which is defined as an alias in "%s". Allowed configuration keys for service aliases are "alias" and "public". The YamlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported attributes.', $key, $id, $file), \E_USER_DEPRECATED);
 367                  }
 368              }
 369  
 370              return;
 371          }
 372  
 373          if ($this->isLoadingInstanceof) {
 374              $definition = new ChildDefinition('');
 375          } elseif (isset($service['parent'])) {
 376              if (!empty($this->instanceof)) {
 377                  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.', $id));
 378              }
 379  
 380              foreach ($defaults as $k => $v) {
 381                  if ('tags' === $k) {
 382                      // since tags are never inherited from parents, there is no confusion
 383                      // thus we can safely add them as defaults to ChildDefinition
 384                      continue;
 385                  }
 386                  if ('bind' === $k) {
 387                      throw new InvalidArgumentException(sprintf('Attribute "bind" on service "%s" cannot be inherited from "_defaults" when a "parent" is set. Move your child definitions to a separate file.', $id));
 388                  }
 389                  if (!isset($service[$k])) {
 390                      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, $id));
 391                  }
 392              }
 393  
 394              $definition = new ChildDefinition($service['parent']);
 395          } else {
 396              $definition = new Definition();
 397  
 398              if (isset($defaults['public'])) {
 399                  $definition->setPublic($defaults['public']);
 400              }
 401              if (isset($defaults['autowire'])) {
 402                  $definition->setAutowired($defaults['autowire']);
 403              }
 404              if (isset($defaults['autoconfigure'])) {
 405                  $definition->setAutoconfigured($defaults['autoconfigure']);
 406              }
 407  
 408              $definition->setChanges([]);
 409          }
 410  
 411          if (isset($service['class'])) {
 412              $definition->setClass($service['class']);
 413          }
 414  
 415          if (isset($service['shared'])) {
 416              $definition->setShared($service['shared']);
 417          }
 418  
 419          if (isset($service['synthetic'])) {
 420              $definition->setSynthetic($service['synthetic']);
 421          }
 422  
 423          if (isset($service['lazy'])) {
 424              $definition->setLazy($service['lazy']);
 425          }
 426  
 427          if (isset($service['public'])) {
 428              $definition->setPublic($service['public']);
 429          }
 430  
 431          if (isset($service['abstract'])) {
 432              $definition->setAbstract($service['abstract']);
 433          }
 434  
 435          if (\array_key_exists('deprecated', $service)) {
 436              $definition->setDeprecated(true, $service['deprecated']);
 437          }
 438  
 439          if (isset($service['factory'])) {
 440              $definition->setFactory($this->parseCallable($service['factory'], 'factory', $id, $file));
 441          }
 442  
 443          if (isset($service['file'])) {
 444              $definition->setFile($service['file']);
 445          }
 446  
 447          if (isset($service['arguments'])) {
 448              $definition->setArguments($this->resolveServices($service['arguments'], $file));
 449          }
 450  
 451          if (isset($service['properties'])) {
 452              $definition->setProperties($this->resolveServices($service['properties'], $file));
 453          }
 454  
 455          if (isset($service['configurator'])) {
 456              $definition->setConfigurator($this->parseCallable($service['configurator'], 'configurator', $id, $file));
 457          }
 458  
 459          if (isset($service['calls'])) {
 460              if (!\is_array($service['calls'])) {
 461                  throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in "%s". Check your YAML syntax.', $id, $file));
 462              }
 463  
 464              foreach ($service['calls'] as $call) {
 465                  if (isset($call['method'])) {
 466                      $method = $call['method'];
 467                      $args = isset($call['arguments']) ? $this->resolveServices($call['arguments'], $file) : [];
 468                  } else {
 469                      $method = $call[0];
 470                      $args = isset($call[1]) ? $this->resolveServices($call[1], $file) : [];
 471                  }
 472  
 473                  if (!\is_array($args)) {
 474                      throw new InvalidArgumentException(sprintf('The second parameter for function call "%s" must be an array of its arguments for service "%s" in "%s". Check your YAML syntax.', $method, $id, $file));
 475                  }
 476                  $definition->addMethodCall($method, $args);
 477              }
 478          }
 479  
 480          $tags = isset($service['tags']) ? $service['tags'] : [];
 481          if (!\is_array($tags)) {
 482              throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in "%s". Check your YAML syntax.', $id, $file));
 483          }
 484  
 485          if (isset($defaults['tags'])) {
 486              $tags = array_merge($tags, $defaults['tags']);
 487          }
 488  
 489          foreach ($tags as $tag) {
 490              if (!\is_array($tag)) {
 491                  $tag = ['name' => $tag];
 492              }
 493  
 494              if (!isset($tag['name'])) {
 495                  throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in "%s".', $id, $file));
 496              }
 497              $name = $tag['name'];
 498              unset($tag['name']);
 499  
 500              if (!\is_string($name) || '' === $name) {
 501                  throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', $id, $file));
 502              }
 503  
 504              foreach ($tag as $attribute => $value) {
 505                  if (!is_scalar($value) && null !== $value) {
 506                      throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s" in "%s". Check your YAML syntax.', $id, $name, $attribute, $file));
 507                  }
 508              }
 509  
 510              $definition->addTag($name, $tag);
 511          }
 512  
 513          if (isset($service['decorates'])) {
 514              if ('' !== $service['decorates'] && '@' === $service['decorates'][0]) {
 515                  throw new InvalidArgumentException(sprintf('The value of the "decorates" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $id, $service['decorates'], substr($service['decorates'], 1)));
 516              }
 517  
 518              $renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null;
 519              $priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0;
 520              $definition->setDecoratedService($service['decorates'], $renameId, $priority);
 521          }
 522  
 523          if (isset($service['autowire'])) {
 524              $definition->setAutowired($service['autowire']);
 525          }
 526  
 527          if (isset($service['autowiring_types'])) {
 528              if (\is_string($service['autowiring_types'])) {
 529                  $definition->addAutowiringType($service['autowiring_types']);
 530              } else {
 531                  if (!\is_array($service['autowiring_types'])) {
 532                      throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be a string or an array for service "%s" in "%s". Check your YAML syntax.', $id, $file));
 533                  }
 534  
 535                  foreach ($service['autowiring_types'] as $autowiringType) {
 536                      if (!\is_string($autowiringType)) {
 537                          throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in "%s". Check your YAML syntax.', $id, $file));
 538                      }
 539  
 540                      $definition->addAutowiringType($autowiringType);
 541                  }
 542              }
 543          }
 544  
 545          if (isset($defaults['bind']) || isset($service['bind'])) {
 546              // deep clone, to avoid multiple process of the same instance in the passes
 547              $bindings = isset($defaults['bind']) ? unserialize(serialize($defaults['bind'])) : [];
 548  
 549              if (isset($service['bind'])) {
 550                  if (!\is_array($service['bind'])) {
 551                      throw new InvalidArgumentException(sprintf('Parameter "bind" must be an array for service "%s" in "%s". Check your YAML syntax.', $id, $file));
 552                  }
 553  
 554                  $bindings = array_merge($bindings, $this->resolveServices($service['bind'], $file));
 555              }
 556  
 557              $definition->setBindings($bindings);
 558          }
 559  
 560          if (isset($service['autoconfigure'])) {
 561              if (!$definition instanceof ChildDefinition) {
 562                  $definition->setAutoconfigured($service['autoconfigure']);
 563              } elseif ($service['autoconfigure']) {
 564                  throw new InvalidArgumentException(sprintf('The service "%s" cannot have a "parent" and also have "autoconfigure". Try setting "autoconfigure: false" for the service.', $id));
 565              }
 566          }
 567  
 568          if (\array_key_exists('namespace', $service) && !\array_key_exists('resource', $service)) {
 569              throw new InvalidArgumentException(sprintf('A "resource" attribute must be set when the "namespace" attribute is set for service "%s" in "%s". Check your YAML syntax.', $id, $file));
 570          }
 571  
 572          if (\array_key_exists('resource', $service)) {
 573              if (!\is_string($service['resource'])) {
 574                  throw new InvalidArgumentException(sprintf('A "resource" attribute must be of type string for service "%s" in "%s". Check your YAML syntax.', $id, $file));
 575              }
 576              $exclude = isset($service['exclude']) ? $service['exclude'] : null;
 577              $namespace = isset($service['namespace']) ? $service['namespace'] : $id;
 578              $this->registerClasses($definition, $namespace, $service['resource'], $exclude);
 579          } else {
 580              $this->setDefinition($id, $definition);
 581          }
 582      }
 583  
 584      /**
 585       * Parses a callable.
 586       *
 587       * @param string|array $callable  A callable
 588       * @param string       $parameter A parameter (e.g. 'factory' or 'configurator')
 589       * @param string       $id        A service identifier
 590       * @param string       $file      A parsed file
 591       *
 592       * @throws InvalidArgumentException When errors occur
 593       *
 594       * @return string|array A parsed callable
 595       */
 596      private function parseCallable($callable, $parameter, $id, $file)
 597      {
 598          if (\is_string($callable)) {
 599              if ('' !== $callable && '@' === $callable[0]) {
 600                  throw new InvalidArgumentException(sprintf('The value of the "%s" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $parameter, $id, $callable, substr($callable, 1)));
 601              }
 602  
 603              if (false !== strpos($callable, ':') && false === strpos($callable, '::')) {
 604                  $parts = explode(':', $callable);
 605  
 606                  return [$this->resolveServices('@'.$parts[0], $file), $parts[1]];
 607              }
 608  
 609              return $callable;
 610          }
 611  
 612          if (\is_array($callable)) {
 613              if (isset($callable[0]) && isset($callable[1])) {
 614                  return [$this->resolveServices($callable[0], $file), $callable[1]];
 615              }
 616  
 617              if ('factory' === $parameter && isset($callable[1]) && null === $callable[0]) {
 618                  return $callable;
 619              }
 620  
 621              throw new InvalidArgumentException(sprintf('Parameter "%s" must contain an array with two elements for service "%s" in "%s". Check your YAML syntax.', $parameter, $id, $file));
 622          }
 623  
 624          throw new InvalidArgumentException(sprintf('Parameter "%s" must be a string or an array for service "%s" in "%s". Check your YAML syntax.', $parameter, $id, $file));
 625      }
 626  
 627      /**
 628       * Loads a YAML file.
 629       *
 630       * @param string $file
 631       *
 632       * @return array The file content
 633       *
 634       * @throws InvalidArgumentException when the given file is not a local file or when it does not exist
 635       */
 636      protected function loadFile($file)
 637      {
 638          if (!class_exists('Symfony\Component\Yaml\Parser')) {
 639              throw new RuntimeException('Unable to load YAML config files as the Symfony Yaml Component is not installed.');
 640          }
 641  
 642          if (!stream_is_local($file)) {
 643              throw new InvalidArgumentException(sprintf('This is not a local file "%s".', $file));
 644          }
 645  
 646          if (!file_exists($file)) {
 647              throw new InvalidArgumentException(sprintf('The file "%s" does not exist.', $file));
 648          }
 649  
 650          if (null === $this->yamlParser) {
 651              $this->yamlParser = new YamlParser();
 652          }
 653  
 654          $prevErrorHandler = set_error_handler(function ($level, $message, $script, $line) use ($file, &$prevErrorHandler) {
 655              $message = \E_USER_DEPRECATED === $level ? preg_replace('/ on line \d+/', ' in "'.$file.'"$0', $message) : $message;
 656  
 657              return $prevErrorHandler ? $prevErrorHandler($level, $message, $script, $line) : false;
 658          });
 659  
 660          try {
 661              $configuration = $this->yamlParser->parseFile($file, Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS);
 662          } catch (ParseException $e) {
 663              throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML: ', $file).$e->getMessage(), 0, $e);
 664          } finally {
 665              restore_error_handler();
 666          }
 667  
 668          return $this->validate($configuration, $file);
 669      }
 670  
 671      /**
 672       * Validates a YAML file.
 673       *
 674       * @param mixed  $content
 675       * @param string $file
 676       *
 677       * @return array
 678       *
 679       * @throws InvalidArgumentException When service file is not valid
 680       */
 681      private function validate($content, $file)
 682      {
 683          if (null === $content) {
 684              return $content;
 685          }
 686  
 687          if (!\is_array($content)) {
 688              throw new InvalidArgumentException(sprintf('The service file "%s" is not valid. It should contain an array. Check your YAML syntax.', $file));
 689          }
 690  
 691          foreach ($content as $namespace => $data) {
 692              if (\in_array($namespace, ['imports', 'parameters', 'services'])) {
 693                  continue;
 694              }
 695  
 696              if (!$this->container->hasExtension($namespace)) {
 697                  $extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions()));
 698                  throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $namespace, $file, $namespace, $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'));
 699              }
 700          }
 701  
 702          return $content;
 703      }
 704  
 705      /**
 706       * Resolves services.
 707       *
 708       * @param mixed  $value
 709       * @param string $file
 710       * @param bool   $isParameter
 711       *
 712       * @return array|string|Reference|ArgumentInterface
 713       */
 714      private function resolveServices($value, $file, $isParameter = false)
 715      {
 716          if ($value instanceof TaggedValue) {
 717              $argument = $value->getValue();
 718              if ('iterator' === $value->getTag()) {
 719                  if (!\is_array($argument)) {
 720                      throw new InvalidArgumentException(sprintf('"!iterator" tag only accepts sequences in "%s".', $file));
 721                  }
 722                  $argument = $this->resolveServices($argument, $file, $isParameter);
 723                  try {
 724                      return new IteratorArgument($argument);
 725                  } catch (InvalidArgumentException $e) {
 726                      throw new InvalidArgumentException(sprintf('"!iterator" tag only accepts arrays of "@service" references in "%s".', $file));
 727                  }
 728              }
 729              if ('tagged' === $value->getTag()) {
 730                  if (!\is_string($argument) || !$argument) {
 731                      throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file));
 732                  }
 733  
 734                  return new TaggedIteratorArgument($argument);
 735              }
 736              if ('service' === $value->getTag()) {
 737                  if ($isParameter) {
 738                      throw new InvalidArgumentException(sprintf('Using an anonymous service in a parameter is not allowed in "%s".', $file));
 739                  }
 740  
 741                  $isLoadingInstanceof = $this->isLoadingInstanceof;
 742                  $this->isLoadingInstanceof = false;
 743                  $instanceof = $this->instanceof;
 744                  $this->instanceof = [];
 745  
 746                  $id = sprintf('%d_%s', ++$this->anonymousServicesCount, preg_replace('/^.*\\\\/', '', isset($argument['class']) ? $argument['class'] : '').$this->anonymousServicesSuffix);
 747                  $this->parseDefinition($id, $argument, $file, []);
 748  
 749                  if (!$this->container->hasDefinition($id)) {
 750                      throw new InvalidArgumentException(sprintf('Creating an alias using the tag "!service" is not allowed in "%s".', $file));
 751                  }
 752  
 753                  $this->container->getDefinition($id)->setPublic(false);
 754  
 755                  $this->isLoadingInstanceof = $isLoadingInstanceof;
 756                  $this->instanceof = $instanceof;
 757  
 758                  return new Reference($id);
 759              }
 760  
 761              throw new InvalidArgumentException(sprintf('Unsupported tag "!%s".', $value->getTag()));
 762          }
 763  
 764          if (\is_array($value)) {
 765              foreach ($value as $k => $v) {
 766                  $value[$k] = $this->resolveServices($v, $file, $isParameter);
 767              }
 768          } elseif (\is_string($value) && 0 === strpos($value, '@=')) {
 769              if (!class_exists(Expression::class)) {
 770                  throw new \LogicException(sprintf('The "@=" expression syntax cannot be used without the ExpressionLanguage component. Try running "composer require symfony/expression-language".'));
 771              }
 772  
 773              return new Expression(substr($value, 2));
 774          } elseif (\is_string($value) && 0 === strpos($value, '@')) {
 775              if (0 === strpos($value, '@@')) {
 776                  $value = substr($value, 1);
 777                  $invalidBehavior = null;
 778              } elseif (0 === strpos($value, '@!')) {
 779                  $value = substr($value, 2);
 780                  $invalidBehavior = ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE;
 781              } elseif (0 === strpos($value, '@?')) {
 782                  $value = substr($value, 2);
 783                  $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
 784              } else {
 785                  $value = substr($value, 1);
 786                  $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
 787              }
 788  
 789              if ('=' === substr($value, -1)) {
 790                  @trigger_error(sprintf('The "=" suffix that used to disable strict references in Symfony 2.x is deprecated since Symfony 3.3 and will be unsupported in 4.0. Remove it in "%s".', $value), \E_USER_DEPRECATED);
 791                  $value = substr($value, 0, -1);
 792              }
 793  
 794              if (null !== $invalidBehavior) {
 795                  $value = new Reference($value, $invalidBehavior);
 796              }
 797          }
 798  
 799          return $value;
 800      }
 801  
 802      /**
 803       * Loads from Extensions.
 804       */
 805      private function loadFromExtensions(array $content)
 806      {
 807          foreach ($content as $namespace => $values) {
 808              if (\in_array($namespace, ['imports', 'parameters', 'services'])) {
 809                  continue;
 810              }
 811  
 812              if (!\is_array($values) && null !== $values) {
 813                  $values = [];
 814              }
 815  
 816              $this->container->loadFromExtension($namespace, $values);
 817          }
 818      }
 819  
 820      /**
 821       * Checks the keywords used to define a service.
 822       *
 823       * @param string $id         The service name
 824       * @param array  $definition The service definition to check
 825       * @param string $file       The loaded YAML file
 826       */
 827      private function checkDefinition($id, array $definition, $file)
 828      {
 829          if ($throw = $this->isLoadingInstanceof) {
 830              $keywords = self::$instanceofKeywords;
 831          } elseif ($throw = (isset($definition['resource']) || isset($definition['namespace']))) {
 832              $keywords = self::$prototypeKeywords;
 833          } else {
 834              $keywords = self::$serviceKeywords;
 835          }
 836  
 837          foreach ($definition as $key => $value) {
 838              if (!isset($keywords[$key])) {
 839                  if ($throw) {
 840                      throw new InvalidArgumentException(sprintf('The configuration key "%s" is unsupported for definition "%s" in "%s". Allowed configuration keys are "%s".', $key, $id, $file, implode('", "', $keywords)));
 841                  }
 842  
 843                  @trigger_error(sprintf('The configuration key "%s" is unsupported for service definition "%s" in "%s". Allowed configuration keys are "%s". The YamlFileLoader object will raise an exception instead in Symfony 4.0 when detecting an unsupported service configuration key.', $key, $id, $file, implode('", "', $keywords)), \E_USER_DEPRECATED);
 844              }
 845          }
 846      }
 847  }


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