1<?php 2 3/* 4 * This file is part of Twig. 5 * 6 * (c) Fabien Potencier 7 * (c) Armin Ronacher 8 * 9 * For the full copyright and license information, please view the LICENSE 10 * file that was distributed with this source code. 11 */ 12 13namespace Twig\Node; 14 15use Twig\Compiler; 16use Twig\Source; 17 18/** 19 * Represents a node in the AST. 20 * 21 * @author Fabien Potencier <fabien@symfony.com> 22 */ 23class Node implements \Countable, \IteratorAggregate 24{ 25 protected $nodes; 26 protected $attributes; 27 protected $lineno; 28 protected $tag; 29 30 private $name; 31 private $sourceContext; 32 33 /** 34 * @param array $nodes An array of named nodes 35 * @param array $attributes An array of attributes (should not be nodes) 36 * @param int $lineno The line number 37 * @param string $tag The tag name associated with the Node 38 */ 39 public function __construct(array $nodes = [], array $attributes = [], int $lineno = 0, string $tag = null) 40 { 41 foreach ($nodes as $name => $node) { 42 if (!$node instanceof self) { 43 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) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, static::class)); 44 } 45 } 46 $this->nodes = $nodes; 47 $this->attributes = $attributes; 48 $this->lineno = $lineno; 49 $this->tag = $tag; 50 } 51 52 public function __toString() 53 { 54 $attributes = []; 55 foreach ($this->attributes as $name => $value) { 56 $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true))); 57 } 58 59 $repr = [static::class.'('.implode(', ', $attributes)]; 60 61 if (\count($this->nodes)) { 62 foreach ($this->nodes as $name => $node) { 63 $len = \strlen($name) + 4; 64 $noderepr = []; 65 foreach (explode("\n", (string) $node) as $line) { 66 $noderepr[] = str_repeat(' ', $len).$line; 67 } 68 69 $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr))); 70 } 71 72 $repr[] = ')'; 73 } else { 74 $repr[0] .= ')'; 75 } 76 77 return implode("\n", $repr); 78 } 79 80 public function compile(Compiler $compiler) 81 { 82 foreach ($this->nodes as $node) { 83 $node->compile($compiler); 84 } 85 } 86 87 public function getTemplateLine() 88 { 89 return $this->lineno; 90 } 91 92 public function getNodeTag() 93 { 94 return $this->tag; 95 } 96 97 /** 98 * @return bool 99 */ 100 public function hasAttribute($name) 101 { 102 return \array_key_exists($name, $this->attributes); 103 } 104 105 /** 106 * @return mixed 107 */ 108 public function getAttribute($name) 109 { 110 if (!\array_key_exists($name, $this->attributes)) { 111 throw new \LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, static::class)); 112 } 113 114 return $this->attributes[$name]; 115 } 116 117 /** 118 * @param string $name 119 * @param mixed $value 120 */ 121 public function setAttribute($name, $value) 122 { 123 $this->attributes[$name] = $value; 124 } 125 126 public function removeAttribute($name) 127 { 128 unset($this->attributes[$name]); 129 } 130 131 /** 132 * @return bool 133 */ 134 public function hasNode($name) 135 { 136 return isset($this->nodes[$name]); 137 } 138 139 /** 140 * @return Node 141 */ 142 public function getNode($name) 143 { 144 if (!isset($this->nodes[$name])) { 145 throw new \LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, static::class)); 146 } 147 148 return $this->nodes[$name]; 149 } 150 151 public function setNode($name, self $node) 152 { 153 $this->nodes[$name] = $node; 154 } 155 156 public function removeNode($name) 157 { 158 unset($this->nodes[$name]); 159 } 160 161 public function count() 162 { 163 return \count($this->nodes); 164 } 165 166 public function getIterator() 167 { 168 return new \ArrayIterator($this->nodes); 169 } 170 171 /** 172 * @deprecated since 2.8 (to be removed in 3.0) 173 */ 174 public function setTemplateName($name/*, $triggerDeprecation = true */) 175 { 176 $triggerDeprecation = 2 > \func_num_args() || \func_get_arg(1); 177 if ($triggerDeprecation) { 178 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0. Use setSourceContext() instead.', E_USER_DEPRECATED); 179 } 180 181 $this->name = $name; 182 foreach ($this->nodes as $node) { 183 $node->setTemplateName($name, $triggerDeprecation); 184 } 185 } 186 187 public function getTemplateName() 188 { 189 return $this->sourceContext ? $this->sourceContext->getName() : null; 190 } 191 192 public function setSourceContext(Source $source) 193 { 194 $this->sourceContext = $source; 195 foreach ($this->nodes as $node) { 196 $node->setSourceContext($source); 197 } 198 199 $this->setTemplateName($source->getName(), false); 200 } 201 202 public function getSourceContext() 203 { 204 return $this->sourceContext; 205 } 206} 207 208class_alias('Twig\Node\Node', 'Twig_Node'); 209 210// Ensure that the aliased name is loaded to keep BC for classes implementing the typehint with the old aliased name. 211class_exists('Twig\Compiler'); 212