CheckExceptionOnInvalidReferenceBehaviorPass.php 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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\ServiceNotFoundException;
  14. use Symfony\Component\DependencyInjection\Reference;
  15. /**
  16. * Checks that all references are pointing to a valid service.
  17. *
  18. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  19. */
  20. class CheckExceptionOnInvalidReferenceBehaviorPass extends AbstractRecursivePass
  21. {
  22. private $serviceLocatorContextIds = [];
  23. /**
  24. * {@inheritdoc}
  25. */
  26. public function process(ContainerBuilder $container)
  27. {
  28. $this->serviceLocatorContextIds = [];
  29. foreach ($container->findTaggedServiceIds('container.service_locator_context') as $id => $tags) {
  30. $this->serviceLocatorContextIds[$id] = $tags[0]['id'];
  31. $container->getDefinition($id)->clearTag('container.service_locator_context');
  32. }
  33. try {
  34. return parent::process($container);
  35. } finally {
  36. $this->serviceLocatorContextIds = [];
  37. }
  38. }
  39. protected function processValue($value, $isRoot = false)
  40. {
  41. if (!$value instanceof Reference) {
  42. return parent::processValue($value, $isRoot);
  43. }
  44. if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $value->getInvalidBehavior() || $this->container->has($id = (string) $value)) {
  45. return $value;
  46. }
  47. $currentId = $this->currentId;
  48. $graph = $this->container->getCompiler()->getServiceReferenceGraph();
  49. if (isset($this->serviceLocatorContextIds[$currentId])) {
  50. $currentId = $this->serviceLocatorContextIds[$currentId];
  51. $locator = $this->container->getDefinition($this->currentId)->getFactory()[0];
  52. foreach ($locator->getArgument(0) as $k => $v) {
  53. if ($v->getValues()[0] === $value) {
  54. if ($k !== $id) {
  55. $currentId = $k.'" in the container provided to "'.$currentId;
  56. }
  57. throw new ServiceNotFoundException($id, $currentId);
  58. }
  59. }
  60. }
  61. if ('.' === $currentId[0] && $graph->hasNode($currentId)) {
  62. foreach ($graph->getNode($currentId)->getInEdges() as $edge) {
  63. if (!$edge->getValue() instanceof Reference || ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $edge->getValue()->getInvalidBehavior()) {
  64. continue;
  65. }
  66. $sourceId = $edge->getSourceNode()->getId();
  67. if ('.' !== $sourceId[0]) {
  68. $currentId = $sourceId;
  69. break;
  70. }
  71. }
  72. }
  73. throw new ServiceNotFoundException($id, $currentId);
  74. }
  75. }