InlineServiceDefinitionsPass.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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\Exception\ServiceCircularReferenceException;
  14. use Symfony\Component\DependencyInjection\Reference;
  15. /**
  16. * Inline service definitions where this is possible.
  17. *
  18. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  19. */
  20. class InlineServiceDefinitionsPass extends AbstractRecursivePass implements RepeatablePassInterface
  21. {
  22. private $cloningIds = array();
  23. private $inlinedServiceIds = array();
  24. /**
  25. * {@inheritdoc}
  26. */
  27. public function setRepeatedPass(RepeatedPass $repeatedPass)
  28. {
  29. // no-op for BC
  30. }
  31. /**
  32. * Returns an array of all services inlined by this pass.
  33. *
  34. * The key is the inlined service id and its value is the list of services it was inlined into.
  35. *
  36. * @return array
  37. */
  38. public function getInlinedServiceIds()
  39. {
  40. return $this->inlinedServiceIds;
  41. }
  42. /**
  43. * {@inheritdoc}
  44. */
  45. protected function processValue($value, $isRoot = false)
  46. {
  47. if ($value instanceof ArgumentInterface) {
  48. // Reference found in ArgumentInterface::getValues() are not inlineable
  49. return $value;
  50. }
  51. if ($value instanceof Definition && $this->cloningIds) {
  52. if ($value->isShared()) {
  53. return $value;
  54. }
  55. $value = clone $value;
  56. }
  57. if (!$value instanceof Reference || !$this->container->hasDefinition($id = (string) $value)) {
  58. return parent::processValue($value, $isRoot);
  59. }
  60. $definition = $this->container->getDefinition($id);
  61. if (!$this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
  62. return $value;
  63. }
  64. $this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
  65. $this->inlinedServiceIds[$id][] = $this->currentId;
  66. if ($definition->isShared()) {
  67. return $definition;
  68. }
  69. if (isset($this->cloningIds[$id])) {
  70. $ids = array_keys($this->cloningIds);
  71. $ids[] = $id;
  72. throw new ServiceCircularReferenceException($id, array_slice($ids, array_search($id, $ids)));
  73. }
  74. $this->cloningIds[$id] = true;
  75. try {
  76. return $this->processValue($definition);
  77. } finally {
  78. unset($this->cloningIds[$id]);
  79. }
  80. }
  81. /**
  82. * Checks if the definition is inlineable.
  83. *
  84. * @return bool If the definition is inlineable
  85. */
  86. private function isInlineableDefinition($id, Definition $definition, ServiceReferenceGraph $graph)
  87. {
  88. if (!$definition->isShared()) {
  89. return true;
  90. }
  91. if ($definition->isDeprecated() || $definition->isPublic() || $definition->isLazy()) {
  92. return false;
  93. }
  94. if (!$graph->hasNode($id)) {
  95. return true;
  96. }
  97. if ($this->currentId == $id) {
  98. return false;
  99. }
  100. $ids = array();
  101. foreach ($graph->getNode($id)->getInEdges() as $edge) {
  102. $ids[] = $edge->getSourceNode()->getId();
  103. }
  104. if (count(array_unique($ids)) > 1) {
  105. return false;
  106. }
  107. if (count($ids) > 1 && is_array($factory = $definition->getFactory()) && ($factory[0] instanceof Reference || $factory[0] instanceof Definition)) {
  108. return false;
  109. }
  110. return true;
  111. }
  112. }