From c03a7a323a891a891d108567ac08cb716a8daeb5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 1 Aug 2014 09:16:32 +0200 Subject: [PATCH] fixed the attribute() function when passing a variable for the arguments --- CHANGELOG | 2 +- lib/Twig/ExpressionParser.php | 2 +- lib/Twig/Node/Expression/GetAttr.php | 34 +++++++++++++------- test/Twig/Tests/Fixtures/functions/attribute.test | 4 ++- test/Twig/Tests/Node/Expression/GetAttrTest.php | 2 +- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 76c4e1f..2bf433a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ * 1.16.1 (2014-XX-XX) - * n/a + * fixed the attribute() function when passing a variable for the arguments * 1.16.0 (2014-07-05) diff --git a/lib/Twig/ExpressionParser.php b/lib/Twig/ExpressionParser.php index 01594f7..f685bad 100644 --- a/lib/Twig/ExpressionParser.php +++ b/lib/Twig/ExpressionParser.php @@ -318,7 +318,7 @@ class Twig_ExpressionParser throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename()); } - return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line); + return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line); default: if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { $arguments = new Twig_Node_Expression_Array(array(), $line); diff --git a/lib/Twig/Node/Expression/GetAttr.php b/lib/Twig/Node/Expression/GetAttr.php index 55d9fcc..6ce6111 100644 --- a/lib/Twig/Node/Expression/GetAttr.php +++ b/lib/Twig/Node/Expression/GetAttr.php @@ -11,7 +11,7 @@ */ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression { - public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno) + public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression $arguments = null, $type, $lineno) { parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno); } @@ -32,20 +32,30 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression $compiler->raw(', ')->subcompile($this->getNode('attribute')); - if (count($this->getNode('arguments')) || Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { - $compiler->raw(', ')->subcompile($this->getNode('arguments')); - - if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { - $compiler->raw(', ')->repr($this->getAttribute('type')); + // only generate optional arguments when needed (to make generated code more readable) + $needFourth = $this->getAttribute('ignore_strict_check'); + $needThird = $needFourth || $this->getAttribute('is_defined_test'); + $needSecond = $needThird || Twig_Template::ANY_CALL !== $this->getAttribute('type'); + $needFirst = $needSecond || null !== $this->getNode('arguments'); + + if ($needFirst) { + if (null !== $this->getNode('arguments')) { + $compiler->raw(', ')->subcompile($this->getNode('arguments')); + } else { + $compiler->raw(', array()'); } + } - if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { - $compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false')); - } + if ($needSecond) { + $compiler->raw(', ')->repr($this->getAttribute('type')); + } - if ($this->getAttribute('ignore_strict_check')) { - $compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false')); - } + if ($needThird) { + $compiler->raw(', ')->repr($this->getAttribute('is_defined_test')); + } + + if ($needFourth) { + $compiler->raw(', ')->repr($this->getAttribute('ignore_strict_check')); } $compiler->raw(')'); diff --git a/test/Twig/Tests/Fixtures/functions/attribute.test b/test/Twig/Tests/Fixtures/functions/attribute.test index 472b74d..71b2038 100644 --- a/test/Twig/Tests/Fixtures/functions/attribute.test +++ b/test/Twig/Tests/Fixtures/functions/attribute.test @@ -4,13 +4,15 @@ {{ attribute(obj, method) }} {{ attribute(array, item) }} {{ attribute(obj, "bar", ["a", "b"]) }} +{{ attribute(obj, "bar", arguments) }} {{ attribute(obj, method) is defined ? 'ok' : 'ko' }} {{ attribute(obj, nonmethod) is defined ? 'ok' : 'ko' }} --DATA-- -return array('obj' => new TwigTestFoo(), 'method' => 'foo', 'array' => array('foo' => 'bar'), 'item' => 'foo', 'nonmethod' => 'xxx') +return array('obj' => new TwigTestFoo(), 'method' => 'foo', 'array' => array('foo' => 'bar'), 'item' => 'foo', 'nonmethod' => 'xxx', 'arguments' => array('a', 'b')) --EXPECT-- foo bar bar_a-b +bar_a-b ok ko diff --git a/test/Twig/Tests/Node/Expression/GetAttrTest.php b/test/Twig/Tests/Node/Expression/GetAttrTest.php index 62fb0d3..76cf5c6 100644 --- a/test/Twig/Tests/Node/Expression/GetAttrTest.php +++ b/test/Twig/Tests/Node/Expression/GetAttrTest.php @@ -46,7 +46,7 @@ class Twig_Tests_Node_Expression_GetAttrTest extends Twig_Test_NodeTestCase $attr = new Twig_Node_Expression_Constant('bar', 1); $args = new Twig_Node_Expression_Array(array(), 1); $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ANY_CALL, 1); - $tests[] = array($node, sprintf('%s%s, "bar")', $this->getAttributeGetter(), $this->getVariableGetter('foo'))); + $tests[] = array($node, sprintf('%s%s, "bar", array())', $this->getAttributeGetter(), $this->getVariableGetter('foo'))); $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ARRAY_CALL, 1); $tests[] = array($node, sprintf('%s%s, "bar", array(), "array")', $this->getAttributeGetter(), $this->getVariableGetter('foo'))); -- 1.7.2.5