Fix merge conflict resolution

This commit is contained in:
Fabien Potencier
2026-05-21 14:11:53 +02:00
parent 8dd0383353
commit b91dbaa1ba
5 changed files with 25 additions and 38 deletions
@@ -67,12 +67,15 @@ final class DotExpressionParser extends AbstractExpressionParser implements Infi
if (
$expr instanceof ContextVariable
&& $attribute instanceof ConstantExpression
&& \is_string($name = $attribute->getAttribute('value'))
&& preg_match('#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#D', $name)
&& (
null !== $parser->getImportedSymbol('template', $expr->getAttribute('name'))
|| '_self' === $expr->getAttribute('name') && $attribute instanceof ConstantExpression
|| '_self' === $expr->getAttribute('name')
)
) {
return new MacroReferenceExpression(new TemplateVariable($expr->getAttribute('name'), $expr->getTemplateLine()), 'macro_'.$attribute->getAttribute('value'), $arguments, $expr->getTemplateLine());
return new MacroReferenceExpression(new TemplateVariable($expr->getAttribute('name'), $expr->getTemplateLine()), 'macro_'.$name, $arguments, $expr->getTemplateLine());
}
return new GetAttrExpression($expr, $attribute, $arguments, $type, $lineno, $nullSafe);
+17 -2
View File
@@ -267,7 +267,7 @@ final class CoreExtension extends AbstractExtension
new TwigFilter('sort', self::sort(...)),
new TwigFilter('merge', self::merge(...)),
new TwigFilter('batch', self::batch(...)),
new TwigFilter('column', self::column(...)),
new TwigFilter('column', self::column(...), ['needs_environment' => true, 'needs_is_sandboxed' => true]),
new TwigFilter('filter', self::filter(...)),
new TwigFilter('map', self::map(...)),
new TwigFilter('reduce', self::reduce(...)),
@@ -1619,6 +1619,9 @@ final class CoreExtension extends AbstractExtension
public static function getAttribute(Environment $env, Source $source, $object, $item, array $arguments = [], $type = Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false, $sandboxed = false, int $lineno = -1)
{
$propertyNotAllowedError = null;
if ($sandboxed && $item instanceof \Stringable) {
$env->getExtension(SandboxExtension::class)->ensureToStringAllowed($item, $lineno, $source);
}
// array
if (Template::METHOD_CALL !== $type) {
@@ -1879,7 +1882,7 @@ final class CoreExtension extends AbstractExtension
*
* @internal
*/
public static function column($array, $name, $index = null): array
public static function column(Environment $env, bool $isSandboxed, $array, $name, $index = null): array
{
if (!is_iterable($array)) {
throw new RuntimeError(\sprintf('The "column" filter expects a sequence or a mapping, got "%s".', get_debug_type($array)));
@@ -1889,6 +1892,18 @@ final class CoreExtension extends AbstractExtension
$array = iterator_to_array($array);
}
if ($isSandboxed) {
$sandbox = $env->getExtension(SandboxExtension::class);
foreach ($array as $item) {
if (\is_object($item)) {
$sandbox->checkPropertyAllowed($item, (string) $name);
if (null !== $index) {
$sandbox->checkPropertyAllowed($item, (string) $index);
}
}
}
}
return array_column($array, $name, $index);
}
+1 -1
View File
@@ -115,7 +115,7 @@ final class SandboxNodeVisitor implements NodeVisitorInterface
foreach ($expr->getOperandNamesToEscape() as $operandName) {
$this->wrapNode($expr, $operandName);
}
} elseif ($expr instanceof FilterExpression || $expr instanceof FunctionExpression) {
} elseif (($expr instanceof FilterExpression || $expr instanceof FunctionExpression) && !$expr->isGenerator()) {
$node->setNode($name, new CheckToStringNode($expr));
}
}
-30
View File
@@ -868,36 +868,6 @@ EOF
$twig->load('1_basic')->render([]);
}
/**
* @dataProvider provideSourcePolicyArrowBlockedTemplates
*/
public function testSourcePolicyBlocksNonClosureCallableInArrow(string $template)
{
$sourcePolicy = new class implements \Twig\Sandbox\SourcePolicyInterface {
public function enableSandbox(Source $source): bool
{
return true;
}
};
$twig = $this->getEnvironment(false, [], ['1_basic' => $template], [], ['sort', 'filter', 'map', 'reduce', 'find', 'join'], [], [], [], $sourcePolicy);
$this->expectException(RuntimeError::class);
$this->expectExceptionMessageMatches('/must be a Closure in sandbox mode/');
$twig->load('1_basic')->render([]);
}
public static function provideSourcePolicyArrowBlockedTemplates(): iterable
{
yield 'sort' => ['{{ ["a","b"]|sort("strnatcasecmp")|join }}'];
yield 'filter' => ['{{ ["a","b"]|filter("is_string")|join }}'];
yield 'map' => ['{{ ["a","b"]|map("strtoupper")|join }}'];
yield 'reduce' => ['{{ [1,2]|reduce("intval") }}'];
yield 'find' => ['{{ ["a","b"]|find("is_string") }}'];
yield 'has some' => ['{{ [1,2] has some "is_string" ? "yes" : "no" }}'];
yield 'has every' => ['{{ [1,2] has every "is_int" ? "yes" : "no" }}'];
}
public function testSourcePolicyAllowsClosureInArrow()
{
$sourcePolicy = new class implements \Twig\Sandbox\SourcePolicyInterface {
+2 -3
View File
@@ -11,6 +11,7 @@
namespace Twig\Tests\Node\Expression;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\MacroReferenceExpression;
@@ -18,9 +19,7 @@ use Twig\Node\Expression\Variable\TemplateVariable;
class MacroReferenceTest extends TestCase
{
/**
* @dataProvider provideInvalidMacroNames
*/
#[DataProvider('provideInvalidMacroNames')]
public function testConstructorRejectsNonIdentifierName(string $name)
{
$this->expectException(\LogicException::class);