TranslationDefaultDomainNodeVisitor.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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\Bridge\Twig\NodeVisitor;
  11. use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
  12. use Symfony\Bridge\Twig\Node\TransNode;
  13. use Twig\Environment;
  14. use Twig\Node\BlockNode;
  15. use Twig\Node\Expression\ArrayExpression;
  16. use Twig\Node\Expression\AssignNameExpression;
  17. use Twig\Node\Expression\ConstantExpression;
  18. use Twig\Node\Expression\FilterExpression;
  19. use Twig\Node\Expression\NameExpression;
  20. use Twig\Node\ModuleNode;
  21. use Twig\Node\Node;
  22. use Twig\Node\SetNode;
  23. use Twig\NodeVisitor\AbstractNodeVisitor;
  24. /**
  25. * @author Fabien Potencier <fabien@symfony.com>
  26. */
  27. final class TranslationDefaultDomainNodeVisitor extends AbstractNodeVisitor
  28. {
  29. private $scope;
  30. public function __construct()
  31. {
  32. $this->scope = new Scope();
  33. }
  34. /**
  35. * {@inheritdoc}
  36. */
  37. protected function doEnterNode(Node $node, Environment $env): Node
  38. {
  39. if ($node instanceof BlockNode || $node instanceof ModuleNode) {
  40. $this->scope = $this->scope->enter();
  41. }
  42. if ($node instanceof TransDefaultDomainNode) {
  43. if ($node->getNode('expr') instanceof ConstantExpression) {
  44. $this->scope->set('domain', $node->getNode('expr'));
  45. return $node;
  46. } else {
  47. $var = $this->getVarName();
  48. $name = new AssignNameExpression($var, $node->getTemplateLine());
  49. $this->scope->set('domain', new NameExpression($var, $node->getTemplateLine()));
  50. return new SetNode(false, new Node([$name]), new Node([$node->getNode('expr')]), $node->getTemplateLine());
  51. }
  52. }
  53. if (!$this->scope->has('domain')) {
  54. return $node;
  55. }
  56. if ($node instanceof FilterExpression && 'trans' === $node->getNode('filter')->getAttribute('value')) {
  57. $arguments = $node->getNode('arguments');
  58. if ($this->isNamedArguments($arguments)) {
  59. if (!$arguments->hasNode('domain') && !$arguments->hasNode(1)) {
  60. $arguments->setNode('domain', $this->scope->get('domain'));
  61. }
  62. } elseif (!$arguments->hasNode(1)) {
  63. if (!$arguments->hasNode(0)) {
  64. $arguments->setNode(0, new ArrayExpression([], $node->getTemplateLine()));
  65. }
  66. $arguments->setNode(1, $this->scope->get('domain'));
  67. }
  68. } elseif ($node instanceof TransNode) {
  69. if (!$node->hasNode('domain')) {
  70. $node->setNode('domain', $this->scope->get('domain'));
  71. }
  72. }
  73. return $node;
  74. }
  75. /**
  76. * {@inheritdoc}
  77. */
  78. protected function doLeaveNode(Node $node, Environment $env): ?Node
  79. {
  80. if ($node instanceof TransDefaultDomainNode) {
  81. return null;
  82. }
  83. if ($node instanceof BlockNode || $node instanceof ModuleNode) {
  84. $this->scope = $this->scope->leave();
  85. }
  86. return $node;
  87. }
  88. /**
  89. * {@inheritdoc}
  90. */
  91. public function getPriority(): int
  92. {
  93. return -10;
  94. }
  95. private function isNamedArguments(Node $arguments): bool
  96. {
  97. foreach ($arguments as $name => $node) {
  98. if (!\is_int($name)) {
  99. return true;
  100. }
  101. }
  102. return false;
  103. }
  104. private function getVarName(): string
  105. {
  106. return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
  107. }
  108. }