testGetAttributeWithSandbox()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 21
rs 9.0534
cc 4
eloc 13
nc 6
nop 4
1
<?php
2
3
/*
4
 * This file is part of Twig.
5
 *
6
 * (c) Fabien Potencier
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
12
{
13
    /**
14
     * @dataProvider getAttributeExceptions
15
     */
16
    public function testGetAttributeExceptions($template, $message, $useExt)
17
    {
18
        $name = 'index_'.($useExt ? 1 : 0);
19
        $templates = array(
20
            $name => $template.$useExt, // appending $useExt makes the template content unique
21
        );
22
23
        $env = new Twig_Environment(new Twig_Loader_Array($templates), array('strict_variables' => true));
24
        if (!$useExt) {
25
            $env->addNodeVisitor(new CExtDisablingNodeVisitor());
26
        }
27
        $template = $env->loadTemplate($name);
28
29
        $context = array(
30
            'string'          => 'foo',
31
            'empty_array'     => array(),
32
            'array'           => array('foo' => 'foo'),
33
            'array_access'    => new Twig_TemplateArrayAccessObject(),
34
            'magic_exception' => new Twig_TemplateMagicPropertyObjectWithException(),
35
            'object'          => new stdClass(),
36
        );
37
38
        try {
39
            $template->render($context);
40
            $this->fail('Accessing an invalid attribute should throw an exception.');
41
        } catch (Twig_Error_Runtime $e) {
42
            $this->assertSame(sprintf($message, $name), $e->getMessage());
43
        }
44
    }
45
46
    public function getAttributeExceptions()
47
    {
48
        $tests = array(
49
            array('{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1', false),
50
            array('{{ empty_array["a"] }}', 'Key "a" does not exist as the array is empty in "%s" at line 1', false),
51
            array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false),
52
            array('{{ array_access["a"] }}', 'Key "a" in object with ArrayAccess of class "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
53
            array('{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1', false),
54
            array('{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1', false),
55
            array('{{ empty_array.a }}', 'Key "a" does not exist as the array is empty in "%s" at line 1', false),
56
            array('{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false),
57
            array('{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1', false),
58
            array('{{ array_access.a }}', 'Method "a" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
59
            array('{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ _self.foo(array_access) }}', 'Method "missing_method" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
60
            array('{{ magic_exception.test }}', 'An exception has been thrown during the rendering of a template ("Hey! Don\'t try to isset me!") in "%s" at line 1.', false),
61
            array('{{ object["a"] }}', 'Impossible to access a key "a" on an object of class "stdClass" that does not implement ArrayAccess interface in "%s" at line 1', false),
62
        );
63
64
        if (function_exists('twig_template_get_attributes')) {
65
            foreach (array_slice($tests, 0) as $test) {
66
                $test[2] = true;
67
                $tests[] = $test;
68
            }
69
        }
70
71
        return $tests;
72
    }
73
74
    /**
75
     * @dataProvider getGetAttributeWithSandbox
76
     */
77
    public function testGetAttributeWithSandbox($object, $item, $allowed, $useExt)
78
    {
79
        $twig = new Twig_Environment();
80
        $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(/*method*/), array(/*prop*/), array());
81
        $twig->addExtension(new Twig_Extension_Sandbox($policy, !$allowed));
82
        $template = new Twig_TemplateTest($twig, $useExt);
83
84
        try {
85
            $template->getAttribute($object, $item, array(), 'any');
86
87
            if (!$allowed) {
88
                $this->fail();
89
            }
90
        } catch (Twig_Sandbox_SecurityError $e) {
91
            if ($allowed) {
92
                $this->fail();
93
            }
94
95
            $this->assertContains('is not allowed', $e->getMessage());
96
        }
97
    }
98
99
    public function getGetAttributeWithSandbox()
100
    {
101
        $tests = array(
102
            array(new Twig_TemplatePropertyObject(), 'defined', false, false),
103
            array(new Twig_TemplatePropertyObject(), 'defined', true, false),
104
            array(new Twig_TemplateMethodObject(), 'defined', false, false),
105
            array(new Twig_TemplateMethodObject(), 'defined', true, false),
106
        );
107
108
        if (function_exists('twig_template_get_attributes')) {
109
            foreach (array_slice($tests, 0) as $test) {
110
                $test[3] = true;
111
                $tests[] = $test;
112
            }
113
        }
114
115
        return $tests;
116
    }
117
118
    /**
119
     * @dataProvider getGetAttributeWithTemplateAsObject
120
     */
121
    public function testGetAttributeWithTemplateAsObject($useExt)
122
    {
123
        $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
124
        $template1 = new Twig_TemplateTest(new Twig_Environment(), false);
125
126
        $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'string'));
127
        $this->assertEquals('some_string', $template->getAttribute($template1, 'string'));
128
129
        $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'true'));
