vendor/twig/twig/src/Node/Node.php line 206

  1. <?php
  2. /*
  3.  * This file is part of Twig.
  4.  *
  5.  * (c) Fabien Potencier
  6.  * (c) Armin Ronacher
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace Twig\Node;
  12. use Twig\Attribute\YieldReady;
  13. use Twig\Compiler;
  14. use Twig\Source;
  15. /**
  16.  * Represents a node in the AST.
  17.  *
  18.  * @author Fabien Potencier <fabien@symfony.com>
  19.  */
  20. #[YieldReady]
  21. class Node implements \Countable\IteratorAggregate
  22. {
  23.     /**
  24.      * @var array<string|int, Node>
  25.      */
  26.     protected $nodes;
  27.     protected $attributes;
  28.     protected $lineno;
  29.     protected $tag;
  30.     private $sourceContext;
  31.     /** @var array<string, NameDeprecation> */
  32.     private $nodeNameDeprecations = [];
  33.     /** @var array<string, NameDeprecation> */
  34.     private $attributeNameDeprecations = [];
  35.     /**
  36.      * @param array<string|int, Node> $nodes      An array of named nodes
  37.      * @param array                   $attributes An array of attributes (should not be nodes)
  38.      * @param int                     $lineno     The line number
  39.      */
  40.     public function __construct(array $nodes = [], array $attributes = [], int $lineno 0)
  41.     {
  42.         foreach ($nodes as $name => $node) {
  43.             if (!$node instanceof self) {
  44.                 throw new \InvalidArgumentException(\sprintf('Using "%s" for the value of node "%s" of "%s" is not supported. You must pass a \Twig\Node\Node instance.'\is_object($node) ? $node::class : (null === $node 'null' \gettype($node)), $name, static::class));
  45.             }
  46.         }
  47.         $this->nodes $nodes;
  48.         $this->attributes $attributes;
  49.         $this->lineno $lineno;
  50.         if (\func_num_args() > 3) {
  51.             trigger_deprecation('twig/twig''3.12'\sprintf('The "tag" constructor argument of the "%s" class is deprecated and ignored (check which TokenParser class set it to "%s"), the tag is now automatically set by the Parser when needed.', static::class, func_get_arg(3) ?: 'null'));
  52.         }
  53.     }
  54.     public function __toString()
  55.     {
  56.         $repr = static::class;
  57.         if ($this->tag) {
  58.             $repr .= \sprintf("\n  tag: %s"$this->tag);
  59.         }
  60.         $attributes = [];
  61.         foreach ($this->attributes as $name => $value) {
  62.             if (\is_callable($value)) {
  63.                 $v '\Closure';
  64.             } elseif ($value instanceof \Stringable) {
  65.                 $v = (string) $value;
  66.             } else {
  67.                 $v str_replace("\n"''var_export($valuetrue));
  68.             }
  69.             $attributes[] = \sprintf('%s: %s'$name$v);
  70.         }
  71.         if ($attributes) {
  72.             $repr .= \sprintf("\n  attributes:\n    %s"implode("\n    "$attributes));
  73.         }
  74.         if (\count($this->nodes)) {
  75.             $repr .= "\n  nodes:";
  76.             foreach ($this->nodes as $name => $node) {
  77.                 $len \strlen($name) + 6;
  78.                 $noderepr = [];
  79.                 foreach (explode("\n", (string) $node) as $line) {
  80.                     $noderepr[] = str_repeat(' '$len).$line;
  81.                 }
  82.                 $repr .= \sprintf("\n    %s: %s"$nameltrim(implode("\n"$noderepr)));
  83.             }
  84.         }
  85.         return $repr;
  86.     }
  87.     /**
  88.      * @return void
  89.      */
  90.     public function compile(Compiler $compiler)
  91.     {
  92.         foreach ($this->nodes as $node) {
  93.             $compiler->subcompile($node);
  94.         }
  95.     }
  96.     public function getTemplateLine(): int
  97.     {
  98.         return $this->lineno;
  99.     }
  100.     public function getNodeTag(): ?string
  101.     {
  102.         return $this->tag;
  103.     }
  104.     /**
  105.      * @internal
  106.      */
  107.     public function setNodeTag(string $tag): void
  108.     {
  109.         if ($this->tag) {
  110.             throw new \LogicException('The tag of a node can only be set once.');
  111.         }
  112.         $this->tag $tag;
  113.     }
  114.     public function hasAttribute(string $name): bool
  115.     {
  116.         return \array_key_exists($name$this->attributes);
  117.     }
  118.     public function getAttribute(string $name)
  119.     {
  120.         if (!\array_key_exists($name$this->attributes)) {
  121.             throw new \LogicException(\sprintf('Attribute "%s" does not exist for Node "%s".'$name, static::class));
  122.         }
  123.         $triggerDeprecation \func_num_args() > func_get_arg(1) : true;
  124.         if ($triggerDeprecation && isset($this->attributeNameDeprecations[$name])) {
  125.             $dep $this->attributeNameDeprecations[$name];
  126.             if ($dep->getNewName()) {
  127.                 trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting attribute "%s" on a "%s" class is deprecated, get the "%s" attribute instead.'$name, static::class, $dep->getNewName());
  128.             } else {
  129.                 trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting attribute "%s" on a "%s" class is deprecated.'$name, static::class);
  130.             }
  131.         }
  132.         return $this->attributes[$name];
  133.     }
  134.     public function setAttribute(string $name$value): void
  135.     {
  136.         $triggerDeprecation \func_num_args() > func_get_arg(2) : true;
  137.         if ($triggerDeprecation && isset($this->attributeNameDeprecations[$name])) {
  138.             $dep $this->attributeNameDeprecations[$name];
  139.             if ($dep->getNewName()) {
  140.                 trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting attribute "%s" on a "%s" class is deprecated, set the "%s" attribute instead.'$name, static::class, $dep->getNewName());
  141.             } else {
  142.                 trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting attribute "%s" on a "%s" class is deprecated.'$name, static::class);
  143.             }
  144.         }
  145.         $this->attributes[$name] = $value;
  146.     }
  147.     public function deprecateAttribute(string $nameNameDeprecation $dep): void
  148.     {
  149.         $this->attributeNameDeprecations[$name] = $dep;
  150.     }
  151.     public function removeAttribute(string $name): void
  152.     {
  153.         unset($this->attributes[$name]);
  154.     }
  155.     /**
  156.      * @param string|int $name
  157.      */
  158.     public function hasNode(string $name): bool
  159.     {
  160.         return isset($this->nodes[$name]);
  161.     }
  162.     /**
  163.      * @param string|int $name
  164.      */
  165.     public function getNode(string $name): self
  166.     {
  167.         if (!isset($this->nodes[$name])) {
  168.             throw new \LogicException(\sprintf('Node "%s" does not exist for Node "%s".'$name, static::class));
  169.         }
  170.         $triggerDeprecation \func_num_args() > func_get_arg(1) : true;
  171.         if ($triggerDeprecation && isset($this->nodeNameDeprecations[$name])) {
  172.             $dep $this->nodeNameDeprecations[$name];
  173.             if ($dep->getNewName()) {
  174.                 trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting node "%s" on a "%s" class is deprecated, get the "%s" node instead.'$name, static::class, $dep->getNewName());
  175.             } else {
  176.                 trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting node "%s" on a "%s" class is deprecated.'$name, static::class);
  177.             }
  178.         }
  179.         return $this->nodes[$name];
  180.     }
  181.     /**
  182.      * @param string|int $name
  183.      */
  184.     public function setNode(string $nameself $node): void
  185.     {
  186.         $triggerDeprecation \func_num_args() > func_get_arg(2) : true;
  187.         if ($triggerDeprecation && isset($this->nodeNameDeprecations[$name])) {
  188.             $dep $this->nodeNameDeprecations[$name];
  189.             if ($dep->getNewName()) {
  190.                 trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting node "%s" on a "%s" class is deprecated, set the "%s" node instead.'$name, static::class, $dep->getNewName());
  191.             } else {
  192.                 trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting node "%s" on a "%s" class is deprecated.'$name, static::class);
  193.             }
  194.         }
  195.         if (null !== $this->sourceContext) {
  196.             $node->setSourceContext($this->sourceContext);
  197.         }
  198.         $this->nodes[$name] = $node;
  199.     }
  200.     /**
  201.      * @param string|int $name
  202.      */
  203.     public function removeNode(string $name): void
  204.     {
  205.         unset($this->nodes[$name]);
  206.     }
  207.     /**
  208.      * @param string|int $name
  209.      */
  210.     public function deprecateNode(string $nameNameDeprecation $dep): void
  211.     {
  212.         $this->nodeNameDeprecations[$name] = $dep;
  213.     }
  214.     /**
  215.      * @return int
  216.      */
  217.     #[\ReturnTypeWillChange]
  218.     public function count()
  219.     {
  220.         return \count($this->nodes);
  221.     }
  222.     public function getIterator(): \Traversable
  223.     {
  224.         return new \ArrayIterator($this->nodes);
  225.     }
  226.     public function getTemplateName(): ?string
  227.     {
  228.         return $this->sourceContext $this->sourceContext->getName() : null;
  229.     }
  230.     public function setSourceContext(Source $source): void
  231.     {
  232.         $this->sourceContext $source;
  233.         foreach ($this->nodes as $node) {
  234.             $node->setSourceContext($source);
  235.         }
  236.     }
  237.     public function getSourceContext(): ?Source
  238.     {
  239.         return $this->sourceContext;
  240.     }
  241. }