Added support for unconsumed macro arguments

This commit is contained in:
Martin Hasoň
2015-03-20 00:17:33 +01:00
parent dfddd2e0ef
commit 7f00cb9d10
6 changed files with 97 additions and 21 deletions
+4
View File
@@ -20,6 +20,10 @@ Macros differs from native PHP functions in a few ways:
* Arguments of a macro are always optional. * Arguments of a macro are always optional.
* If more positional arguments are passed to the macro than accepted by the macro,
they end up in the special ``varargs`` variable as a list of values. This variable
is always available in the macro body.
But as with PHP functions, macros don't have access to the current template But as with PHP functions, macros don't have access to the current template
variables. variables.
+5 -1
View File
@@ -93,7 +93,7 @@ access the variable attribute:
don't put the braces around them. don't put the braces around them.
If a variable or attribute does not exist, you will receive a ``null`` value If a variable or attribute does not exist, you will receive a ``null`` value
when the ``strict_variables`` option is set to ``false``; alternatively, if ``strict_variables`` when the ``strict_variables`` option is set to ``false``; alternatively, if ``strict_variables``
is set, Twig will throw an error (see :ref:`environment options<environment_options>`). is set, Twig will throw an error (see :ref:`environment options<environment_options>`).
.. sidebar:: Implementation .. sidebar:: Implementation
@@ -541,6 +541,10 @@ macro call:
<input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" /> <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
{% endmacro %} {% endmacro %}
Inside macros, you have access to special variable ``varargs``. If more positional arguments
are passed to the macro than accepted by the macro, they end up in the special ``varargs`` variable
as a list of values.
.. _twig-expressions: .. _twig-expressions:
Expressions Expressions
+49 -19
View File
@@ -16,8 +16,19 @@
*/ */
class Twig_Node_Macro extends Twig_Node class Twig_Node_Macro extends Twig_Node
{ {
const VARARGS_NAME = 'varargs';
public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null) public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
{ {
foreach ($arguments as $argumentName => $argument) {
if (self::VARARGS_NAME === $argumentName) {
throw new Twig_Error_Syntax(sprintf(
'The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments',
self::VARARGS_NAME, $name, self::VARARGS_NAME
), $argument->getLine());
}
}
parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag); parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
} }
@@ -30,7 +41,7 @@ class Twig_Node_Macro extends Twig_Node
{ {
$compiler $compiler
->addDebugInfo($this) ->addDebugInfo($this)
->write(sprintf("public function get%s(", $this->getAttribute('name'))) ->write(sprintf('public function get%s(', $this->getAttribute('name')))
; ;
$count = count($this->getNode('arguments')); $count = count($this->getNode('arguments'));
@@ -46,36 +57,55 @@ class Twig_Node_Macro extends Twig_Node
} }
} }
if (PHP_VERSION_ID >= 50600) {
if ($count) {
$compiler->raw(', ');
}
$compiler->raw('...$__varargs__');
}
$compiler $compiler
->raw(")\n") ->raw(")\n")
->write("{\n") ->write("{\n")
->indent() ->indent()
; ;
if (!count($this->getNode('arguments'))) { $compiler
$compiler->write("\$context = \$this->env->getGlobals();\n\n"); ->write("\$context = \$this->env->mergeGlobals(array(\n")
} else { ->indent()
$compiler ;
->write("\$context = \$this->env->mergeGlobals(array(\n")
->indent()
;
foreach ($this->getNode('arguments') as $name => $default) {
$compiler
->write('')
->string($name)
->raw(' => $__'.$name.'__')
->raw(",\n")
;
}
foreach ($this->getNode('arguments') as $name => $default) {
$compiler $compiler
->outdent() ->addIndentation()
->write("));\n\n") ->string($name)
->raw(' => $__'.$name.'__')
->raw(",\n")
; ;
} }
$compiler $compiler
->addIndentation()
->string(self::VARARGS_NAME)
->raw(' => ')
;
if (PHP_VERSION_ID >= 50600) {
$compiler->raw("\$__varargs__,\n");
} else {
$compiler
->raw('func_num_args() > ')
->repr($count)
->raw(' ? array_slice(func_get_args(), ')
->repr($count)
->raw(") : array(),\n")
;
}
$compiler
->outdent()
->write("));\n\n")
->write("\$blocks = array();\n\n") ->write("\$blocks = array();\n\n")
->write("ob_start();\n") ->write("ob_start();\n")
->write("try {\n") ->write("try {\n")
@@ -0,0 +1,21 @@
--TEST--
macro with arbitrary arguments
--TEMPLATE--
{% from _self import test1, test2 %}
{% macro test1(var) %}
{{- var }}: {{ varargs|join(", ") }}
{% endmacro %}
{% macro test2() %}
{{- varargs|join(", ") }}
{% endmacro %}
{{ test1("foo", "bar", "foobar") }}
{{ test2("foo", "bar", "foobar") }}
--DATA--
return array();
--EXPECT--
foo: bar, foobar
foo, bar, foobar
@@ -0,0 +1,8 @@
--TEST--
macro with varargs argument
--TEMPLATE--
{% macro test(varargs) %}
{% endmacro %}
--EXCEPTION--
Twig_Error_Syntax: The argument "varargs" in macro "test" cannot be defined because the variable "varargs" is reserved for arbitrary arguments in "index.twig" at line 2
+10 -1
View File
@@ -31,14 +31,23 @@ class Twig_Tests_Node_MacroTest extends Twig_Test_NodeTestCase
), array(), 1); ), array(), 1);
$node = new Twig_Node_Macro('foo', $body, $arguments, 1); $node = new Twig_Node_Macro('foo', $body, $arguments, 1);
if (PHP_VERSION_ID >= 50600) {
$declaration = ', ...$__varargs__';
$varargs = '$__varargs__';
} else {
$declaration = '';
$varargs = 'func_num_args() > 2 ? array_slice(func_get_args(), 2) : array()';
}
return array( return array(
array($node, <<<EOF array($node, <<<EOF
// line 1 // line 1
public function getfoo(\$__foo__ = null, \$__bar__ = "Foo") public function getfoo(\$__foo__ = null, \$__bar__ = "Foo"$declaration)
{ {
\$context = \$this->env->mergeGlobals(array( \$context = \$this->env->mergeGlobals(array(
"foo" => \$__foo__, "foo" => \$__foo__,
"bar" => \$__bar__, "bar" => \$__bar__,
"varargs" => $varargs,
)); ));
\$blocks = array(); \$blocks = array();