Skip to content

Commit

Permalink
[FEATURE] Respect ContainerInterface in StandardVariableProvider (#1002)
Browse files Browse the repository at this point in the history
With this change, it is possible to access properties of objects implementing
`Psr\Container\ContainerInterface` from Fluid templates using the normal
object accessor syntax. The interface requires two methods `has()` and `get()`
which are used by Fluid to obtain the requested property from the object.
  • Loading branch information
o-ba authored Sep 10, 2024
1 parent 8fa9173 commit a5d7bd3
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 1 deletion.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"phpstan/phpstan": "^1.11.5",
"phpstan/phpstan-phpunit": "^1.4.0",
"phpunit/phpunit": "^11.2.5",
"t3docs/fluid-documentation-generator": "^4.3"
"t3docs/fluid-documentation-generator": "^4.3",
"psr/container": "^2.0"
},
"suggest": {
"ext-json": "PHP JSON is needed when using JSONVariableProvider: A relatively rare use case",
Expand Down
6 changes: 6 additions & 0 deletions src/Core/Variables/StandardVariableProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

namespace TYPO3Fluid\Fluid\Core\Variables;

use Psr\Container\ContainerInterface;

/**
* Class StandardVariableProvider
*/
Expand Down Expand Up @@ -117,6 +119,10 @@ public function getByPath(string $path): mixed
continue;
}
if (is_object($subject)) {
if ($subject instanceof ContainerInterface && $subject->has($pathSegment)) {
$subject = $subject->get($pathSegment);
continue;
}
$upperCasePropertyName = ucfirst($pathSegment);
$getMethod = 'get' . $upperCasePropertyName;
if (method_exists($subject, $getMethod)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?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\Unit\Core\Variables\Fixtures;

use Psr\Container\ContainerInterface;

/**
* Used by StandardVariableProviderTest
*/
final readonly class StandardVariableProviderContainerFixture implements ContainerInterface
{
public function __construct(private array $properties) {}

public function get(string $id): mixed
{
return $this->properties[$id] ?? null;
}

public function has(string $id): bool
{
return array_key_exists($id, $this->properties);
}
}
64 changes: 64 additions & 0 deletions tests/Unit/Core/Variables/StandardVariableProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPUnit\Framework\TestCase;
use TYPO3Fluid\Fluid\Core\Variables\InvalidVariableIdentifierException;
use TYPO3Fluid\Fluid\Core\Variables\StandardVariableProvider;
use TYPO3Fluid\Fluid\Tests\Unit\Core\Variables\Fixtures\StandardVariableProviderContainerFixture;
use TYPO3Fluid\Fluid\Tests\Unit\Core\Variables\Fixtures\StandardVariableProviderModelFixture;

final class StandardVariableProviderTest extends TestCase
Expand Down Expand Up @@ -245,6 +246,69 @@ public static function getPathTestValues(): array
'user.invalid',
null,
],
'access container' => [
[
'user' => new StandardVariableProviderContainerFixture(['name' => 'Foobar Name']),
],
'user.name',
'Foobar Name',
],
'access container getter that returns empty string' => [
[
'user' => new StandardVariableProviderContainerFixture(['name' => '']),
],
'user.name',
'',
],
'access container getter that returns FALSE' => [
[
'user' => new StandardVariableProviderContainerFixture(['name' => false]),
],
'user.name',
false,
],
'access container getter that returns object' => [
[
'user' => new StandardVariableProviderContainerFixture(['object' => new \stdClass()]),
],
'user.object',
new \stdClass(),
],
'access container getter that returns object recursive' => [
[
'user' => new StandardVariableProviderContainerFixture(['object' => new StandardVariableProviderModelFixture('Foobar Name')]),
],
'user.object.name',
'Foobar Name',
],
'access container getter that returns container recursive' => [
[
'user' => new StandardVariableProviderContainerFixture(['object' => new StandardVariableProviderContainerFixture(['name' => 'Foobar Name'])]),
],
'user.object.name',
'Foobar Name',
],
'access container getter that returns array' => [
[
'user' => new StandardVariableProviderContainerFixture(['array' => ['foo' => 'bar']]),
],
'user.array',
['foo' => 'bar'],
],
'access container getter that returns value of array' => [
[
'user' => new StandardVariableProviderContainerFixture(['array' => ['foo' => 'bar']]),
],
'user.array.foo',
'bar',
],
'access container not existing returns null' => [
[
'user' => new StandardVariableProviderContainerFixture(['name' => 'Foobar Name']),
],
'user.invalid',
null,
],
'access dynamic variable using invalid variable reference' => [
[],
'{invalid}',
Expand Down

0 comments on commit a5d7bd3

Please sign in to comment.