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; 16 17/** 18 * Represents a node in the AST. 19 * 20 * @author Fabien Potencier <fabien@symfony.com> 21 */ 22class Node implements \Twig_NodeInterface 23{ 24 protected $nodes; 25 protected $attributes; 26 protected $lineno; 27 protected $tag; 28 29 private $name; 30 31 /** 32 * Constructor. 33 * 34 * The nodes are automatically made available as properties ($this->node). 35 * The attributes are automatically made available as array items ($this['name']). 36 * 37 * @param array $nodes An array of named nodes 38 * @param array $attributes An array of attributes (should not be nodes) 39 * @param int $lineno The line number 40 * @param string $tag The tag name associated with the Node 41 */ 42 public function __construct(array $nodes = [], array $attributes = [], $lineno = 0, $tag = null) 43 { 44 foreach ($nodes as $name => $node) { 45 if (!$node instanceof \Twig_NodeInterface) { 46 @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); 47 } 48 } 49 $this->nodes = $nodes; 50 $this->attributes = $attributes; 51 $this->lineno = $lineno; 52 $this->tag = $tag; 53 } 54 55 public function __toString() 56 { 57 $attributes = []; 58 foreach ($this->attributes as $name => $value) { 59 $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true))); 60 } 61 62 $repr = [\get_class($this).'('.implode(', ', $attributes)]; 63 64 if (\count($this->nodes)) { 65 foreach ($this->nodes as $name => $node) { 66 $len = \strlen($name) + 4; 67 $noderepr = []; 68 foreach (explode("\n", (string) $node) as $line) { 69 $noderepr[] = str_repeat(' ', $len).$line; 70 } 71 72 $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr))); 73 } 74 75 $repr[] = ')'; 76 } else { 77 $repr[0] .= ')'; 78 } 79 80 return implode("\n", $repr); 81 } 82 83 /** 84 * @deprecated since 1.16.1 (to be removed in 2.0) 85 */ 86 public function toXml($asDom = false) 87 { 88 @trigger_error(sprintf('%s is deprecated since version 1.16.1 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); 89 90 $dom = new \DOMDocument('1.0', 'UTF-8'); 91 $dom->formatOutput = true; 92 $dom->appendChild($xml = $dom->createElement('twig')); 93 94 $xml->appendChild($node = $dom->createElement('node')); 95 $node->setAttribute('class', \get_class($this)); 96 97 foreach ($this->attributes as $name => $value) { 98 $node->appendChild($attribute = $dom->createElement('attribute')); 99 $attribute->setAttribute('name', $name); 100 $attribute->appendChild($dom->createTextNode($value)); 101 } 102 103 foreach ($this->nodes as $name => $n) { 104 if (null === $n) { 105 continue; 106 } 107 108 $child = $n->toXml(true)->getElementsByTagName('node')->item(0); 109 $child = $dom->importNode($child, true); 110 $child->setAttribute('name', $name); 111 112 $node->appendChild($child); 113 } 114 115 return $asDom ? $dom : $dom->saveXML(); 116 } 117 118 public function compile(Compiler $compiler) 119 { 120 foreach ($this->nodes as $node) { 121 $node->compile($compiler); 122 } 123 } 124 125 public function getTemplateLine() 126 { 127 return $this->lineno; 128 } 129 130 /** 131 * @deprecated since 1.27 (to be removed in 2.0) 132 */ 133 public function getLine() 134 { 135 @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateLine() instead.', E_USER_DEPRECATED); 136 137 return $this->lineno; 138 } 139 140 public function getNodeTag() 141 { 142 return $this->tag; 143 } 144 145 /** 146 * @return bool 147 */ 148 public function hasAttribute($name) 149 { 150 return \array_key_exists($name, $this->attributes); 151 } 152 153 /** 154 * @return mixed 155 */ 156 public function getAttribute($name) 157 { 158 if (!\array_key_exists($name, $this->attributes)) { 159 throw new \LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, \get_class($this))); 160 } 161 162 return $this->attributes[$name]; 163 } 164 165 /** 166 * @param string $name 167 * @param mixed $value 168 */ 169 public function setAttribute($name, $value) 170 { 171 $this->attributes[$name] = $value; 172 } 173 174 public function removeAttribute($name) 175 { 176 unset($this->attributes[$name]); 177 } 178 179 /** 180 * @return bool 181 */ 182 public function hasNode($name) 183 { 184 return \array_key_exists($name, $this->nodes); 185 } 186 187 /** 188 * @return Node 189 */ 190 public function getNode($name) 191 { 192 if (!\array_key_exists($name, $this->nodes)) { 193 throw new \LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, \get_class($this))); 194 } 195 196 return $this->nodes[$name]; 197 } 198 199 public function setNode($name, $node = null) 200 { 201 if (!$node instanceof \Twig_NodeInterface) { 202 @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); 203 } 204 205 $this->nodes[$name] = $node; 206 } 207 208 public function removeNode($name) 209 { 210 unset($this->nodes[$name]); 211 } 212 213 public function count() 214 { 215 return \count($this->nodes); 216 } 217 218 public function getIterator() 219 { 220 return new \ArrayIterator($this->nodes); 221 } 222 223 public function setTemplateName($name) 224 { 225 $this->name = $name; 226 foreach ($this->nodes as $node) { 227 if (null !== $node) { 228 $node->setTemplateName($name); 229 } 230 } 231 } 232 233 public function getTemplateName() 234 { 235 return $this->name; 236 } 237 238 /** 239 * @deprecated since 1.27 (to be removed in 2.0) 240 */ 241 public function setFilename($name) 242 { 243 @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use setTemplateName() instead.', E_USER_DEPRECATED); 244 245 $this->setTemplateName($name); 246 } 247 248 /** 249 * @deprecated since 1.27 (to be removed in 2.0) 250 */ 251 public function getFilename() 252 { 253 @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateName() instead.', E_USER_DEPRECATED); 254 255 return $this->name; 256 } 257} 258 259class_alias('Twig\Node\Node', 'Twig_Node'); 260 261// Ensure that the aliased name is loaded to keep BC for classes implementing the typehint with the old aliased name. 262class_exists('Twig\Compiler'); 263