Skip to content

Commit

Permalink
[!!!][FEATURE] Boolean and Null literals (#949)
Browse files Browse the repository at this point in the history
This patch enhances Fluid's capabilities of dealing with booleans and null significantly.
Previously, the actual booleans `false` and `true` could be only created from within inline
syntax or if a ViewHelper argument was defined as boolean (in which case strings were
parsed as boolean). `null` values couldn't really be created at all. Now, there exist
standard variables for true, false, and null, which can be used in all contexts.

This patch is marked as breaking because it disallows the usage of the variable names
`true`, `false` and `null` in variable providers.
  • Loading branch information
s2b authored Aug 9, 2024
1 parent 08c24b0 commit ba2c48b
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 18 deletions.
47 changes: 30 additions & 17 deletions src/Core/Parser/SyntaxTree/ObjectAccessorNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,42 @@ public function getObjectPath(): string
*/
public function evaluate(RenderingContextInterface $renderingContext): mixed
{
$objectPath = strtolower($this->objectPath);
$variableProvider = $renderingContext->getVariableProvider();
if ($objectPath === '_all') {
return $variableProvider->getAll();
}
return $variableProvider->getByPath($this->objectPath);
return match (strtolower($this->objectPath)) {
'_all' => $variableProvider->getAll(),
'true' => true,
'false' => false,
'null' => null,
default => $variableProvider->getByPath($this->objectPath),
};
}

public function convert(TemplateCompiler $templateCompiler): array
{
$path = $this->objectPath;
if ($path === '_all') {
return [
return match (strtolower($this->objectPath)) {
'_all' => [
'initialization' => '',
'execution' => '$renderingContext->getVariableProvider()->getAll()',
];
}
return [
'initialization' => '',
'execution' => sprintf(
'$renderingContext->getVariableProvider()->getByPath(\'%s\')',
$path,
),
];
],
'true' => [
'initialization' => '',
'execution' => 'true',
],
'false' => [
'initialization' => '',
'execution' => 'false',
],
'null' => [
'initialization' => '',
'execution' => 'null',
],
default => [
'initialization' => '',
'execution' => sprintf(
'$renderingContext->getVariableProvider()->getByPath(\'%s\')',
$this->objectPath,
),
],
};
}
}
12 changes: 12 additions & 0 deletions src/Core/Variables/InvalidVariableIdentifierException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?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\Core\Variables;

class InvalidVariableIdentifierException extends \Exception {}
5 changes: 5 additions & 0 deletions src/Core/Variables/StandardVariableProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
class StandardVariableProvider implements VariableProviderInterface
{
protected array $disallowedIdentifiers = ['null', 'true', 'false', '_all'];

/**
* Variables stored in context
*
Expand Down Expand Up @@ -75,6 +77,9 @@ public function getAll(): array|\ArrayAccess
*/
public function add(string $identifier, mixed $value): void
{
if (in_array(strtolower($identifier), $this->disallowedIdentifiers)) {
throw new InvalidVariableIdentifierException('Invalid variable identifier: ' . $identifier, 1723131119);
}
$this->variables[$identifier] = $value;
}

Expand Down
5 changes: 4 additions & 1 deletion tests/Unit/Core/Parser/SyntaxTree/ObjectAccessorNodeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public static function getEvaluateTestValues(): array
[['foo' => ['bar' => 'test'], 'dynamic' => 'bar'], 'foo.{dynamic}', 'test'],
[['foo' => ['bar' => 'test'], 'dynamic' => ['sub' => 'bar']], 'foo.{dynamic.sub}', 'test'],
[['foo' => ['bar' => 'test'], 'dynamic' => ['sub' => 'bar'], 'baz' => 'sub'], 'foo.{dynamic.{baz}}', 'test'],
[[], 'true', true],
[[], 'false', false],
[[], 'null', null],
];
}

Expand All @@ -43,7 +46,7 @@ public function testEvaluateGetsExpectedValue(array $variables, string $path, $e
$variableContainer = new StandardVariableProvider($variables);
$renderingContext->expects(self::any())->method('getVariableProvider')->willReturn($variableContainer);
$value = $node->evaluate($renderingContext);
self::assertEquals($expected, $value);
self::assertSame($expected, $value);
}

#[Test]
Expand Down
10 changes: 10 additions & 0 deletions tests/Unit/Core/Variables/StandardVariableProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use TYPO3Fluid\Fluid\Core\Variables\InvalidVariableIdentifierException;
use TYPO3Fluid\Fluid\Core\Variables\StandardVariableProvider;
use TYPO3Fluid\Fluid\Tests\Unit\Core\Variables\Fixtures\StandardVariableProviderModelFixture;

Expand Down Expand Up @@ -434,4 +435,13 @@ public function getByPathReturnsExpectedValues(array $variables, string $path, $
$result = $subject->getByPath($path);
self::assertEquals($expected, $result);
}

#[Test]
public function exceptionIsThrownForInvalidVariableIdentifier(): void
{
self::expectException(InvalidVariableIdentifierException::class);
self::expectExceptionCode(1723131119);
$subject = new StandardVariableProvider();
$subject->add('TrUe', false);
}
}

0 comments on commit ba2c48b

Please sign in to comment.