ResolveInvalidReferencesPass.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection\Compiler;
  11. use Symfony\Component\DependencyInjection\ContainerBuilder;
  12. use Symfony\Component\DependencyInjection\ContainerInterface;
  13. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  14. use Symfony\Component\DependencyInjection\Reference;
  15. /**
  16. * Emulates the invalid behavior if the reference is not found within the
  17. * container.
  18. *
  19. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  20. */
  21. class ResolveInvalidReferencesPass implements CompilerPassInterface
  22. {
  23. private $container;
  24. /**
  25. * Process the ContainerBuilder to resolve invalid references.
  26. */
  27. public function process(ContainerBuilder $container)
  28. {
  29. $this->container = $container;
  30. foreach ($container->getDefinitions() as $definition) {
  31. if ($definition->isSynthetic() || $definition->isAbstract()) {
  32. continue;
  33. }
  34. $definition->setArguments(
  35. $this->processArguments($definition->getArguments())
  36. );
  37. $calls = array();
  38. foreach ($definition->getMethodCalls() as $call) {
  39. try {
  40. $calls[] = array($call[0], $this->processArguments($call[1], true));
  41. } catch (RuntimeException $e) {
  42. // this call is simply removed
  43. }
  44. }
  45. $definition->setMethodCalls($calls);
  46. $properties = array();
  47. foreach ($definition->getProperties() as $name => $value) {
  48. try {
  49. $value = $this->processArguments(array($value), true);
  50. $properties[$name] = reset($value);
  51. } catch (RuntimeException $e) {
  52. // ignore property
  53. }
  54. }
  55. $definition->setProperties($properties);
  56. }
  57. }
  58. /**
  59. * Processes arguments to determine invalid references.
  60. *
  61. * @param array $arguments An array of Reference objects
  62. * @param bool $inMethodCall
  63. *
  64. * @return array
  65. *
  66. * @throws RuntimeException When the config is invalid
  67. */
  68. private function processArguments(array $arguments, $inMethodCall = false)
  69. {
  70. foreach ($arguments as $k => $argument) {
  71. if (\is_array($argument)) {
  72. $arguments[$k] = $this->processArguments($argument, $inMethodCall);
  73. } elseif ($argument instanceof Reference) {
  74. $id = (string) $argument;
  75. $invalidBehavior = $argument->getInvalidBehavior();
  76. $exists = $this->container->has($id);
  77. // resolve invalid behavior
  78. if (!$exists && ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) {
  79. $arguments[$k] = null;
  80. } elseif (!$exists && ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $invalidBehavior) {
  81. if ($inMethodCall) {
  82. throw new RuntimeException('Method shouldn\'t be called.');
  83. }
  84. $arguments[$k] = null;
  85. }
  86. }
  87. }
  88. return $arguments;
  89. }
  90. }