130
        $this->assertEquals('1', $template->getAttribute($template1, 'true'));
131
132
        $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'zero'));
133
        $this->assertEquals('0', $template->getAttribute($template1, 'zero'));
134
135
        $this->assertNotInstanceof('Twig_Markup', $template->getAttribute($template1, 'empty'));
136
        $this->assertSame('', $template->getAttribute($template1, 'empty'));
137
    }
138
139
    public function getGetAttributeWithTemplateAsObject()
140
    {
141
        $bools = array(
142
            array(false),
143
        );
144
145
        if (function_exists('twig_template_get_attributes')) {
146
            $bools[] = array(true);
147
        }
148
149
        return $bools;
150
    }
151
152
    /**
153
     * @dataProvider getTestsDependingOnExtensionAvailability
154
     */
155
    public function testGetAttributeOnArrayWithConfusableKey($useExt = false)
156
    {
157
        $template = new Twig_TemplateTest(
158
            new Twig_Environment(),
159
            $useExt
160
        );
161
162
        $array = array('Zero', 'One', -1 => 'MinusOne', '' => 'EmptyString', '1.5' => 'FloatButString', '01' => 'IntegerButStringWithLeadingZeros');
163
164
        $this->assertSame('Zero', $array[false]);
165
        $this->assertSame('One', $array[true]);
166
        $this->assertSame('One', $array[1.5]);
167
        $this->assertSame('One', $array['1']);
168
        $this->assertSame('MinusOne', $array[-1.5]);
169
        $this->assertSame('FloatButString', $array['1.5']);
170
        $this->assertSame('IntegerButStringWithLeadingZeros', $array['01']);
171
        $this->assertSame('EmptyString', $array[null]);
172
173
        $this->assertSame('Zero', $template->getAttribute($array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)');
174
        $this->assertSame('One', $template->getAttribute($array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)');
175
        $this->assertSame('One', $template->getAttribute($array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)');
176
        $this->assertSame('One', $template->getAttribute($array, '1'), '"1" is treated as integer 1 when accessing an array (equals PHP behavior)');
177
        $this->assertSame('MinusOne', $template->getAttribute($array, -1.5), 'negative float is casted to int when accessing an array (equals PHP behavior)');
178
        $this->assertSame('FloatButString', $template->getAttribute($array, '1.5'), '"1.5" is treated as-is when accessing an array (equals PHP behavior)');
179
        $this->assertSame('IntegerButStringWithLeadingZeros', $template->getAttribute($array, '01'), '"01" is treated as-is when accessing an array (equals PHP behavior)');
180
        $this->assertSame('EmptyString', $template->getAttribute($array, null), 'null is treated as "" when accessing an array (equals PHP behavior)');
181
    }
182
183
    public function getTestsDependingOnExtensionAvailability()
184
    {
185
        if (function_exists('twig_template_get_attributes')) {
186
            return array(array(false), array(true));
187
        }
188
189
        return array(array(false));
190
    }
191
192
    /**
193
     * @dataProvider getGetAttributeTests
194
     */
195
    public function testGetAttribute($defined, $value, $object, $item, $arguments, $type, $useExt = false)
196
    {
197
        $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
198
199
        $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
200
    }
201
202
    /**
203
     * @dataProvider getGetAttributeTests
204
     */
205
    public function testGetAttributeStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false, $exceptionMessage = null)
206
    {
207
        $template = new Twig_TemplateTest(new Twig_Environment(null, array('strict_variables' => true)), $useExt);
208
209
        if ($defined) {
210
            $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
211
        } else {
212
            try {
213
                $this->assertEquals($value, $template->getAttribute($object, $item, $arguments, $type));
214
215
                throw new Exception('Expected Twig_Error_Runtime exception.');
216
            } catch (Twig_Error_Runtime $e) {
217
                if (null !== $exceptionMessage) {
218
                    $this->assertSame($exceptionMessage, $e->getMessage());
219
                }
220
            }
221
        }
222
    }
223
224
    /**
225
     * @dataProvider getGetAttributeTests
226
     */
227
    public function testGetAttributeDefined($defined, $value, $object, $item, $arguments, $type, $useExt = false)
228
    {
229
        $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
230
231
        $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true));
232
    }
