TranslatorPathsPass.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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\Translation\DependencyInjection;
  11. use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass;
  12. use Symfony\Component\DependencyInjection\ContainerBuilder;
  13. use Symfony\Component\DependencyInjection\Definition;
  14. use Symfony\Component\DependencyInjection\Reference;
  15. use Symfony\Component\DependencyInjection\ServiceLocator;
  16. use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver;
  17. /**
  18. * @author Yonel Ceruto <yonelceruto@gmail.com>
  19. */
  20. class TranslatorPathsPass extends AbstractRecursivePass
  21. {
  22. private int $level = 0;
  23. /**
  24. * @var array<string, bool>
  25. */
  26. private array $paths = [];
  27. /**
  28. * @var array<int, Definition>
  29. */
  30. private array $definitions = [];
  31. /**
  32. * @var array<string, array<string, bool>>
  33. */
  34. private array $controllers = [];
  35. public function process(ContainerBuilder $container)
  36. {
  37. if (!$container->hasDefinition('translator')) {
  38. return;
  39. }
  40. foreach ($this->findControllerArguments($container) as $controller => $argument) {
  41. $id = substr($controller, 0, strpos($controller, ':') ?: \strlen($controller));
  42. if ($container->hasDefinition($id)) {
  43. [$locatorRef] = $argument->getValues();
  44. $this->controllers[(string) $locatorRef][$container->getDefinition($id)->getClass()] = true;
  45. }
  46. }
  47. try {
  48. parent::process($container);
  49. $paths = [];
  50. foreach ($this->paths as $class => $_) {
  51. if (($r = $container->getReflectionClass($class)) && !$r->isInterface()) {
  52. $paths[] = $r->getFileName();
  53. foreach ($r->getTraits() as $trait) {
  54. $paths[] = $trait->getFileName();
  55. }
  56. }
  57. }
  58. if ($paths) {
  59. if ($container->hasDefinition('console.command.translation_debug')) {
  60. $definition = $container->getDefinition('console.command.translation_debug');
  61. $definition->replaceArgument(6, array_merge($definition->getArgument(6), $paths));
  62. }
  63. if ($container->hasDefinition('console.command.translation_extract')) {
  64. $definition = $container->getDefinition('console.command.translation_extract');
  65. $definition->replaceArgument(7, array_merge($definition->getArgument(7), $paths));
  66. }
  67. }
  68. } finally {
  69. $this->level = 0;
  70. $this->paths = [];
  71. $this->definitions = [];
  72. }
  73. }
  74. protected function processValue(mixed $value, bool $isRoot = false): mixed
  75. {
  76. if ($value instanceof Reference) {
  77. if ('translator' === (string) $value) {
  78. for ($i = $this->level - 1; $i >= 0; --$i) {
  79. $class = $this->definitions[$i]->getClass();
  80. if (ServiceLocator::class === $class) {
  81. if (!isset($this->controllers[$this->currentId])) {
  82. continue;
  83. }
  84. foreach ($this->controllers[$this->currentId] as $class => $_) {
  85. $this->paths[$class] = true;
  86. }
  87. } else {
  88. $this->paths[$class] = true;
  89. }
  90. break;
  91. }
  92. }
  93. return $value;
  94. }
  95. if ($value instanceof Definition) {
  96. $this->definitions[$this->level++] = $value;
  97. $value = parent::processValue($value, $isRoot);
  98. unset($this->definitions[--$this->level]);
  99. return $value;
  100. }
  101. return parent::processValue($value, $isRoot);
  102. }
  103. private function findControllerArguments(ContainerBuilder $container): array
  104. {
  105. if (!$container->has('argument_resolver.service')) {
  106. return [];
  107. }
  108. $resolverDef = $container->findDefinition('argument_resolver.service');
  109. if (TraceableValueResolver::class === $resolverDef->getClass()) {
  110. $resolverDef = $container->getDefinition($resolverDef->getArgument(0));
  111. }
  112. $argument = $resolverDef->getArgument(0);
  113. if ($argument instanceof Reference) {
  114. $argument = $container->getDefinition($argument);
  115. }
  116. return $argument->getArgument(0);
  117. }
  118. }