diff --git a/CHANGELOG b/CHANGELOG index 54d3a847b..01e4acaba 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,9 @@ * Deprecate `Twig\ExpressionParser\parseHashExpression()` in favor of `Twig\ExpressionParser::parseMappingExpression()` + * Deprecate `Twig\ExpressionParser\parseArrayExpression()`` in favor of + `Twig\ExpressionParser::parseSequenceExpression()` + # 3.10.3 (2024-05-16) * Fix missing ; in generated code diff --git a/doc/coding_standards.rst b/doc/coding_standards.rst index f7bdb43c2..d10906fa6 100644 --- a/doc/coding_standards.rst +++ b/doc/coding_standards.rst @@ -40,7 +40,7 @@ standards: {{ foo ~ bar }} {{ true ? true : false }} -* Put exactly one space after the ``:`` sign in mappings and ``,`` in arrays +* Put exactly one space after the ``:`` sign in mappings and ``,`` in sequences and mappings: .. code-block:: twig @@ -80,8 +80,8 @@ standards: {{ foo|default('foo') }} {{ range(1..10) }} -* Do not put any spaces before and after the opening and the closing of arrays - and mappings: +* Do not put any spaces before and after the opening and the closing of + sequences and mappings: .. code-block:: twig diff --git a/doc/deprecated.rst b/doc/deprecated.rst index 91b6d9329..c994dc7fa 100644 --- a/doc/deprecated.rst +++ b/doc/deprecated.rst @@ -51,6 +51,9 @@ Parser * The ``Twig\ExpressionParser::parseHashExpression()`` method is deprecated, use ``Twig\ExpressionParser::parseMappingExpression()`` instead. +* The ``Twig\ExpressionParser::parseArrayExpression()`` method is deprecated, use + ``Twig\ExpressionParser::parseSequenceExpression()`` instead. + Templates --------- diff --git a/doc/filters/data_uri.rst b/doc/filters/data_uri.rst index e008266b3..131a71bb8 100644 --- a/doc/filters/data_uri.rst +++ b/doc/filters/data_uri.rst @@ -50,6 +50,6 @@ Arguments --------- * ``mime``: The mime type -* ``parameters``: An array of parameters +* ``parameters``: A mapping of parameters .. _RFC 2397: https://tools.ietf.org/html/rfc2397 diff --git a/doc/filters/keys.rst b/doc/filters/keys.rst index 6bed8291e..26c61bcd1 100644 --- a/doc/filters/keys.rst +++ b/doc/filters/keys.rst @@ -1,14 +1,20 @@ ``keys`` ======== -The ``keys`` filter returns the keys of an array. It is useful when you want to -iterate over the keys of an array: +The ``keys`` filter returns the keys of a sequence or a mapping. It is useful +when you want to iterate over the keys of a sequence or a mapping: .. code-block:: twig - {% for key in array|keys %} - ... + {% for key in [1, 2, 3, 4]|keys %} + {{ key }} {% endfor %} + {# outputs: 1 2 3 4 #} + + {% for key in {a: 'a_value', b: 'b_value'}|keys %} + {{ key }} + {% endfor %} + {# outputs: a b #} .. note:: diff --git a/doc/filters/merge.rst b/doc/filters/merge.rst index 633dcf75f..fc21884ba 100644 --- a/doc/filters/merge.rst +++ b/doc/filters/merge.rst @@ -1,7 +1,9 @@ ``merge`` ========= -The ``merge`` filter merges an array with another array: +The ``merge`` filter merges sequences and mappings. + +The ``merge`` filter also works on sequences: .. code-block:: twig @@ -29,7 +31,7 @@ overridden. .. tip:: - If you want to ensure that some values are defined in an array (by given + If you want to ensure that some values are defined in a mapping (by given default values), reverse the two elements in the call: .. code-block:: twig diff --git a/doc/filters/sort.rst b/doc/filters/sort.rst index 98b7afe37..4afd60e7d 100644 --- a/doc/filters/sort.rst +++ b/doc/filters/sort.rst @@ -1,7 +1,7 @@ ``sort`` ======== -The ``sort`` filter sorts an array: +The ``sort`` filter sorts sequences and mappings: .. code-block:: twig @@ -15,7 +15,7 @@ The ``sort`` filter sorts an array: association. It supports Traversable objects by transforming those to arrays. -You can pass an arrow function to sort the array: +You can pass an arrow function to configure the sorting: .. code-block:: html+twig diff --git a/doc/filters/split.rst b/doc/filters/split.rst index 386ae3043..f6728ddad 100644 --- a/doc/filters/split.rst +++ b/doc/filters/split.rst @@ -11,7 +11,7 @@ of strings: You can also pass a ``limit`` argument: -* If ``limit`` is positive, the returned array will contain a maximum of +* If ``limit`` is positive, the returned sequence will contain a maximum of limit elements with the last element containing the rest of string; * If ``limit`` is negative, all components except the last -limit are diff --git a/doc/filters/url_encode.rst b/doc/filters/url_encode.rst index c5919be01..f78983134 100644 --- a/doc/filters/url_encode.rst +++ b/doc/filters/url_encode.rst @@ -1,8 +1,8 @@ ``url_encode`` ============== -The ``url_encode`` filter percent encodes a given string as URL segment -or an array as query string: +The ``url_encode`` filter percent encodes a given string as URL segment or a +mapping as query string: .. code-block:: twig diff --git a/doc/functions/cycle.rst b/doc/functions/cycle.rst index 46f8f21ca..3b6db61c4 100644 --- a/doc/functions/cycle.rst +++ b/doc/functions/cycle.rst @@ -1,7 +1,7 @@ ``cycle`` ========= -The ``cycle`` function cycles on an array of values: +The ``cycle`` function cycles on a sequence or mapping: .. code-block:: twig diff --git a/doc/tags/for.rst b/doc/tags/for.rst index 4517f5907..3bd859bd0 100644 --- a/doc/tags/for.rst +++ b/doc/tags/for.rst @@ -1,8 +1,8 @@ ``for`` ======= -Loop over each item in a sequence. For example, to display a list of users -provided in a variable called ``users``: +Loop over each item in a sequence or a mapping. For example, to display a list +of users provided in a variable called ``users``: .. code-block:: html+twig @@ -15,8 +15,8 @@ provided in a variable called ``users``: .. note:: - A sequence can be either an array or an object implementing the - ``Traversable`` interface. + A sequence or a mapping can be either an array or an object implementing + the ``Traversable`` interface. If you do need to iterate over a sequence of numbers, you can use the ``..`` operator: diff --git a/doc/tags/if.rst b/doc/tags/if.rst index 0523cb1ac..8a29af5da 100644 --- a/doc/tags/if.rst +++ b/doc/tags/if.rst @@ -12,7 +12,7 @@ In the simplest form you can use it to test if an expression evaluates to
Our website is in maintenance mode. Please, come back later.
{% endif %} -You can also test if an array is not empty: +You can also test if a sequence or a mapping is not empty: .. code-block:: html+twig @@ -71,8 +71,10 @@ use more complex ``expressions`` there too: INF (Infinity) true whitespace-only string true string "0" or '0' false - empty array false + empty sequence false + empty mapping false null false - non-empty array true + non-empty sequence true + non-empty mapping true object true ====================== ==================== diff --git a/doc/templates.rst b/doc/templates.rst index 0acc1c8d9..4c1b847b9 100644 --- a/doc/templates.rst +++ b/doc/templates.rst @@ -102,7 +102,7 @@ If a variable or attribute does not exist, the behavior depends on the For convenience's sake ``foo.bar`` does the following things on the PHP layer: - * check if ``foo`` is an array and ``bar`` a valid element; + * check if ``foo`` is a sequence or a mapping and ``bar`` a valid element; * if not, and if ``foo`` is an object, check that ``bar`` is a valid property; * if not, and if ``foo`` is an object, check that ``bar`` is a valid method (even if ``bar`` is the constructor - use ``__construct()`` instead); @@ -115,7 +115,7 @@ If a variable or attribute does not exist, the behavior depends on the Twig also supports a specific syntax for accessing items on PHP arrays, ``foo['bar']``: - * check if ``foo`` is an array and ``bar`` a valid element; + * check if ``foo`` is a sequence or a mapping and ``bar`` a valid element; * if not, and if ``strict_variables`` is ``false``, return ``null``; * if not, throw an exception. @@ -531,7 +531,7 @@ exist: writing the number down. If a dot is present the number is a float, otherwise an integer. -* ``["foo", "bar"]``: Arrays are defined by a sequence of expressions +* ``["foo", "bar"]``: Sequences are defined by a sequence of expressions separated by a comma (``,``) and wrapped with squared brackets (``[]``). * ``{"foo": "bar"}``: Mappings are defined by a list of keys and values @@ -563,7 +563,7 @@ exist: * ``null``: ``null`` represents no specific value. This is the value returned when a variable does not exist. ``none`` is an alias for ``null``. -Arrays and mappings can be nested: +Sequences and mappings can be nested: .. code-block:: twig @@ -698,8 +698,8 @@ operand is contained in the right: .. tip:: - You can use this filter to perform a containment test on strings, arrays, - or objects implementing the ``Traversable`` interface. + You can use this filter to perform a containment test on strings, + sequences, mappings, or objects implementing the ``Traversable`` interface. To perform a negative test, use the ``not in`` operator: @@ -785,7 +785,7 @@ The following operators don't fit into any of the other categories: {# returns the value of foo if it is defined and not null, 'no' otherwise #} {{ foo ?? 'no' }} -* ``...``: The spread operator can be used to expand arrays or mappings (it +* ``...``: The spread operator can be used to expand sequences or mappings (it cannot be used to expand the arguments of a function call): .. code-block:: twig @@ -827,7 +827,7 @@ Operator Score of precedence Description ``**`` 200 Raises a number to the power of another ``??`` 300 Default value when a variable is null ``+``, ``-`` 500 Unary operations on numbers -``|``,``[]``,``.`` - Filters, array, mapping, and attribute access +``|``,``[]``,``.`` - Filters, sequence, mapping, and attribute access ============================= =================================== ===================================================== Without using any parentheses, the operator precedence rules are used to diff --git a/doc/tests/empty.rst b/doc/tests/empty.rst index 6348f92ae..3abdb8bbd 100644 --- a/doc/tests/empty.rst +++ b/doc/tests/empty.rst @@ -1,7 +1,7 @@ ``empty`` ========= -``empty`` checks if a variable is an empty string, an empty array, an empty +``empty`` checks if a variable is an empty string, an empty sequence, an empty mapping, exactly ``false``, or exactly ``null``. For objects that implement the ``Countable`` interface, ``empty`` will check the diff --git a/src/ExpressionParser.php b/src/ExpressionParser.php index 443c7daa1..3a97370ed 100644 --- a/src/ExpressionParser.php +++ b/src/ExpressionParser.php @@ -278,7 +278,7 @@ class ExpressionParser // no break default: if ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '[')) { - $node = $this->parseArrayExpression(); + $node = $this->parseSequenceExpression(); } elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) { $node = $this->parseMappingExpression(); } elseif ($token->test(/* Token::OPERATOR_TYPE */ 8, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) { @@ -320,15 +320,22 @@ class ExpressionParser } public function parseArrayExpression() + { + trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseSequenceExpression()" instead.', __METHOD__); + + return $this->parseSequenceExpression(); + } + + public function parseSequenceExpression() { $stream = $this->parser->getStream(); - $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'An array element was expected'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'A sequence element was expected'); $node = new ArrayExpression([], $stream->getCurrent()->getLine()); $first = true; while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) { if (!$first) { - $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A sequence element must be followed by a comma'); // trailing ,? if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) { @@ -346,7 +353,7 @@ class ExpressionParser $node->addElement($this->parseExpression()); } } - $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened sequence is not properly closed'); return $node; } @@ -641,7 +648,7 @@ class ExpressionParser $value = $this->parsePrimaryExpression(); if (!$this->checkConstantExpression($value)) { - throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, or an array).', $token->getLine(), $stream->getSourceContext()); + throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping).', $token->getLine(), $stream->getSourceContext()); } } else { $value = $this->parseExpression(0, $allowArrow); diff --git a/src/Extension/CoreExtension.php b/src/Extension/CoreExtension.php index 405a35353..a7bdc8204 100644 --- a/src/Extension/CoreExtension.php +++ b/src/Extension/CoreExtension.php @@ -329,7 +329,7 @@ final class CoreExtension extends AbstractExtension } if (!\count($values)) { - throw new RuntimeError('The "cycle" function does not work on empty arrays.'); + throw new RuntimeError('The "cycle" function does not work on empty sequences/mappings.'); } return $values[$position % \count($values)]; @@ -399,7 +399,7 @@ final class CoreExtension extends AbstractExtension $values = self::toArray($values); if (0 === \count($values)) { - throw new RuntimeError('The random function cannot pick from an empty array.'); + throw new RuntimeError('The random function cannot pick from an empty sequence/mapping.'); } return $values[array_rand($values, 1)]; @@ -536,7 +536,7 @@ final class CoreExtension extends AbstractExtension public static function replace($str, $from): string { if (!is_iterable($from)) { - throw new RuntimeError(\sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from))); + throw new RuntimeError(\sprintf('The "replace" filter expects a sequence/mapping or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from))); } return strtr($str ?? '', self::toArray($from)); @@ -633,7 +633,7 @@ final class CoreExtension extends AbstractExtension foreach ($arrays as $argNumber => $array) { if (!is_iterable($array)) { - throw new RuntimeError(\sprintf('The merge filter only works with arrays or "Traversable", got "%s" for argument %d.', \gettype($array), $argNumber + 1)); + throw new RuntimeError(\sprintf('The merge filter only works with sequences/mappings or "Traversable", got "%s" for argument %d.', \gettype($array), $argNumber + 1)); } $result = array_merge($result, self::toArray($array)); @@ -907,7 +907,7 @@ final class CoreExtension extends AbstractExtension if ($array instanceof \Traversable) { $array = iterator_to_array($array); } elseif (!\is_array($array)) { - throw new RuntimeError(\sprintf('The sort filter only works with arrays or "Traversable", got "%s".', \gettype($array))); + throw new RuntimeError(\sprintf('The sort filter only works with sequences/mappings or "Traversable", got "%s".', \gettype($array))); } if (null !== $arrow) { @@ -1424,7 +1424,7 @@ final class CoreExtension extends AbstractExtension public static function batch($items, $size, $fill = null, $preserveKeys = true): array { if (!is_iterable($items)) { - throw new RuntimeError(\sprintf('The "batch" filter expects an array or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items))); + throw new RuntimeError(\sprintf('The "batch" filter expects a sequence/mapping or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items))); } $size = ceil($size); @@ -1491,9 +1491,9 @@ final class CoreExtension extends AbstractExtension $message = \sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object)); } elseif (\is_array($object)) { if (empty($object)) { - $message = \sprintf('Key "%s" does not exist as the array is empty.', $arrayItem); + $message = \sprintf('Key "%s" does not exist as the sequence/mapping is empty.', $arrayItem); } else { - $message = \sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object))); + $message = \sprintf('Key "%s" for sequence/mapping with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object))); } } elseif (/* Template::ARRAY_CALL */ 'array' === $type) { if (null === $object) { @@ -1523,7 +1523,7 @@ final class CoreExtension extends AbstractExtension if (null === $object) { $message = \sprintf('Impossible to invoke a method ("%s") on a null variable.', $item); } elseif (\is_array($object)) { - $message = \sprintf('Impossible to invoke a method ("%s") on an array.', $item); + $message = \sprintf('Impossible to invoke a method ("%s") on a sequence/mapping.', $item); } else { $message = \sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); } @@ -1661,7 +1661,7 @@ final class CoreExtension extends AbstractExtension if ($array instanceof \Traversable) { $array = iterator_to_array($array); } elseif (!\is_array($array)) { - throw new RuntimeError(\sprintf('The column filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array))); + throw new RuntimeError(\sprintf('The column filter only works with sequences/mappings or "Traversable", got "%s" as first argument.', \gettype($array))); } return array_column($array, $name, $index); @@ -1673,7 +1673,7 @@ final class CoreExtension extends AbstractExtension public static function filter(Environment $env, $array, $arrow) { if (!is_iterable($array)) { - throw new RuntimeError(\sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array))); + throw new RuntimeError(\sprintf('The "filter" filter expects a sequence/mapping or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array))); } self::checkArrowInSandbox($env, $arrow, 'filter', 'filter'); @@ -1709,7 +1709,7 @@ final class CoreExtension extends AbstractExtension self::checkArrowInSandbox($env, $arrow, 'reduce', 'filter'); if (!\is_array($array) && !$array instanceof \Traversable) { - throw new RuntimeError(\sprintf('The "reduce" filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array))); + throw new RuntimeError(\sprintf('The "reduce" filter only works with sequences/mappings or "Traversable", got "%s" as first argument.', \gettype($array))); } $accumulator = $initial; diff --git a/tests/ExpressionParserTest.php b/tests/ExpressionParserTest.php index e00c2598d..abf5ae3a8 100644 --- a/tests/ExpressionParserTest.php +++ b/tests/ExpressionParserTest.php @@ -55,9 +55,9 @@ class ExpressionParserTest extends TestCase } /** - * @dataProvider getTestsForArray + * @dataProvider getTestsForSequence */ - public function testArrayExpression($template, $expected) + public function testSequenceExpression($template, $expected) { $env = new Environment($this->createMock(LoaderInterface::class), ['cache' => false, 'autoescape' => false]); $stream = $env->tokenize($source = new Source($template, '')); @@ -68,9 +68,9 @@ class ExpressionParserTest extends TestCase } /** - * @dataProvider getFailingTestsForArray + * @dataProvider getFailingTestsForSequence */ - public function testArraySyntaxError($template) + public function testSequenceSyntaxError($template) { $this->expectException(SyntaxError::class); @@ -79,7 +79,7 @@ class ExpressionParserTest extends TestCase $parser->parse($env->tokenize(new Source($template, 'index'))); } - public function getFailingTestsForArray() + public function getFailingTestsForSequence() { return [ ['{{ [1, "a": "b"] }}'], @@ -88,10 +88,10 @@ class ExpressionParserTest extends TestCase ]; } - public function getTestsForArray() + public function getTestsForSequence() { return [ - // simple array + // simple sequence ['{{ [1, 2] }}', new ArrayExpression([ new ConstantExpression(0, 1), new ConstantExpression(1, 1), @@ -101,7 +101,7 @@ class ExpressionParserTest extends TestCase ], 1), ], - // array with trailing , + // sequence with trailing , ['{{ [1, 2, ] }}', new ArrayExpression([ new ConstantExpression(0, 1), new ConstantExpression(1, 1), @@ -131,7 +131,7 @@ class ExpressionParserTest extends TestCase ], 1), ], - // mapping in an array + // mapping in a sequence ['{{ [1, {"a": "b", "b": "c"}] }}', new ArrayExpression([ new ConstantExpression(0, 1), new ConstantExpression(1, 1), @@ -147,7 +147,7 @@ class ExpressionParserTest extends TestCase ], 1), ], - // array in a mapping + // sequence in a mapping ['{{ {"a": [1, 2], "b": "c"} }}', new ArrayExpression([ new ConstantExpression('a', 1), new ArrayExpression([ @@ -168,7 +168,7 @@ class ExpressionParserTest extends TestCase new NameExpression('b', 1), ], 1)], - // array with spread operator + // sequence with spread operator ['{{ [1, 2, ...foo] }}', new ArrayExpression([ new ConstantExpression(0, 1), @@ -301,7 +301,7 @@ class ExpressionParserTest extends TestCase public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template) { $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('A default value for an argument must be a constant (a boolean, a string, a number, or an array) in "index" at line 1'); + $this->expectExceptionMessage('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping) in "index" at line 1'); $env = new Environment($this->createMock(LoaderInterface::class), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); diff --git a/tests/Fixtures/exceptions/exception_in_extension_extends.test b/tests/Fixtures/exceptions/exception_in_extension_extends.test index 2ab298059..fee521878 100644 --- a/tests/Fixtures/exceptions/exception_in_extension_extends.test +++ b/tests/Fixtures/exceptions/exception_in_extension_extends.test @@ -9,4 +9,4 @@ Exception thrown from a child for an extension error --DATA-- return [] --EXCEPTION-- -Twig\Error\RuntimeError: The random function cannot pick from an empty array in "base.twig" at line 4. +Twig\Error\RuntimeError: The random function cannot pick from an empty sequence/mapping in "base.twig" at line 4. diff --git a/tests/Fixtures/exceptions/exception_in_extension_include.test b/tests/Fixtures/exceptions/exception_in_extension_include.test index e2281b290..ab09cabb7 100644 --- a/tests/Fixtures/exceptions/exception_in_extension_include.test +++ b/tests/Fixtures/exceptions/exception_in_extension_include.test @@ -9,4 +9,4 @@ Exception thrown from an include for an extension error --DATA-- return [] --EXCEPTION-- -Twig\Error\RuntimeError: The random function cannot pick from an empty array in "content.twig" at line 4. +Twig\Error\RuntimeError: The random function cannot pick from an empty sequence/mapping in "content.twig" at line 4. diff --git a/tests/Fixtures/filters/replace_invalid_arg.test b/tests/Fixtures/filters/replace_invalid_arg.test index ba6fea412..ea1632500 100644 --- a/tests/Fixtures/filters/replace_invalid_arg.test +++ b/tests/Fixtures/filters/replace_invalid_arg.test @@ -5,4 +5,4 @@ Exception for invalid argument type in replace call --DATA-- return ['stdClass' => new \stdClass()] --EXCEPTION-- -Twig\Error\RuntimeError: The "replace" filter expects an array or "Traversable" as replace values, got "stdClass" in "index.twig" at line 2. +Twig\Error\RuntimeError: The "replace" filter expects a sequence/mapping or "Traversable" as replace values, got "stdClass" in "index.twig" at line 2. diff --git a/tests/Fixtures/functions/cycle_empty.test b/tests/Fixtures/functions/cycle_empty.test deleted file mode 100644 index bb338452a..000000000 --- a/tests/Fixtures/functions/cycle_empty.test +++ /dev/null @@ -1,8 +0,0 @@ ---TEST-- -"cycle" function returns an error on empty arrays ---TEMPLATE-- -{{ cycle([], 0) }} ---DATA-- -return [] ---EXCEPTION-- -Twig\Error\RuntimeError: The "cycle" function does not work on empty arrays in "index.twig" at line 2. diff --git a/tests/TemplateTest.php b/tests/TemplateTest.php index 9f9ca5a9e..1256b5df5 100644 --- a/tests/TemplateTest.php +++ b/tests/TemplateTest.php @@ -66,17 +66,17 @@ class TemplateTest extends TestCase return [ ['{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1.'], ['{{ null["a"] }}', 'Impossible to access a key ("a") on a null variable in "%s" at line 1.'], - ['{{ empty_array["a"] }}', 'Key "a" does not exist as the array is empty in "%s" at line 1.'], - ['{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1.'], + ['{{ empty_array["a"] }}', 'Key "a" does not exist as the sequence/mapping is empty in "%s" at line 1.'], + ['{{ array["a"] }}', 'Key "a" for sequence/mapping with keys "foo" does not exist in "%s" at line 1.'], ['{{ array_access["a"] }}', 'Key "a" in object with ArrayAccess of class "Twig\Tests\TemplateArrayAccessObject" does not exist in "%s" at line 1.'], ['{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1.'], ['{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1.'], ['{{ null.a }}', 'Impossible to access an attribute ("a") on a null variable in "%s" at line 1.'], ['{{ null.a() }}', 'Impossible to invoke a method ("a") on a null variable in "%s" at line 1.'], - ['{{ array.a() }}', 'Impossible to invoke a method ("a") on an array in "%s" at line 1.'], - ['{{ empty_array.a }}', 'Key "a" does not exist as the array is empty in "%s" at line 1.'], - ['{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1.'], - ['{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1.'], + ['{{ array.a() }}', 'Impossible to invoke a method ("a") on a sequence/mapping in "%s" at line 1.'], + ['{{ empty_array.a }}', 'Key "a" does not exist as the sequence/mapping is empty in "%s" at line 1.'], + ['{{ array.a }}', 'Key "a" for sequence/mapping with keys "foo" does not exist in "%s" at line 1.'], + ['{{ attribute(array, -10) }}', 'Key "-10" for sequence/mapping with keys "foo" does not exist in "%s" at line 1.'], ['{{ array_access.a }}', 'Neither the property "a" nor one of the methods "a()", "geta()"/"isa()"/"hasa()" or "__call()" exist and have public access in class "Twig\Tests\TemplateArrayAccessObject" in "%s" at line 1.'], ['{% from _self import foo %}{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ foo(array_access) }}', 'Neither the property "missing_method" nor one of the methods "missing_method()", "getmissing_method()"/"ismissing_method()"/"hasmissing_method()" or "__call()" exist and have public access in class "Twig\Tests\TemplateArrayAccessObject" in "%s" at line 1.'], ['{{ 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.'], @@ -193,14 +193,14 @@ class TemplateTest extends TestCase $this->assertSame('IntegerButStringWithLeadingZeros', $array['01']); $this->assertSame('EmptyString', $array[null]); - $this->assertSame('Zero', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)'); - $this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)'); - $this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)'); - $this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '1'), '"1" is treated as integer 1 when accessing an array (equals PHP behavior)'); - $this->assertSame('MinusOne', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, -1.5), 'negative float is casted to int when accessing an array (equals PHP behavior)'); - $this->assertSame('FloatButString', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '1.5'), '"1.5" is treated as-is when accessing an array (equals PHP behavior)'); - $this->assertSame('IntegerButStringWithLeadingZeros', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '01'), '"01" is treated as-is when accessing an array (equals PHP behavior)'); - $this->assertSame('EmptyString', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, null), 'null is treated as "" when accessing an array (equals PHP behavior)'); + $this->assertSame('Zero', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, false), 'false is treated as 0 when accessing a sequence/mapping (equals PHP behavior)'); + $this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, true), 'true is treated as 1 when accessing a sequence/mapping (equals PHP behavior)'); + $this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, 1.5), 'float is casted to int when accessing a sequence/mapping (equals PHP behavior)'); + $this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '1'), '"1" is treated as integer 1 when accessing a sequence/mapping (equals PHP behavior)'); + $this->assertSame('MinusOne', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, -1.5), 'negative float is casted to int when accessing a sequence/mapping (equals PHP behavior)'); + $this->assertSame('FloatButString', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '1.5'), '"1.5" is treated as-is when accessing a sequence/mapping (equals PHP behavior)'); + $this->assertSame('IntegerButStringWithLeadingZeros', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '01'), '"01" is treated as-is when accessing a sequence/mapping (equals PHP behavior)'); + $this->assertSame('EmptyString', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, null), 'null is treated as "" when accessing a sequence/mapping (equals PHP behavior)'); } /** @@ -395,7 +395,7 @@ class TemplateTest extends TestCase $tests = array_merge($tests, [ [false, null, 42, 'a', [], $anyType, 'Impossible to access an attribute ("a") on a integer variable ("42") in "index.twig".'], [false, null, 'string', 'a', [], $anyType, 'Impossible to access an attribute ("a") on a string variable ("string") in "index.twig".'], - [false, null, [], 'a', [], $anyType, 'Key "a" does not exist as the array is empty in "index.twig".'], + [false, null, [], 'a', [], $anyType, 'Key "a" does not exist as the sequence/mapping is empty in "index.twig".'], ]); return $tests;