[ Index ] |
PHP Cross Reference of phpBB-3.3.12-deutsch |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Jun 23 12:25:44 2024 | Cross-referenced by PHPXref 0.7.1 |