mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-30 12:06:56 +00:00
Fix testing and expression when it evaluates to an instance of Markup
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
# 3.21.0 (2025-XX-XX)
|
||||
|
||||
* Fix testing and expression when it evaluates to an instance of `Markup`
|
||||
* Add `ReturnPrimitiveTypeInterface` (and sub-interfaces for number, boolean, string, and array)
|
||||
* Add `SupportDefinedTestInterface` for expression nodes supporting the `defined` test
|
||||
* Deprecate using the `|` operator in an expression with `+` or `-` without using parentheses to clarify precedence
|
||||
* Deprecate operator precedence outside of the [0, 512] range
|
||||
|
||||
@@ -76,6 +76,7 @@ use Twig\Node\Expression\Test\EvenTest;
|
||||
use Twig\Node\Expression\Test\NullTest;
|
||||
use Twig\Node\Expression\Test\OddTest;
|
||||
use Twig\Node\Expression\Test\SameasTest;
|
||||
use Twig\Node\Expression\Test\TrueTest;
|
||||
use Twig\Node\Expression\Unary\NegUnary;
|
||||
use Twig\Node\Expression\Unary\NotUnary;
|
||||
use Twig\Node\Expression\Unary\PosUnary;
|
||||
@@ -318,6 +319,7 @@ final class CoreExtension extends AbstractExtension
|
||||
new TwigTest('iterable', 'is_iterable'),
|
||||
new TwigTest('sequence', [self::class, 'testSequence']),
|
||||
new TwigTest('mapping', [self::class, 'testMapping']),
|
||||
new TwigTest('true', null, ['node_class' => TrueTest::class]),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ use Twig\Node\Expression\Unary\SpreadUnary;
|
||||
use Twig\Node\Expression\Unary\StringCastUnary;
|
||||
use Twig\Node\Expression\Variable\ContextVariable;
|
||||
|
||||
class ArrayExpression extends AbstractExpression implements SupportDefinedTestInterface
|
||||
class ArrayExpression extends AbstractExpression implements SupportDefinedTestInterface, ReturnArrayInterface
|
||||
{
|
||||
use SupportDefinedTestTrait;
|
||||
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class AddBinary extends AbstractBinary
|
||||
class AddBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class AndBinary extends AbstractBinary
|
||||
class AndBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class BitwiseAndBinary extends AbstractBinary
|
||||
class BitwiseAndBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class BitwiseOrBinary extends AbstractBinary
|
||||
class BitwiseOrBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class BitwiseXorBinary extends AbstractBinary
|
||||
class BitwiseXorBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnStringInterface;
|
||||
|
||||
class ConcatBinary extends AbstractBinary
|
||||
class ConcatBinary extends AbstractBinary implements ReturnStringInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class DivBinary extends AbstractBinary
|
||||
class DivBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class EndsWithBinary extends AbstractBinary
|
||||
class EndsWithBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class EqualBinary extends AbstractBinary
|
||||
class EqualBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class FloorDivBinary extends AbstractBinary
|
||||
class FloorDivBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class GreaterBinary extends AbstractBinary
|
||||
class GreaterBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class GreaterEqualBinary extends AbstractBinary
|
||||
class GreaterEqualBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class HasEveryBinary extends AbstractBinary
|
||||
class HasEveryBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class HasSomeBinary extends AbstractBinary
|
||||
class HasSomeBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class InBinary extends AbstractBinary
|
||||
class InBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class LessBinary extends AbstractBinary
|
||||
class LessBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class LessEqualBinary extends AbstractBinary
|
||||
class LessEqualBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -13,10 +13,11 @@ namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Node;
|
||||
|
||||
class MatchesBinary extends AbstractBinary
|
||||
class MatchesBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function __construct(Node $left, Node $right, int $lineno)
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class ModBinary extends AbstractBinary
|
||||
class ModBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class MulBinary extends AbstractBinary
|
||||
class MulBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class NotEqualBinary extends AbstractBinary
|
||||
class NotEqualBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class NotInBinary extends AbstractBinary
|
||||
class NotInBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class OrBinary extends AbstractBinary
|
||||
class OrBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class PowerBinary extends AbstractBinary
|
||||
class PowerBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnArrayInterface;
|
||||
|
||||
class RangeBinary extends AbstractBinary
|
||||
class RangeBinary extends AbstractBinary implements ReturnArrayInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class SpaceshipBinary extends AbstractBinary
|
||||
class SpaceshipBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class StartsWithBinary extends AbstractBinary
|
||||
class StartsWithBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnNumberInterface;
|
||||
|
||||
class SubBinary extends AbstractBinary
|
||||
class SubBinary extends AbstractBinary implements ReturnNumberInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
namespace Twig\Node\Expression\Binary;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnBoolInterface;
|
||||
|
||||
class XorBinary extends AbstractBinary
|
||||
class XorBinary extends AbstractBinary implements ReturnBoolInterface
|
||||
{
|
||||
public function operator(Compiler $compiler): Compiler
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ use Twig\Compiler;
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class ConstantExpression extends AbstractExpression implements SupportDefinedTestInterface
|
||||
class ConstantExpression extends AbstractExpression implements SupportDefinedTestInterface, ReturnPrimitiveTypeInterface
|
||||
{
|
||||
use SupportDefinedTestTrait;
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Node\Expression;
|
||||
|
||||
interface ReturnArrayInterface extends ReturnPrimitiveTypeInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Node\Expression;
|
||||
|
||||
interface ReturnBoolInterface extends ReturnPrimitiveTypeInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Node\Expression;
|
||||
|
||||
interface ReturnNumberInterface extends ReturnPrimitiveTypeInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Node\Expression;
|
||||
|
||||
interface ReturnPrimitiveTypeInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Node\Expression;
|
||||
|
||||
interface ReturnStringInterface extends ReturnPrimitiveTypeInterface
|
||||
{
|
||||
}
|
||||
@@ -14,11 +14,18 @@ namespace Twig\Node\Expression\Ternary;
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\OperatorEscapeInterface;
|
||||
use Twig\Node\Expression\ReturnPrimitiveTypeInterface;
|
||||
use Twig\Node\Expression\Test\TrueTest;
|
||||
use Twig\TwigTest;
|
||||
|
||||
final class ConditionalTernary extends AbstractExpression implements OperatorEscapeInterface
|
||||
{
|
||||
public function __construct(AbstractExpression $test, AbstractExpression $left, AbstractExpression $right, int $lineno)
|
||||
{
|
||||
if (!$test instanceof ReturnPrimitiveTypeInterface) {
|
||||
$test = new TrueTest($test, new TwigTest('true'), null, $test->getTemplateLine());
|
||||
}
|
||||
|
||||
parent::__construct(['test' => $test, 'left' => $left, 'right' => $right], [], $lineno);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ use Twig\Compiler;
|
||||
use Twig\Node\Expression\TestExpression;
|
||||
|
||||
/**
|
||||
* Checks that a variable is null.
|
||||
* Checks that an expression is null.
|
||||
*
|
||||
* {{ var is none }}
|
||||
*
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Node\Expression\Test;
|
||||
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\TestExpression;
|
||||
|
||||
/**
|
||||
* Checks that an expression is true.
|
||||
*
|
||||
* {{ var is true }}
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class TrueTest extends TestExpression
|
||||
{
|
||||
public function compile(Compiler $compiler): void
|
||||
{
|
||||
$compiler
|
||||
->raw('(($tmp = ')
|
||||
->subcompile($this->getNode('node'))
|
||||
->raw(') && $tmp instanceof Markup ? (string) $tmp : $tmp)')
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ use Twig\Node\NameDeprecation;
|
||||
use Twig\Node\Node;
|
||||
use Twig\TwigTest;
|
||||
|
||||
class TestExpression extends CallExpression
|
||||
class TestExpression extends CallExpression implements ReturnBoolInterface
|
||||
{
|
||||
#[FirstClassTwigCallableReady]
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,9 @@ namespace Twig\Node;
|
||||
|
||||
use Twig\Attribute\YieldReady;
|
||||
use Twig\Compiler;
|
||||
use Twig\Node\Expression\ReturnPrimitiveTypeInterface;
|
||||
use Twig\Node\Expression\Test\TrueTest;
|
||||
use Twig\TwigTest;
|
||||
|
||||
/**
|
||||
* Represents an if node.
|
||||
@@ -25,6 +28,12 @@ class IfNode extends Node
|
||||
{
|
||||
public function __construct(Node $tests, ?Node $else, int $lineno)
|
||||
{
|
||||
for ($i = 0, $count = \count($tests); $i < $count; $i += 2) {
|
||||
$test = $tests->getNode((string) $i);
|
||||
if (!$test instanceof ReturnPrimitiveTypeInterface) {
|
||||
$tests->setNode($i, new TrueTest($test, new TwigTest('true'), null, $test->getTemplateLine()));
|
||||
}
|
||||
}
|
||||
$nodes = ['tests' => $tests];
|
||||
if (null !== $else) {
|
||||
$nodes['else'] = $else;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
Twig outputs 0 nodes correctly
|
||||
--TEMPLATE--
|
||||
{{ empty|trim ? 'KO' : 'ok' }}
|
||||
{{ spaces|trim ? 'KO' : 'ok' }}
|
||||
{% if empty %}KO{% else %}ok{% endif %}
|
||||
|
||||
{% if spaces|trim %}KO{% else %}ok{% endif %}
|
||||
|
||||
{% set bar %} {% endset %}{{ bar|trim ? 'KO' : 'ok' }}
|
||||
--DATA--
|
||||
return ['spaces' => new Twig\Markup(' ', 'UTF-8'), 'empty' => new Twig\Markup('', 'UTF-8')]
|
||||
--EXPECT--
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
Reference in New Issue
Block a user