-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE] Array unpacking (spread operator)
This change adds unpacking to Fluid’s array syntax, also known as the spread operator. Internally, it uses PHP’s own spread operator, so the behavior should be consistent between Fluid and PHP. Example: <f:variable name="array1" value="{key1: 'value1'}" /> <f:variable name="array2" value="{key2: 'value2'}" /> <f:variable name="combinedArray" value="{...array1, ...array2, anotherKey: 'another value'}" /> Result: {key1: 'value1', key2: 'value2', anotherKey: 'another value'} Note that this change does not cover dynamic ViewHelper arguments. This means that you can only use the spread operator in normal array contexts, but not for arguments in inline ViewHelper syntax. This is currently not possible because then ViewHelper arguments could then only be validated at runtime rather than parsetime, which is where validation currently happens for performance reasons. Because of similarities between object accessor and array definition syntax, there is an edge case where Fluid wrongly chooses object accessor instead of array syntax. This only happens if the array syntax is used without any spaces at the beginning and only with a single spread operator. This case shouldn’t be relevant for real-world usage because it only creates a copy of the original array. This edge case results in null: {...input1} These variants work fine: { ...input1} { ...input1 } {...input1, ...input2} {key: value, ...input1}
- Loading branch information
Showing
5 changed files
with
233 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file belongs to the package "TYPO3 Fluid". | ||
* See LICENSE.txt that was shipped with this package. | ||
*/ | ||
|
||
namespace TYPO3Fluid\Fluid\Tests\Functional\Cases\Parsing; | ||
|
||
use TYPO3Fluid\Fluid\Tests\Functional\AbstractFunctionalTestCase; | ||
use TYPO3Fluid\Fluid\View\TemplateView; | ||
|
||
final class ArraySyntaxTest extends AbstractFunctionalTestCase | ||
{ | ||
public static function arraySyntaxDataProvider(): array | ||
{ | ||
return [ | ||
// Edge case: Fluid treats this expression as an object accessor instead of an array | ||
'single array spread without whitespace' => [ | ||
'<f:variable name="result" value="{...input1}" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
], | ||
null, | ||
], | ||
// Edge case: Fluid treats this expression as an object accessor instead of an array | ||
'single array spread with whitespace after' => [ | ||
'<f:variable name="result" value="{...input1 }" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
], | ||
null, | ||
], | ||
'single array spread with whitespace before' => [ | ||
'<f:variable name="result" value="{ ...input1}" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
], | ||
['abc' => 1, 'def' => 2], | ||
], | ||
'single array spread' => [ | ||
'<f:variable name="result" value="{ ...input1 }" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
], | ||
['abc' => 1, 'def' => 2], | ||
], | ||
'multiple array spreads' => [ | ||
'<f:variable name="result" value="{ ...input1, ...input2 }" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
'input2' => ['ghi' => 3], | ||
], | ||
['abc' => 1, 'def' => 2, 'ghi' => 3], | ||
], | ||
'multiple array spreads mixed with other items' => [ | ||
'<f:variable name="result" value="{ first: 1, ...input1, middle: \'middle value\', ...input2, last: { sub: 1 } }" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
'input2' => ['ghi' => 3], | ||
], | ||
['first' => 1, 'abc' => 1, 'def' => 2, 'middle' => 'middle value', 'ghi' => 3, 'last' => ['sub' => 1]], | ||
], | ||
'overwrite static value' => [ | ||
'<f:variable name="result" value="{ abc: 10, ...input1 }" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
], | ||
['abc' => 1, 'def' => 2], | ||
], | ||
'overwrite spreaded value' => [ | ||
'<f:variable name="result" value="{ ...input1, abc: 10 }" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
], | ||
['abc' => 10, 'def' => 2], | ||
], | ||
'overwrite spreaded value with spreaded value' => [ | ||
'<f:variable name="result" value="{ ...input1, ...input2 }" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
'input2' => ['abc' => 10], | ||
], | ||
['abc' => 10, 'def' => 2], | ||
], | ||
'whitespace variants' => [ | ||
'<f:variable name="result" value="{... input1 , ... input2}" />', | ||
[ | ||
'input1' => ['abc' => 1, 'def' => 2], | ||
'input2' => ['ghi' => 3], | ||
], | ||
['abc' => 1, 'def' => 2, 'ghi' => 3], | ||
] | ||
]; | ||
} | ||
|
||
/** | ||
* @test | ||
* @dataProvider arraySyntaxDataProvider | ||
*/ | ||
public function arraySyntax(string $source, array $variables, $expected): void | ||
{ | ||
$view = new TemplateView(); | ||
$view->getRenderingContext()->setCache(self::$cache); | ||
$view->getRenderingContext()->getTemplatePaths()->setTemplateSource($source); | ||
$view->assignMultiple($variables); | ||
$view->render(); | ||
self::assertSame($view->getRenderingContext()->getVariableProvider()->get('result'), $expected); | ||
|
||
$view = new TemplateView(); | ||
$view->getRenderingContext()->setCache(self::$cache); | ||
$view->getRenderingContext()->getTemplatePaths()->setTemplateSource($source); | ||
$view->assignMultiple($variables); | ||
$view->render(); | ||
self::assertSame($view->getRenderingContext()->getVariableProvider()->get('result'), $expected); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters