From 1621435b89a41fe3110816e7167ae376b809c177 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 18 Dec 2010 16:20:05 +0100 Subject: [PATCH] added support for functions --- CHANGELOG | 1 + lib/Twig/ExpressionParser.php | 2 + lib/Twig/Function.php | 38 ++++++++++++++++++++ lib/Twig/Node/Expression/Function.php | 35 ++++++++++++++++++ lib/Twig/Template.php | 14 +++++++ test/Twig/Tests/Fixtures/expressions/function.test | 13 +++++++ test/Twig/Tests/integrationTest.php | 10 +++++ 7 files changed, 113 insertions(+), 0 deletions(-) create mode 100644 lib/Twig/Function.php create mode 100644 lib/Twig/Node/Expression/Function.php create mode 100644 test/Twig/Tests/Fixtures/expressions/function.test diff --git a/CHANGELOG b/CHANGELOG index a5e1528..baf47ee 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ Backward incompatibilities: Changes: + * added support for functions (a function is just syntactic sugar for a getAttribute() call) * made macros callable when sandbox mode is enabled * added an exception when a macro uses a reserved name * the "default" filter now uses the "empty" test instead of just checking for null diff --git a/lib/Twig/ExpressionParser.php b/lib/Twig/ExpressionParser.php index 323c420..e0e323e 100644 --- a/lib/Twig/ExpressionParser.php +++ b/lib/Twig/ExpressionParser.php @@ -216,6 +216,8 @@ class Twig_ExpressionParser $node = $this->parseSubscriptExpression($node); } elseif ('|' == $token->getValue()) { $node = $this->parseFilterExpression($node); + } elseif ($node instanceof Twig_Node_Expression_Name && '(' == $token->getValue()) { + return new Twig_Node_Expression_Function($node, $this->parseArguments(), $node->getLine()); } else { break; } diff --git a/lib/Twig/Function.php b/lib/Twig/Function.php new file mode 100644 index 0000000..dd29601 --- /dev/null +++ b/lib/Twig/Function.php @@ -0,0 +1,38 @@ + + */ +class Twig_Function extends Exception +{ + protected $object; + protected $method; + + public function __construct($object, $method) + { + $this->object = $object; + $this->method = $method; + } + + public function getObject() + { + return $this->object; + } + + public function getMethod() + { + return $this->method; + } +} diff --git a/lib/Twig/Node/Expression/Function.php b/lib/Twig/Node/Expression/Function.php new file mode 100644 index 0000000..0cf5e95 --- /dev/null +++ b/lib/Twig/Node/Expression/Function.php @@ -0,0 +1,35 @@ + $name, 'arguments' => $arguments), array(), $lineno); + } + + public function compile($compiler) + { + $compiler + ->raw('$this->callFunction($context, ') + ->subcompile($this->getNode('name')) + ->raw(', array(') + ; + + foreach ($this->getNode('arguments') as $node) { + $compiler + ->subcompile($node) + ->raw(', ') + ; + } + + $compiler->raw('))'); + } +} diff --git a/lib/Twig/Template.php b/lib/Twig/Template.php index 4f9eab6..6073e35 100644 --- a/lib/Twig/Template.php +++ b/lib/Twig/Template.php @@ -101,6 +101,20 @@ abstract class Twig_Template implements Twig_TemplateInterface return $context[$item]; } + protected function callFunction($context, $function, array $arguments = array()) + { + if (!$function instanceof Twig_Function) { + throw new Twig_Error_Runtime('Called a non-function', -1, $this->getTemplateName()); + } + + $object = $function->getObject(); + if (!is_object($object)) { + $object = $this->getContext($context, $object); + } + + return $this->getAttribute($object, $function->getMethod(), $arguments, Twig_Node_Expression_GetAttr::TYPE_METHOD, false); + } + protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_Node_Expression_GetAttr::TYPE_ANY, $noStrictCheck = false) { // array diff --git a/test/Twig/Tests/Fixtures/expressions/function.test b/test/Twig/Tests/Fixtures/expressions/function.test new file mode 100644 index 0000000..90409ad --- /dev/null +++ b/test/Twig/Tests/Fixtures/expressions/function.test @@ -0,0 +1,13 @@ +--TEST-- +Twig supports calling variables +--TEMPLATE-- +{{ lower('FOO') }} +{{ lower1('FOO') }} +--DATA-- +return array( + 'foo' => new Foo(), + 'lower' => new Twig_Function('foo', 'strToLower'), + 'lower1' => new Twig_Function(new Foo(), 'strToLower')) +--EXPECT-- +foo +foo diff --git a/test/Twig/Tests/integrationTest.php b/test/Twig/Tests/integrationTest.php index 7383735..183a56c 100644 --- a/test/Twig/Tests/integrationTest.php +++ b/test/Twig/Tests/integrationTest.php @@ -79,6 +79,11 @@ class Twig_Tests_IntegrationTest extends PHPUnit_Framework_TestCase } } +function test_foo($value = 'foo') +{ + return $value; +} + class Foo { const BAR_NAME = 'bar'; @@ -112,6 +117,11 @@ class Foo { return 'not'; } + + public function strToLower($value) + { + return strtolower($value); + } } class TestExtension extends Twig_Extension -- 1.7.2.5