AnalyzeServiceReferencesPass.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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\Argument\ArgumentInterface;
  12. use Symfony\Component\DependencyInjection\Definition;
  13. use Symfony\Component\DependencyInjection\ExpressionLanguage;
  14. use Symfony\Component\DependencyInjection\Reference;
  15. use Symfony\Component\DependencyInjection\ContainerBuilder;
  16. use Symfony\Component\ExpressionLanguage\Expression;
  17. /**
  18. * Run this pass before passes that need to know more about the relation of
  19. * your services.
  20. *
  21. * This class will populate the ServiceReferenceGraph with information. You can
  22. * retrieve the graph in other passes from the compiler.
  23. *
  24. * @autor ThurData <info@thurdata.ch>
  25. */
  26. class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements RepeatablePassInterface
  27. {
  28. private $graph;
  29. private $currentDefinition;
  30. private $onlyConstructorArguments;
  31. private $lazy;
  32. private $expressionLanguage;
  33. /**
  34. * @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
  35. */
  36. public function __construct($onlyConstructorArguments = false)
  37. {
  38. $this->onlyConstructorArguments = (bool) $onlyConstructorArguments;
  39. }
  40. /**
  41. * {@inheritdoc}
  42. */
  43. public function setRepeatedPass(RepeatedPass $repeatedPass)
  44. {
  45. // no-op for BC
  46. }
  47. /**
  48. * Processes a ContainerBuilder object to populate the service reference graph.
  49. */
  50. public function process(ContainerBuilder $container)
  51. {
  52. $this->container = $container;
  53. $this->graph = $container->getCompiler()->getServiceReferenceGraph();
  54. $this->graph->clear();
  55. $this->lazy = false;
  56. foreach ($container->getAliases() as $id => $alias) {
  57. $this->graph->connect($id, $alias, (string) $alias, $this->getDefinition((string) $alias), null);
  58. }
  59. parent::process($container);
  60. }
  61. protected function processValue($value, $isRoot = false)
  62. {
  63. $lazy = $this->lazy;
  64. if ($value instanceof ArgumentInterface) {
  65. $this->lazy = true;
  66. parent::processValue($value->getValues());
  67. $this->lazy = $lazy;
  68. return $value;
  69. }
  70. if ($value instanceof Expression) {
  71. $this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
  72. return $value;
  73. }
  74. if ($value instanceof Reference) {
  75. $targetDefinition = $this->getDefinition((string) $value);
  76. $this->graph->connect(
  77. $this->currentId,
  78. $this->currentDefinition,
  79. $this->getDefinitionId((string) $value),
  80. $targetDefinition,
  81. $value,
  82. $this->lazy || ($targetDefinition && $targetDefinition->isLazy())
  83. );
  84. return $value;
  85. }
  86. if (!$value instanceof Definition) {
  87. return parent::processValue($value, $isRoot);
  88. }
  89. if ($isRoot) {
  90. if ($value->isSynthetic() || $value->isAbstract()) {
  91. return $value;
  92. }
  93. $this->currentDefinition = $value;
  94. }
  95. $this->lazy = false;
  96. $this->processValue($value->getFactory());
  97. $this->processValue($value->getArguments());
  98. if (!$this->onlyConstructorArguments) {
  99. $this->processValue($value->getProperties());
  100. $this->processValue($value->getMethodCalls());
  101. $this->processValue($value->getConfigurator());
  102. }
  103. $this->lazy = $lazy;
  104. return $value;
  105. }
  106. /**
  107. * Returns a service definition given the full name or an alias.
  108. *
  109. * @param string $id A full id or alias for a service definition
  110. *
  111. * @return Definition|null The definition related to the supplied id
  112. */
  113. private function getDefinition($id)
  114. {
  115. $id = $this->getDefinitionId($id);
  116. return null === $id ? null : $this->container->getDefinition($id);
  117. }
  118. private function getDefinitionId($id)
  119. {
  120. while ($this->container->hasAlias($id)) {
  121. $id = (string) $this->container->getAlias($id);
  122. }
  123. if (!$this->container->hasDefinition($id)) {
  124. return;
  125. }
  126. return $id;
  127. }
  128. private function getExpressionLanguage()
  129. {
  130. if (null === $this->expressionLanguage) {
  131. $providers = $this->container->getExpressionLanguageProviders();
  132. $this->expressionLanguage = new ExpressionLanguage(null, $providers, function ($arg) {
  133. if ('""' === substr_replace($arg, '', 1, -1)) {
  134. $id = stripcslashes(substr($arg, 1, -1));
  135. $this->graph->connect(
  136. $this->currentId,
  137. $this->currentDefinition,
  138. $this->getDefinitionId($id),
  139. $this->getDefinition($id)
  140. );
  141. }
  142. return sprintf('$this->get(%s)', $arg);
  143. });
  144. }
  145. return $this->expressionLanguage;
  146. }
  147. }