diff --git a/bundle/Templating/Twig/Node/GetAttrExpressionDecorator.php b/bundle/Templating/Twig/Node/GetAttrExpressionDecorator.php index c3ffc380..37371d84 100644 --- a/bundle/Templating/Twig/Node/GetAttrExpressionDecorator.php +++ b/bundle/Templating/Twig/Node/GetAttrExpressionDecorator.php @@ -29,14 +29,25 @@ public function __toString(): string return $this->decoratedExpression->__toString(); } + public function enableDefinedTest(): void + { + $this->decoratedExpression->enableDefinedTest(); + } + + public function isDefinedTestEnabled(): bool + { + return $this->decoratedExpression->isDefinedTestEnabled(); + } + public function compile(Compiler $compiler): void { $env = $compiler->getEnvironment(); + $arrayAccessSandbox = false; // optimize array calls if ( $this->getAttribute('optimizable') - && !$this->getAttribute('is_defined_test') + && !$this->isDefinedTestEnabled() && $this->getAttribute('type') === Template::ARRAY_CALL && (!$env->isStrictVariables() || $this->getAttribute('ignore_strict_check')) ) { @@ -45,16 +56,33 @@ public function compile(Compiler $compiler): void ->raw('((' . $var . ' = ') ->subcompile($this->getNode('node')) ->raw(') && is_array(') - ->raw($var) + ->raw($var); + + if (!$env->hasExtension(SandboxExtension::class)) { + $compiler + ->raw(') || ') + ->raw($var) + ->raw(' instanceof ArrayAccess ? (') + ->raw($var) + ->raw('[') + ->subcompile($this->getNode('attribute')) + ->raw('] ?? null) : null)'); + + return; + } + + $arrayAccessSandbox = true; + + $compiler ->raw(') || ') ->raw($var) - ->raw(' instanceof ArrayAccess ? (') + ->raw(' instanceof ArrayAccess && in_array(') + ->raw($var.'::class') + ->raw(', CoreExtension::ARRAY_LIKE_CLASSES, true) ? (') ->raw($var) ->raw('[') ->subcompile($this->getNode('attribute')) - ->raw('] ?? null) : null)'); - - return; + ->raw('] ?? null) : '); } $compiler->raw(self::class . '::twigGetAttribute($this->env, $this->source, '); @@ -76,11 +104,15 @@ public function compile(Compiler $compiler): void $compiler->raw(', ') ->repr($this->getAttribute('type')) - ->raw(', ')->repr($this->getAttribute('is_defined_test')) + ->raw(', ')->repr($this->isDefinedTestEnabled()) ->raw(', ')->repr($this->getAttribute('ignore_strict_check')) ->raw(', ')->repr($env->hasExtension(SandboxExtension::class)) ->raw(', ')->repr($this->getNode('node')->getTemplateLine()) ->raw(')'); + + if ($arrayAccessSandbox) { + $compiler->raw(')'); + } } public function getTemplateLine(): int @@ -98,9 +130,9 @@ public function hasAttribute(string $name): bool return $this->decoratedExpression->hasAttribute($name); } - public function getAttribute(string $name) + public function getAttribute($name, $default = null) { - return $this->decoratedExpression->getAttribute($name); + return $this->decoratedExpression->getAttribute($name, $default); } public function setAttribute(string $name, $value): void @@ -171,7 +203,7 @@ public static function twigGetAttribute( mixed $object, mixed $item, array $arguments = [], - $type = 'any', + $type = Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false, $sandboxed = false, diff --git a/composer.json b/composer.json index 29445203..1909c2d4 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "ibexa/fieldtype-richtext": "^4.6", "netgen/ibexa-search-extra": "^3.0", "sensio/framework-extra-bundle": "^6.1.0", - "twig/twig": "^3.9" + "twig/twig": "^3.21" }, "require-dev": { "phpunit/phpunit": "^9.0",