InlineServiceDefinitionsPass.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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\ContainerInterface;
  12. use Symfony\Component\DependencyInjection\Definition;
  13. use Symfony\Component\DependencyInjection\Reference;
  14. use Symfony\Component\DependencyInjection\ContainerBuilder;
  15. /**
  16. * Inline service definitions where this is possible.
  17. *
  18. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  19. */
  20. class InlineServiceDefinitionsPass implements RepeatablePassInterface
  21. {
  22. private $repeatedPass;
  23. private $graph;
  24. private $compiler;
  25. private $formatter;
  26. private $currentId;
  27. /**
  28. * {@inheritDoc}
  29. */
  30. public function setRepeatedPass(RepeatedPass $repeatedPass)
  31. {
  32. $this->repeatedPass = $repeatedPass;
  33. }
  34. /**
  35. * Processes the ContainerBuilder for inline service definitions.
  36. *
  37. * @param ContainerBuilder $container
  38. */
  39. public function process(ContainerBuilder $container)
  40. {
  41. $this->compiler = $container->getCompiler();
  42. $this->formatter = $this->compiler->getLoggingFormatter();
  43. $this->graph = $this->compiler->getServiceReferenceGraph();
  44. foreach ($container->getDefinitions() as $id => $definition) {
  45. $this->currentId = $id;
  46. $definition->setArguments(
  47. $this->inlineArguments($container, $definition->getArguments())
  48. );
  49. $definition->setMethodCalls(
  50. $this->inlineArguments($container, $definition->getMethodCalls())
  51. );
  52. $definition->setProperties(
  53. $this->inlineArguments($container, $definition->getProperties())
  54. );
  55. }
  56. }
  57. /**
  58. * Processes inline arguments.
  59. *
  60. * @param ContainerBuilder $container The ContainerBuilder
  61. * @param array $arguments An array of arguments
  62. *
  63. * @return array
  64. */
  65. private function inlineArguments(ContainerBuilder $container, array $arguments)
  66. {
  67. foreach ($arguments as $k => $argument) {
  68. if (is_array($argument)) {
  69. $arguments[$k] = $this->inlineArguments($container, $argument);
  70. } elseif ($argument instanceof Reference) {
  71. if (!$container->hasDefinition($id = (string) $argument)) {
  72. continue;
  73. }
  74. if ($this->isInlineableDefinition($container, $id, $definition = $container->getDefinition($id))) {
  75. $this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId));
  76. if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) {
  77. $arguments[$k] = $definition;
  78. } else {
  79. $arguments[$k] = clone $definition;
  80. }
  81. }
  82. } elseif ($argument instanceof Definition) {
  83. $argument->setArguments($this->inlineArguments($container, $argument->getArguments()));
  84. $argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls()));
  85. $argument->setProperties($this->inlineArguments($container, $argument->getProperties()));
  86. }
  87. }
  88. return $arguments;
  89. }
  90. /**
  91. * Checks if the definition is inlineable.
  92. *
  93. * @param ContainerBuilder $container
  94. * @param string $id
  95. * @param Definition $definition
  96. *
  97. * @return Boolean If the definition is inlineable
  98. */
  99. private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition)
  100. {
  101. if (ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
  102. return true;
  103. }
  104. if ($definition->isPublic()) {
  105. return false;
  106. }
  107. if (!$this->graph->hasNode($id)) {
  108. return true;
  109. }
  110. $ids = array();
  111. foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
  112. $ids[] = $edge->getSourceNode()->getId();
  113. }
  114. if (count(array_unique($ids)) > 1) {
  115. return false;
  116. }
  117. return $container->getDefinition(reset($ids))->getScope() === $definition->getScope();
  118. }
  119. }