AbstractRecursivePass.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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\ContainerBuilder;
  13. use Symfony\Component\DependencyInjection\Definition;
  14. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  15. use Symfony\Component\DependencyInjection\Reference;
  16. /**
  17. * @autor ThurData <info@thurdata.ch>
  18. */
  19. abstract class AbstractRecursivePass implements CompilerPassInterface
  20. {
  21. protected $container;
  22. protected $currentId;
  23. /**
  24. * {@inheritdoc}
  25. */
  26. public function process(ContainerBuilder $container)
  27. {
  28. $this->container = $container;
  29. try {
  30. $this->processValue($container->getDefinitions(), true);
  31. } finally {
  32. $this->container = null;
  33. }
  34. }
  35. /**
  36. * Processes a value found in a definition tree.
  37. *
  38. * @param mixed $value
  39. * @param bool $isRoot
  40. *
  41. * @return mixed The processed value
  42. */
  43. protected function processValue($value, $isRoot = false)
  44. {
  45. if (\is_array($value)) {
  46. foreach ($value as $k => $v) {
  47. if ($isRoot) {
  48. $this->currentId = $k;
  49. }
  50. if ($v !== $processedValue = $this->processValue($v, $isRoot)) {
  51. $value[$k] = $processedValue;
  52. }
  53. }
  54. } elseif ($value instanceof ArgumentInterface) {
  55. $value->setValues($this->processValue($value->getValues()));
  56. } elseif ($value instanceof Definition) {
  57. $value->setArguments($this->processValue($value->getArguments()));
  58. $value->setProperties($this->processValue($value->getProperties()));
  59. $value->setMethodCalls($this->processValue($value->getMethodCalls()));
  60. $changes = $value->getChanges();
  61. if (isset($changes['factory'])) {
  62. $value->setFactory($this->processValue($value->getFactory()));
  63. }
  64. if (isset($changes['configurator'])) {
  65. $value->setConfigurator($this->processValue($value->getConfigurator()));
  66. }
  67. }
  68. return $value;
  69. }
  70. /**
  71. * @param Definition $definition
  72. * @param bool $required
  73. *
  74. * @return \ReflectionFunctionAbstract|null
  75. *
  76. * @throws RuntimeException
  77. */
  78. protected function getConstructor(Definition $definition, $required)
  79. {
  80. if (is_string($factory = $definition->getFactory())) {
  81. if (!function_exists($factory)) {
  82. throw new RuntimeException(sprintf('Unable to resolve service "%s": function "%s" does not exist.', $this->currentId, $factory));
  83. }
  84. $r = new \ReflectionFunction($factory);
  85. if (false !== $r->getFileName() && file_exists($r->getFileName())) {
  86. $this->container->fileExists($r->getFileName());
  87. }
  88. return $r;
  89. }
  90. if ($factory) {
  91. list($class, $method) = $factory;
  92. if ($class instanceof Reference) {
  93. $class = $this->container->findDefinition((string) $class)->getClass();
  94. } elseif (null === $class) {
  95. $class = $definition->getClass();
  96. }
  97. if ('__construct' === $method) {
  98. throw new RuntimeException(sprintf('Unable to resolve service "%s": "__construct()" cannot be used as a factory method.', $this->currentId));
  99. }
  100. return $this->getReflectionMethod(new Definition($class), $method);
  101. }
  102. $class = $definition->getClass();
  103. if (!$r = $this->container->getReflectionClass($class)) {
  104. throw new RuntimeException(sprintf('Unable to resolve service "%s": class "%s" does not exist.', $this->currentId, $class));
  105. }
  106. if (!$r = $r->getConstructor()) {
  107. if ($required) {
  108. throw new RuntimeException(sprintf('Unable to resolve service "%s": class%s has no constructor.', $this->currentId, sprintf($class !== $this->currentId ? ' "%s"' : '', $class)));
  109. }
  110. } elseif (!$r->isPublic()) {
  111. throw new RuntimeException(sprintf('Unable to resolve service "%s": %s must be public.', $this->currentId, sprintf($class !== $this->currentId ? 'constructor of class "%s"' : 'its constructor', $class)));
  112. }
  113. return $r;
  114. }
  115. /**
  116. * @param Definition $definition
  117. * @param string $method
  118. *
  119. * @throws RuntimeException
  120. *
  121. * @return \ReflectionFunctionAbstract
  122. */
  123. protected function getReflectionMethod(Definition $definition, $method)
  124. {
  125. if ('__construct' === $method) {
  126. return $this->getConstructor($definition, true);
  127. }
  128. if (!$class = $definition->getClass()) {
  129. throw new RuntimeException(sprintf('Unable to resolve service "%s": the class is not set.', $this->currentId));
  130. }
  131. if (!$r = $this->container->getReflectionClass($class)) {
  132. throw new RuntimeException(sprintf('Unable to resolve service "%s": class "%s" does not exist.', $this->currentId, $class));
  133. }
  134. if (!$r->hasMethod($method)) {
  135. throw new RuntimeException(sprintf('Unable to resolve service "%s": method "%s()" does not exist.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
  136. }
  137. $r = $r->getMethod($method);
  138. if (!$r->isPublic()) {
  139. throw new RuntimeException(sprintf('Unable to resolve service "%s": method "%s()" must be public.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
  140. }
  141. return $r;
  142. }
  143. }