mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-14 19:36:43 +00:00
Added variadic filters, tests, and functions
This commit is contained in:
@@ -224,6 +224,23 @@ through your filter::
|
||||
|
||||
$filter = new Twig_SimpleFilter('somefilter', 'somefilter', array('pre_escape' => 'html', 'is_safe' => array('html')));
|
||||
|
||||
Variadic Filters
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 1.19
|
||||
Support for variadic filters was added in Twig 1.19.
|
||||
|
||||
If you want to pass a variable number of positional or named arguments to the filter,
|
||||
set the ``is_variadic`` option to ``true``; Twig will pass the array of arbitrary arguments
|
||||
as the last argument to the filter call that is defined as an array with an empty default value::
|
||||
|
||||
$filter = new Twig_SimpleFilter('thumbnail', function ($file, array $options = array()) {
|
||||
...
|
||||
}, array('is_variadic' => true));
|
||||
|
||||
The named arguments passed to the variadic filter cannot be checked if they are valid or not
|
||||
as if they are not valid, they will end up in the option array.
|
||||
|
||||
Dynamic Filters
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -331,6 +348,10 @@ The ``node`` sub-node will contain an expression of ``my_value``. Node-based
|
||||
tests also have access to the ``arguments`` node. This node will contain the
|
||||
various other arguments that have been provided to your test.
|
||||
|
||||
If you want to pass a variable number of positional or named arguments to the test,
|
||||
set the ``is_variadic`` option to ``true``. Tests also support dynamic name feature
|
||||
as filters and functions.
|
||||
|
||||
Tags
|
||||
----
|
||||
|
||||
|
||||
+16
-1
@@ -93,7 +93,7 @@ access the variable attribute:
|
||||
don't put the braces around them.
|
||||
|
||||
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>`).
|
||||
|
||||
.. sidebar:: Implementation
|
||||
@@ -238,6 +238,21 @@ case positional arguments must always come before named arguments:
|
||||
Each function and filter documentation page has a section where the names
|
||||
of all arguments are listed when supported.
|
||||
|
||||
Variadic Arguments
|
||||
------------------
|
||||
|
||||
.. versionadded:: 1.19
|
||||
Support for variadic arguments was added in Twig 1.19.
|
||||
|
||||
The variadic filter, function or test can accept any arbitrary positional or named arguments:
|
||||
|
||||
.. code-block:: jinja
|
||||
|
||||
{{ "path/to/image.png"|thumbnail(size=[32, 32], mode=outbound, quality=90, format="jpg") }}
|
||||
|
||||
The named arguments passed to the variadic filter, function or test cannot be checked if they are valid or not
|
||||
as if they are not valid, they will end up in the option array.
|
||||
|
||||
Control Structure
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -106,12 +106,19 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
|
||||
$parameters[$name] = $node;
|
||||
}
|
||||
|
||||
if (!$named) {
|
||||
$isVariadic = $this->hasAttribute('is_variadic') && $this->getAttribute('is_variadic');
|
||||
if (!$named && !$isVariadic) {
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
if (!$callable) {
|
||||
throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $callType, $callName));
|
||||
if ($named) {
|
||||
$message = sprintf('Named arguments are not supported for %s "%s".', $callType, $callName);
|
||||
} else {
|
||||
$message = sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName);
|
||||
}
|
||||
|
||||
throw new LogicException($message);
|
||||
}
|
||||
|
||||
// manage named arguments
|
||||
@@ -141,6 +148,22 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
|
||||
array_shift($definition);
|
||||
}
|
||||
}
|
||||
if ($isVariadic) {
|
||||
$argument = end($definition);
|
||||
if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && array() === $argument->getDefaultValue()) {
|
||||
array_pop($definition);
|
||||
} else {
|
||||
$callableName = $r->name;
|
||||
if ($r->getDeclaringClass()) {
|
||||
$callableName = $r->getDeclaringClass()->name.'::'.$callableName;
|
||||
}
|
||||
|
||||
throw new LogicException(sprintf(
|
||||
'The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = array()".',
|
||||
$callableName, $callType, $callName
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$arguments = array();
|
||||
$names = array();
|
||||
@@ -185,6 +208,23 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
|
||||
}
|
||||
}
|
||||
|
||||
if ($isVariadic) {
|
||||
$arbitraryArguments = new Twig_Node_Expression_Array(array(), -1);
|
||||
foreach ($parameters as $key => $value) {
|
||||
if (is_int($key)) {
|
||||
$arbitraryArguments->addElement($value);
|
||||
} else {
|
||||
$arbitraryArguments->addElement($value, new Twig_Node_Expression_Constant($key, -1));
|
||||
}
|
||||
unset($parameters[$key]);
|
||||
}
|
||||
|
||||
if ($arbitraryArguments->count()) {
|
||||
$arguments = array_merge($arguments, $optionalArguments);
|
||||
$arguments[] = $arbitraryArguments;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($parameters)) {
|
||||
$unknownParameter = null;
|
||||
foreach ($parameters as $parameter) {
|
||||
|
||||
@@ -30,6 +30,9 @@ class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
|
||||
if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
|
||||
$this->setAttribute('callable', $filter->getCallable());
|
||||
}
|
||||
if ($filter instanceof Twig_SimpleFilter) {
|
||||
$this->setAttribute('is_variadic', $filter->isVariadic());
|
||||
}
|
||||
|
||||
$this->compileCallable($compiler);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
|
||||
if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
|
||||
$this->setAttribute('callable', $function->getCallable());
|
||||
}
|
||||
if ($function instanceof Twig_SimpleFunction) {
|
||||
$this->setAttribute('is_variadic', $function->isVariadic());
|
||||
}
|
||||
|
||||
$this->compileCallable($compiler);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ class Twig_Node_Expression_Test extends Twig_Node_Expression_Call
|
||||
if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) {
|
||||
$this->setAttribute('callable', $test->getCallable());
|
||||
}
|
||||
if ($test instanceof Twig_SimpleTest) {
|
||||
$this->setAttribute('is_variadic', $test->isVariadic());
|
||||
}
|
||||
|
||||
$this->compileCallable($compiler);
|
||||
}
|
||||
|
||||
@@ -27,12 +27,13 @@ class Twig_SimpleFilter
|
||||
$this->callable = $callable;
|
||||
$this->options = array_merge(array(
|
||||
'needs_environment' => false,
|
||||
'needs_context' => false,
|
||||
'is_safe' => null,
|
||||
'is_safe_callback' => null,
|
||||
'pre_escape' => null,
|
||||
'preserves_safety' => null,
|
||||
'node_class' => 'Twig_Node_Expression_Filter',
|
||||
'needs_context' => false,
|
||||
'is_variadic' => false,
|
||||
'is_safe' => null,
|
||||
'is_safe_callback' => null,
|
||||
'pre_escape' => null,
|
||||
'preserves_safety' => null,
|
||||
'node_class' => 'Twig_Node_Expression_Filter',
|
||||
), $options);
|
||||
}
|
||||
|
||||
@@ -91,4 +92,9 @@ class Twig_SimpleFilter
|
||||
{
|
||||
return $this->options['pre_escape'];
|
||||
}
|
||||
|
||||
public function isVariadic()
|
||||
{
|
||||
return $this->options['is_variadic'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,11 @@ class Twig_SimpleFunction
|
||||
$this->callable = $callable;
|
||||
$this->options = array_merge(array(
|
||||
'needs_environment' => false,
|
||||
'needs_context' => false,
|
||||
'is_safe' => null,
|
||||
'is_safe_callback' => null,
|
||||
'node_class' => 'Twig_Node_Expression_Function',
|
||||
'needs_context' => false,
|
||||
'is_variadic' => false,
|
||||
'is_safe' => null,
|
||||
'is_safe_callback' => null,
|
||||
'node_class' => 'Twig_Node_Expression_Function',
|
||||
), $options);
|
||||
}
|
||||
|
||||
@@ -81,4 +82,9 @@ class Twig_SimpleFunction
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function isVariadic()
|
||||
{
|
||||
return $this->options['is_variadic'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ class Twig_SimpleTest
|
||||
$this->name = $name;
|
||||
$this->callable = $callable;
|
||||
$this->options = array_merge(array(
|
||||
'is_variadic' => false,
|
||||
'node_class' => 'Twig_Node_Expression_Test',
|
||||
), $options);
|
||||
}
|
||||
@@ -43,4 +44,9 @@ class Twig_SimpleTest
|
||||
{
|
||||
return $this->options['node_class'];
|
||||
}
|
||||
|
||||
public function isVariadic()
|
||||
{
|
||||
return $this->options['is_variadic'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class Twig_Tests_Node_Expression_CallTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
public function testResolveArgumentsOnlyNecessaryArgumentsForCustomFunction()
|
||||
{
|
||||
$node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'custom_function'));
|
||||
$node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'custom_function'));
|
||||
|
||||
$this->assertEquals(array('arg1'), $node->getArguments(array($this, 'customFunction'), array('arg1' => 'arg1')));
|
||||
}
|
||||
@@ -84,6 +84,16 @@ class Twig_Tests_Node_Expression_CallTest extends PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(array('arg1'), $node->getArguments(__CLASS__.'::customStaticFunction', array('arg1' => 'arg1')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException LogicException
|
||||
* @expectedExceptionMessage The last parameter of "Twig_Tests_Node_Expression_CallTest::customFunctionWithArbitraryArguments" for function "foo" must be an array with default value, eg. "array $arg = array()".
|
||||
*/
|
||||
public function testResolveArgumentsWithMissingParameterForArbitraryArguments()
|
||||
{
|
||||
$node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'foo', 'is_variadic' => true));
|
||||
$node->getArguments(array($this, 'customFunctionWithArbitraryArguments'), array());
|
||||
}
|
||||
|
||||
public static function customStaticFunction($arg1, $arg2 = 'default', $arg3 = array())
|
||||
{
|
||||
}
|
||||
@@ -91,6 +101,10 @@ class Twig_Tests_Node_Expression_CallTest extends PHPUnit_Framework_TestCase
|
||||
public function customFunction($arg1, $arg2 = 'default', $arg3 = array())
|
||||
{
|
||||
}
|
||||
|
||||
public function customFunctionWithArbitraryArguments()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Twig_Tests_Node_Expression_Call extends Twig_Node_Expression_Call
|
||||
|
||||
@@ -25,6 +25,10 @@ class Twig_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase
|
||||
|
||||
public function getTests()
|
||||
{
|
||||
$environment = new Twig_Environment();
|
||||
$environment->addFilter(new Twig_SimpleFilter('bar', 'bar', array('needs_environment' => true)));
|
||||
$environment->addFilter(new Twig_SimpleFilter('barbar', 'twig_tests_filter_barbar', array('needs_context' => true, 'is_variadic' => true)));
|
||||
|
||||
$tests = array();
|
||||
|
||||
$expr = new Twig_Node_Expression_Constant('foo', 1);
|
||||
@@ -41,7 +45,7 @@ class Twig_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase
|
||||
$date = new Twig_Node_Expression_Constant(0, 1);
|
||||
$node = $this->createFilter($date, 'date', array(
|
||||
'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
|
||||
'format' => new Twig_Node_Expression_Constant('d/m/Y H:i:s P', 1),
|
||||
'format' => new Twig_Node_Expression_Constant('d/m/Y H:i:s P', 1),
|
||||
));
|
||||
$tests[] = array($node, 'twig_date_format_filter($this->env, 0, "d/m/Y H:i:s P", "America/Chicago")');
|
||||
|
||||
@@ -69,6 +73,31 @@ class Twig_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase
|
||||
$tests[] = array($node, 'call_user_func_array($this->env->getFilter(\'anonymous\')->getCallable(), array("foo"))');
|
||||
}
|
||||
|
||||
// needs environment
|
||||
$node = $this->createFilter($string, 'bar');
|
||||
$tests[] = array($node, 'bar($this->env, "abc")', $environment);
|
||||
|
||||
$node = $this->createFilter($string, 'bar', array(new Twig_Node_Expression_Constant('bar', 1)));
|
||||
$tests[] = array($node, 'bar($this->env, "abc", "bar")', $environment);
|
||||
|
||||
// arbitrary named arguments
|
||||
$node = $this->createFilter($string, 'barbar');
|
||||
$tests[] = array($node, 'twig_tests_filter_barbar($context, "abc")', $environment);
|
||||
|
||||
$node = $this->createFilter($string, 'barbar', array('foo' => new Twig_Node_Expression_Constant('bar', 1)));
|
||||
$tests[] = array($node, 'twig_tests_filter_barbar($context, "abc", null, null, array("foo" => "bar"))', $environment);
|
||||
|
||||
$node = $this->createFilter($string, 'barbar', array('arg2' => new Twig_Node_Expression_Constant('bar', 1)));
|
||||
$tests[] = array($node, 'twig_tests_filter_barbar($context, "abc", null, "bar")', $environment);
|
||||
|
||||
$node = $this->createFilter($string, 'barbar', array(
|
||||
new Twig_Node_Expression_Constant('1', 1),
|
||||
new Twig_Node_Expression_Constant('2', 1),
|
||||
new Twig_Node_Expression_Constant('3', 1),
|
||||
'foo' => new Twig_Node_Expression_Constant('bar', 1),
|
||||
));
|
||||
$tests[] = array($node, 'twig_tests_filter_barbar($context, "abc", "1", "2", array(0 => "3", "foo" => "bar"))', $environment);
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
@@ -119,3 +148,7 @@ class Twig_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase
|
||||
return parent::getEnvironment();
|
||||
}
|
||||
}
|
||||
|
||||
function twig_tests_filter_barbar($context, $string, $arg1 = null, $arg2 = null, array $args = array())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ class Twig_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase
|
||||
$environment->addFunction(new Twig_SimpleFunction('bar', 'bar', array('needs_environment' => true)));
|
||||
$environment->addFunction(new Twig_SimpleFunction('foofoo', 'foofoo', array('needs_context' => true)));
|
||||
$environment->addFunction(new Twig_SimpleFunction('foobar', 'foobar', array('needs_environment' => true, 'needs_context' => true)));
|
||||
$environment->addFunction(new Twig_SimpleFunction('barbar', 'twig_tests_function_barbar', array('is_variadic' => true)));
|
||||
|
||||
$tests = array();
|
||||
|
||||
@@ -58,10 +59,28 @@ class Twig_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase
|
||||
// named arguments
|
||||
$node = $this->createFunction('date', array(
|
||||
'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
|
||||
'date' => new Twig_Node_Expression_Constant(0, 1),
|
||||
'date' => new Twig_Node_Expression_Constant(0, 1),
|
||||
));
|
||||
$tests[] = array($node, 'twig_date_converter($this->env, 0, "America/Chicago")');
|
||||
|
||||
// arbitrary named arguments
|
||||
$node = $this->createFunction('barbar');
|
||||
$tests[] = array($node, 'twig_tests_function_barbar()', $environment);
|
||||
|
||||
$node = $this->createFunction('barbar', array('foo' => new Twig_Node_Expression_Constant('bar', 1)));
|
||||
$tests[] = array($node, 'twig_tests_function_barbar(null, null, array("foo" => "bar"))', $environment);
|
||||
|
||||
$node = $this->createFunction('barbar', array('arg2' => new Twig_Node_Expression_Constant('bar', 1)));
|
||||
$tests[] = array($node, 'twig_tests_function_barbar(null, "bar")', $environment);
|
||||
|
||||
$node = $this->createFunction('barbar', array(
|
||||
new Twig_Node_Expression_Constant('1', 1),
|
||||
new Twig_Node_Expression_Constant('2', 1),
|
||||
new Twig_Node_Expression_Constant('3', 1),
|
||||
'foo' => new Twig_Node_Expression_Constant('bar', 1),
|
||||
));
|
||||
$tests[] = array($node, 'twig_tests_function_barbar("1", "2", array(0 => "3", "foo" => "bar"))', $environment);
|
||||
|
||||
// function as an anonymous function
|
||||
if (PHP_VERSION_ID >= 50300) {
|
||||
$node = $this->createFunction('anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
|
||||
@@ -85,3 +104,7 @@ class Twig_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase
|
||||
return parent::getEnvironment();
|
||||
}
|
||||
}
|
||||
|
||||
function twig_tests_function_barbar($arg1 = null, $arg2 = null, array $args = array())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ class Twig_Tests_Node_Expression_TestTest extends Twig_Test_NodeTestCase
|
||||
|
||||
public function getTests()
|
||||
{
|
||||
$environment = new Twig_Environment();
|
||||
$environment->addTest(new Twig_SimpleTest('barbar', 'twig_tests_test_barbar', array('is_variadic' => true, 'need_context' => true)));
|
||||
|
||||
$tests = array();
|
||||
|
||||
$expr = new Twig_Node_Expression_Constant('foo', 1);
|
||||
@@ -37,6 +40,25 @@ class Twig_Tests_Node_Expression_TestTest extends Twig_Test_NodeTestCase
|
||||
$tests[] = array($node, 'call_user_func_array($this->env->getTest(\'anonymous\')->getCallable(), array("foo", "foo"))');
|
||||
}
|
||||
|
||||
// arbitrary named arguments
|
||||
$string = new Twig_Node_Expression_Constant('abc', 1);
|
||||
$node = $this->createTest($string, 'barbar');
|
||||
$tests[] = array($node, 'twig_tests_test_barbar("abc")', $environment);
|
||||
|
||||
$node = $this->createTest($string, 'barbar', array('foo' => new Twig_Node_Expression_Constant('bar', 1)));
|
||||
$tests[] = array($node, 'twig_tests_test_barbar("abc", null, null, array("foo" => "bar"))', $environment);
|
||||
|
||||
$node = $this->createTest($string, 'barbar', array('arg2' => new Twig_Node_Expression_Constant('bar', 1)));
|
||||
$tests[] = array($node, 'twig_tests_test_barbar("abc", null, "bar")', $environment);
|
||||
|
||||
$node = $this->createTest($string, 'barbar', array(
|
||||
new Twig_Node_Expression_Constant('1', 1),
|
||||
new Twig_Node_Expression_Constant('2', 1),
|
||||
new Twig_Node_Expression_Constant('3', 1),
|
||||
'foo' => new Twig_Node_Expression_Constant('bar', 1),
|
||||
));
|
||||
$tests[] = array($node, 'twig_tests_test_barbar("abc", "1", "2", array(0 => "3", "foo" => "bar"))', $environment);
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
@@ -54,3 +76,7 @@ class Twig_Tests_Node_Expression_TestTest extends Twig_Test_NodeTestCase
|
||||
return parent::getEnvironment();
|
||||
}
|
||||
}
|
||||
|
||||
function twig_tests_test_barbar($string, $arg1 = null, $arg2 = null, array $args = array())
|
||||
{
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user