233
234
    /**
235
     * @dataProvider getGetAttributeTests
236
     */
237
    public function testGetAttributeDefinedStrict($defined, $value, $object, $item, $arguments, $type, $useExt = false)
238
    {
239
        $template = new Twig_TemplateTest(new Twig_Environment(null, array('strict_variables' => true)), $useExt);
240
241
        $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true));
242
    }
243
244
    /**
245
     * @dataProvider getTestsDependingOnExtensionAvailability
246
     */
247
    public function testGetAttributeCallExceptions($useExt = false)
248
    {
249
        $template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
250
251
        $object = new Twig_TemplateMagicMethodExceptionObject();
252
253
        $this->assertNull($template->getAttribute($object, 'foo'));
254
    }
255
256
    public function getGetAttributeTests()
257
    {
258
        $array = array(
259
            'defined' => 'defined',
260
            'zero'    => 0,
261
            'null'    => null,
262
            '1'       => 1,
263
            'bar'     => true,
264
            '09'      => '09',
265
            '+4'      => '+4',
266
        );
267
268
        $objectArray         = new Twig_TemplateArrayAccessObject();
269
        $stdObject           = (object) $array;
270
        $magicPropertyObject = new Twig_TemplateMagicPropertyObject();
271
        $propertyObject      = new Twig_TemplatePropertyObject();
272
        $propertyObject1     = new Twig_TemplatePropertyObjectAndIterator();
273
        $propertyObject2     = new Twig_TemplatePropertyObjectAndArrayAccess();
274
        $propertyObject3     = new Twig_TemplatePropertyObjectDefinedWithUndefinedValue();
275
        $methodObject        = new Twig_TemplateMethodObject();
276
        $magicMethodObject   = new Twig_TemplateMagicMethodObject();
277
278
        $anyType    = Twig_Template::ANY_CALL;
279
        $methodType = Twig_Template::METHOD_CALL;
280
        $arrayType  = Twig_Template::ARRAY_CALL;
281
282
        $basicTests = array(
283
            // array(defined, value, property to fetch)
284
            array(true,  'defined', 'defined'),
285
            array(false, null,      'undefined'),
286
            array(false, null,      'protected'),
287
            array(true,  0,         'zero'),
288
            array(true,  1,         1),
289
            array(true,  1,         1.0),
290
            array(true,  null,      'null'),
291
            array(true,  true,      'bar'),
292
            array(true,  '09',      '09'),
293
            array(true,  '+4',      '+4'),
294
        );
295
        $testObjects = array(
296
            // array(object, type of fetch)
297
            array($array,               $arrayType),
298
            array($objectArray,         $arrayType),
299
            array($stdObject,           $anyType),
300
            array($magicPropertyObject, $anyType),
301
            array($methodObject,        $methodType),
302
            array($methodObject,        $anyType),
303
            array($propertyObject,      $anyType),
304
            array($propertyObject1,     $anyType),
305
            array($propertyObject2,     $anyType),
306
        );
307
308
        $tests = array();
309
        foreach ($testObjects as $testObject) {
310
            foreach ($basicTests as $test) {
311
                // properties cannot be numbers
312
                if (($testObject[0] instanceof stdClass || $testObject[0] instanceof Twig_TemplatePropertyObject) && is_numeric($test[2])) {
313
                    continue;
314
                }
315
316
                if ('+4' === $test[2] && $methodObject === $testObject[0]) {
317
                    continue;
318
                }
319
320
                $tests[] = array($test[0], $test[1], $testObject[0], $test[2], array(), $testObject[1]);
321
            }
322
        }
323
324
        // additional properties tests
325
        $tests = array_merge($tests, array(
326
            array(true, null, $propertyObject3, 'foo', array(), $anyType),
327
        ));
328
329
        // additional method tests
330
        $tests = array_merge($tests, array(
331
            array(true, 'defined', $methodObject, 'defined',    array(), $methodType),
332
            array(true, 'defined', $methodObject, 'DEFINED',    array(), $methodType),
333
            array(true, 'defined', $methodObject, 'getDefined', array(), $methodType),
334
            array(true, 'defined', $methodObject, 'GETDEFINED', array(), $methodType),
335
            array(true, 'static',  $methodObject, 'static',     array(), $methodType),
336
            array(true, 'static',  $methodObject, 'getStatic',  array(), $methodType),
337
338
            array(true, '__call_undefined', $magicMethodObject, 'undefined', array(), $methodType),
339
            array(true, '__call_UNDEFINED', $magicMethodObject, 'UNDEFINED', array(), $methodType),
340
        ));
341
342
        // add the same tests for the any type
343
        foreach ($tests as $test) {
344
            if ($anyType !== $test[5]) {
345
                $test[5] = $anyType;
346
                $tests[] = $test;
347
            }
348
        }
349
350
        $methodAndPropObject = new Twig_TemplateMethodAndPropObject();
351
352
        // additional method tests
353
        $tests = array_merge($tests, array(
354
            array(true, 'a', $methodAndPropObject, 'a', array(), $anyType),
355
            array(true, 'a', $methodAndPropObject, 'a', array(), $methodType),
356
            array(false, null, $methodAndPropObject, 'a', array(), $arrayType),
357
358
            array(true, 'b_prop', $methodAndPropObject, 'b', array(), $anyType),
359
            array(true, 'b', $methodAndPropObject, 'B', array(), $anyType),
360
            array(true, 'b', $methodAndPropObject, 'b', array(), $methodType),
361
            array(true, 'b', $methodAndPropObject, 'B', array(), $methodType),
362
            array(false, null, $methodAndPropObject, 'b', array(), $arrayType),
363
364
            array(false, null, $methodAndPropObject, 'c', array(), $anyType),
365
            array(false, null, $methodAndPropObject, 'c', array(), $methodType),
366
            array(false, null, $methodAndPropObject, 'c', array(), $arrayType),
367
368
        ));
369
370
        // tests when input is not an array or object
371
        $tests = array_merge($tests, array(
372
            array(false, null, 42, 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a integer variable ("42")'),
373
            array(false, null, "string", 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a string variable ("string")'),
374
            array(false, null, array(), 'a', array(), $anyType, false, 'Key "a" does not exist as the array is empty'),
375
        ));
376
377
        // add twig_template_get_attributes tests
378
379
        if (function_exists('twig_template_get_attributes')) {
380
            foreach (array_slice($tests, 0) as $test) {
381
                $test = array_pad($test, 7, null);
382
                $test[6] = true;
383
                $tests[] = $test;
384
            }
385
        }
386
387
        return $tests;
388
    }
389
}
390
391
class Twig_TemplateTest extends Twig_Template
392
{
393
    protected $useExtGetAttribute = false;
394
395
    public function __construct(Twig_Environment $env, $useExtGetAttribute = false)
396
    {
397
        parent::__construct($env);
398
        $this->useExtGetAttribute = $useExtGetAttribute;
399
        self::$cache = array();
400
    }
401
402
    public function getZero()
403
    {
404
        return 0;
405
    }
406
407
    public function getEmpty()
408
    {
409
        return '';
410
    }
411
412
    public function getString()
413
    {
414
        return 'some_string';
415
    }
416
417
    public function getTrue()
418
    {
419
        return true;
420
    }
421
422
    public function getTemplateName()
423
    {
424
    }
425
426
    public function getDebugInfo()
427
    {
428
        return array();
429
    }
430
431
    protected function doGetParent(array $context)
432
    {
433
    }
434
435
    protected function doDisplay(array $context, array $blocks = array())
436
    {
437
    }
438
439
    public function getAttribute($object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
440
    {
441
        if ($this->useExtGetAttribute) {
442
            return twig_template_get_attributes($this, $object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
443
        } else {
444
            return parent::getAttribute($object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
445
        }
446
    }
447
}
448
449
class Twig_TemplateArrayAccessObject implements ArrayAccess
450
{
451
    protected $protected = 'protected';
452
453
    public $attributes = array(
454
        'defined' => 'defined',
455
        'zero'    => 0,
456
        'null'    => null,
457
        '1'       => 1,
458
        'bar'     => true,
459
        '09'      => '09',
460
        '+4'      => '+4',
461
    );
462
463
    public function offsetExists($name)
464
    {
465
        return array_key_exists($name, $this->attributes);
466
    }
467
468
    public function offsetGet($name)
469
    {
470
        return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
471
    }
472
473
    public function offsetSet($name, $value)
474
    {
475
    }
476
477
    public function offsetUnset($name)
478
    {
479
    }
480
}
481
482
class Twig_TemplateMagicPropertyObject
483
{
484
    public $defined = 'defined';
485
486
    public $attributes = array(
487
        'zero'    => 0,
488
        'null'    => null,
489
        '1'       => 1,
490
        'bar'     => true,
491
        '09'      => '09',
492
        '+4'      => '+4',
493
    );
494
495
    protected $protected = 'protected';
496
497
    public function __isset($name)
498
    {
499
        return array_key_exists($name, $this->attributes);
500
    }
501
502
    public function __get($name)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
503
    {
504
        return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : null;
505
    }
506
}
507
508
class Twig_TemplateMagicPropertyObjectWithException
509
{
510
    public function __isset($key)
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
511
    {
512
        throw new Exception("Hey! Don't try to isset me!");
513
    }
514
}
515
516
class Twig_TemplatePropertyObject
517
{
518
    public $defined = 'defined';
519
    public $zero    = 0;
520
    public $null    = null;
521
    public $bar     = true;
522
523
    protected $protected = 'protected';
524
}
525
526
class Twig_TemplatePropertyObjectAndIterator extends Twig_TemplatePropertyObject implements IteratorAggregate
527
{
528
    public function getIterator()
529
    {
530
        return new ArrayIterator(array('foo', 'bar'));
531
    }
532
}
533
534
class Twig_TemplatePropertyObjectAndArrayAccess extends Twig_TemplatePropertyObject implements ArrayAccess
535
{
536
    private $data = array();
537
538
    public function offsetExists($offset)
539
    {
540
        return array_key_exists($offset, $this->data);
541
    }
542
543
    public function offsetGet($offset)
544
    {
545
        return $this->offsetExists($offset) ? $this->data[$offset] : 'n/a';
546
    }
547
548
    public function offsetSet($offset, $value)
549
    {
550
    }
551
552
    public function offsetUnset($offset)
553
    {
554
    }
555
}
556
557
class Twig_TemplatePropertyObjectDefinedWithUndefinedValue
558
{
559
    public $foo;
560
561
    public function __construct()
562
    {
563
        $this->foo = @$notExist;
0 ignored issues
show
Bug introduced by
The variable $notExist does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
564
    }
565
}
566
567
class Twig_TemplateMethodObject
568
{
569
    public function getDefined()
570
    {
571
        return 'defined';
572
    }
573
574
    public function get1()
575
    {
576
        return 1;
577
    }
578
579
    public function get09()
580
    {
581
        return '09';
582
    }
583
584
    public function getZero()
585
    {
586
        return 0;
587
    }
588
589
    public function getNull()
590
    {
591
    }
592
593
    public function isBar()
594
    {
595
        return true;
596
    }
597
598
    protected function getProtected()
599
    {
600
        return 'protected';
601
    }
602
603
    public static function getStatic()
604
    {
605
        return 'static';
606
    }
607
}
608
609
class Twig_TemplateMethodAndPropObject
610
{
611
    private $a = 'a_prop';
0 ignored issues
show
Unused Code introduced by
The property $a is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
612
    public function getA()
613
    {
614
        return 'a';
615
    }
616
617
    public $b = 'b_prop';
618
    public function getB()
619
    {
620
        return 'b';
621
    }
622
623
    private $c = 'c_prop';
0 ignored issues
show
Unused Code introduced by
The property $c is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
624
    private function getC()
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
625
    {
626
        return 'c';
627
    }
628
}
629
630
class Twig_TemplateMagicMethodObject
631
{
632
    public function __call($method, $arguments)
633
    {
634
        return '__call_'.$method;
635
    }
636
}
637
638
class Twig_TemplateMagicMethodExceptionObject
639
{
640
    public function __call($method, $arguments)
641
    {
642
        throw new BadMethodCallException(sprintf('Unkown method %s', $method));
643
    }
644
}
645
646
class CExtDisablingNodeVisitor implements Twig_NodeVisitorInterface
647
{
648
    public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
649
    {
650
        if ($node instanceof Twig_Node_Expression_GetAttr) {
651
            $node->setAttribute('disable_c_ext', true);
652
        }
653
654
        return $node;
655
    }
656
657
    public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
658
    {
659
        return $node;
660
    }
661
662
    public function getPriority()
663
    {
664
        return 0;
665
    }
666
}
667