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 \Twig_NodeInterface 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 = [], $lineno = 0, $tag = null) 40 { 41 foreach ($nodes as $name => $node) { 42 if (!$node instanceof \Twig_NodeInterface) { 43 @trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, \get_class($this)), E_USER_DEPRECATED); 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 = [\get_class($this).'('.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 /** 81 * @deprecated since 1.16.1 (to be removed in 2.0) 82 */ 83 public function toXml($asDom = false) 84 { 85 @trigger_error(sprintf('%s is deprecated since version 1.16.1 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); 86 87 $dom = new \DOMDocument('1.0', 'UTF-8'); 88 $dom->formatOutput = true; 89 $dom->appendChild($xml = $dom->createElement('twig')); 90 91 $xml->appendChild($node = $dom->createElement('node')); 92 $node->setAttribute('class', \get_class($this)); 93 94 foreach ($this->attributes as $name => $value) { 95 $node->appendChild($attribute = $dom->createElement('attribute')); 96 $attribute->setAttribute('name', $name); 97 $attribute->appendChild($dom->createTextNode($value)); 98 } 99 100 foreach ($this->nodes as $name => $n) { 101 if (null === $n) { 102 continue; 103 } 104 105 $child = $n->toXml(true)->getElementsByTagName('node')->item(0); 106 $child = $dom->importNode($child, true); 107 $child->setAttribute('name', $name); 108 109 $node->appendChild($child); 110 } 111 112 return $asDom ? $dom : $dom->saveXML(); 113 } 114 115 public function compile(Compiler $compiler) 116 { 117 foreach ($this->nodes as $node) { 118 $node->compile($compiler); 119 } 120 } 121 122 public function getTemplateLine() 123 { 124 return $this->lineno; 125 } 126 127 /** 128 * @deprecated since 1.27 (to be removed in 2.0) 129 */ 130 public function getLine() 131 { 132 @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateLine() instead.', E_USER_DEPRECATED); 133 134 return $this->lineno; 135 } 136 137 public function getNodeTag() 138 { 139 return $this->tag; 140 } 141 142 /** 143 * @return bool 144 */ 145 public function hasAttribute($name) 146 { 147 return \array_key_exists($name, $this->attributes); 148 } 149 150 /** 151 * @return mixed 152 */ 153 public function getAttribute($name) 154 { 155 if (!\array_key_exists($name, $this->attributes)) { 156 throw new \LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, \get_class($this))); 157 } 158 159 return $this->attributes[$name]; 160 } 161 162 /** 163 * @param string $name 164 * @param mixed $value 165 */ 166 public function setAttribute($name, $value) 167 { 168 $this->attributes[$name] = $value; 169 } 170 171 public function removeAttribute($name) 172 { 173 unset($this->attributes[$name]); 174 } 175 176 /** 177 * @return bool 178 */ 179 public function hasNode($name) 180 { 181 return \array_key_exists($name, $this->nodes); 182 } 183 184 /** 185 * @return Node 186 */ 187 public function getNode($name) 188 { 189 if (!\array_key_exists($name, $this->nodes)) { 190 throw new \LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, \get_class($this))); 191 } 192 193 return $this->nodes[$name]; 194 } 195 196 public function setNode($name, $node = null) 197 { 198 if (!$node instanceof \Twig_NodeInterface) { 199 @trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, \get_class($this)), E_USER_DEPRECATED); 200 } 201 202 $this->nodes[$name] = $node; 203 } 204 205 public function removeNode($name) 206 { 207 unset($this->nodes[$name]); 208 } 209 210 public function count() 211 { 212 return \count($this->nodes); 213 } 214 215 public function getIterator() 216 { 217 return new \ArrayIterator($this->nodes); 218 } 219 220 public function setTemplateName($name) 221 { 222 $this->name = $name; 223 foreach ($this->nodes as $node) { 224 if (null !== $node) { 225 $node->setTemplateName($name); 226 } 227 } 228 } 229 230 public function getTemplateName() 231 { 232 return $this->name; 233 } 234 235 public function setSourceContext(Source $source) 236 { 237 $this->sourceContext = $source; 238 foreach ($this->nodes as $node) { 239 if ($node instanceof Node) { 240 $node->setSourceContext($source); 241 } 242 } 243 } 244 245 public function getSourceContext() 246 { 247 return $this->sourceContext; 248 } 249 250 /** 251 * @deprecated since 1.27 (to be removed in 2.0) 252 */ 253 public function setFilename($name) 254 { 255 @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use setTemplateName() instead.', E_USER_DEPRECATED); 256 257 $this->setTemplateName($name); 258 } 259 260 /** 261 * @deprecated since 1.27 (to be removed in 2.0) 262 */ 263 public function getFilename() 264 { 265 @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateName() instead.', E_USER_DEPRECATED); 266 267 return $this->name; 268 } 269} 270 271class_alias('Twig\Node\Node', 'Twig_Node'); 272 273// Ensure that the aliased name is loaded to keep BC for classes implementing the typehint with the old aliased name. 274class_exists('Twig\Compiler'); 275