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