Skip to content

Commit 0ce79df

Browse files
committed
Use trigger_deprecation() instead of trigger_error() for deprecations
1 parent 9252578 commit 0ce79df

13 files changed

+131
-30
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# 3.11.0 (2024-XX-XX)
22

3+
* Add the possibility to add a package and a version to the `deprecated` tag
4+
* Add the possibility to add a package for filter/function/test deprecations
35
* Mark `ConstantExpression` as being `@final`
46
* Add the `find` filter
57
* Fix optimizer mode validation in `OptimizerNodeVisitor`

doc/advanced.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,18 @@ deprecated one when that makes sense::
285285
// ...
286286
}, ['deprecated' => true, 'alternative' => 'new_one']);
287287

288+
.. versionadded:: 3.11
289+
290+
The ``deprecating_package`` option was added in Twig 3.11.
291+
292+
You can also set the ``deprecating_package`` option to specify the package that
293+
is deprecating the filter, and ``deprecated`` can be set to the package version
294+
when the filter was deprecated::
295+
296+
$filter = new \Twig\TwigFilter('obsolete', function () {
297+
// ...
298+
}, ['deprecated' => '1.1', 'deprecating_package' => 'foo/bar']);
299+
288300
When a filter is deprecated, Twig emits a deprecation notice when compiling a
289301
template using it. See :ref:`deprecation-notices` for more information.
290302

doc/tags/deprecated.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ You can also deprecate a macro in the following way:
2323
Note that by default, the deprecation notices are silenced and never displayed nor logged.
2424
See :ref:`deprecation-notices` to learn how to handle them.
2525

26+
.. versionadded:: 3.11
27+
28+
The ``package`` and ``version`` options were added in Twig 3.11.
29+
30+
You can optionally add the package and the version that introduced the deprecation:
31+
32+
.. code-block:: twig
33+
34+
{% deprecated 'The "base.twig" template is deprecated, use "layout.twig" instead.' package='twig/twig' %}
35+
{% deprecated 'The "base.twig" template is deprecated, use "layout.twig" instead.' package='twig/twig' version='3.11' %}
36+
2637
.. note::
2738

2839
Don't use the ``deprecated`` tag to deprecate a ``block`` as the

src/ExpressionParser.php

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -774,16 +774,13 @@ private function getTestNodeClass(TwigTest $test): string
774774
$stream = $this->parser->getStream();
775775
$message = \sprintf('Twig Test "%s" is deprecated', $test->getName());
776776

777-
if ($test->getDeprecatedVersion()) {
778-
$message .= \sprintf(' since version %s', $test->getDeprecatedVersion());
779-
}
780777
if ($test->getAlternative()) {
781778
$message .= \sprintf('. Use "%s" instead', $test->getAlternative());
782779
}
783780
$src = $stream->getSourceContext();
784781
$message .= \sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine());
785782

786-
@trigger_error($message, \E_USER_DEPRECATED);
783+
trigger_deprecation($test->getDeprecatingPackage(), $test->getDeprecatedVersion(), $message);
787784
}
788785

789786
return $test->getNodeClass();
@@ -800,16 +797,13 @@ private function getFunctionNodeClass(string $name, int $line): string
800797

801798
if ($function->isDeprecated()) {
802799
$message = \sprintf('Twig Function "%s" is deprecated', $function->getName());
803-
if ($function->getDeprecatedVersion()) {
804-
$message .= \sprintf(' since version %s', $function->getDeprecatedVersion());
805-
}
806800
if ($function->getAlternative()) {
807801
$message .= \sprintf('. Use "%s" instead', $function->getAlternative());
808802
}
809803
$src = $this->parser->getStream()->getSourceContext();
810804
$message .= \sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
811805

812-
@trigger_error($message, \E_USER_DEPRECATED);
806+
trigger_deprecation($function->getDeprecatingPackage(), $function->getDeprecatedVersion(), $message);
813807
}
814808

815809
return $function->getNodeClass();
@@ -826,16 +820,13 @@ private function getFilterNodeClass(string $name, int $line): string
826820

827821
if ($filter->isDeprecated()) {
828822
$message = \sprintf('Twig Filter "%s" is deprecated', $filter->getName());
829-
if ($filter->getDeprecatedVersion()) {
830-
$message .= \sprintf(' since version %s', $filter->getDeprecatedVersion());
831-
}
832823
if ($filter->getAlternative()) {
833824
$message .= \sprintf('. Use "%s" instead', $filter->getAlternative());
834825
}
835826
$src = $this->parser->getStream()->getSourceContext();
836827
$message .= \sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
837828

838-
@trigger_error($message, \E_USER_DEPRECATED);
829+
trigger_deprecation($filter->getDeprecatingPackage(), $filter->getDeprecatedVersion(), $message);
839830
}
840831

841832
return $filter->getNodeClass();

src/Node/DeprecatedNode.php

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,39 @@ public function compile(Compiler $compiler): void
3535

3636
$expr = $this->getNode('expr');
3737

38-
if ($expr instanceof ConstantExpression) {
39-
$compiler->write('@trigger_error(')
40-
->subcompile($expr);
41-
} else {
38+
if (!$expr instanceof ConstantExpression) {
4239
$varName = $compiler->getVarName();
43-
$compiler->write(\sprintf('$%s = ', $varName))
40+
$compiler
41+
->write(\sprintf('$%s = ', $varName))
4442
->subcompile($expr)
4543
->raw(";\n")
46-
->write(\sprintf('@trigger_error($%s', $varName));
44+
;
45+
}
46+
47+
$compiler->write('trigger_deprecation(');
48+
if ($this->hasNode('package')) {
49+
$compiler->subcompile($this->getNode('package'));
50+
} else {
51+
$compiler->raw("''");
52+
}
53+
$compiler->raw(', ');
54+
if ($this->hasNode('version')) {
55+
$compiler->subcompile($this->getNode('version'));
56+
} else {
57+
$compiler->raw("''");
58+
}
59+
$compiler->raw(', ');
60+
61+
if ($expr instanceof ConstantExpression) {
62+
$compiler->subcompile($expr);
63+
} else {
64+
$compiler->write(\sprintf('$%s', $varName));
4765
}
4866

4967
$compiler
50-
->raw('.')
51-
->string(\sprintf(' ("%s" at line %d).', $this->getTemplateName(), $this->getTemplateLine()))
52-
->raw(", E_USER_DEPRECATED);\n")
68+
->raw(".")
69+
->string(\sprintf(' in "%s" at line %d.', $this->getTemplateName(), $this->getTemplateLine()))
70+
->raw(");\n")
5371
;
5472
}
5573
}

src/TokenParser/DeprecatedTokenParser.php

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Twig\TokenParser;
1313

14+
use Twig\Error\SyntaxError;
1415
use Twig\Node\DeprecatedNode;
1516
use Twig\Node\Node;
1617
use Twig\Token;
@@ -21,6 +22,8 @@
2122
* {% deprecated 'The "base.twig" template is deprecated, use "layout.twig" instead.' %}
2223
* {% extends 'layout.html.twig' %}
2324
*
25+
* {% deprecated 'The "base.twig" template is deprecated, use "layout.twig" instead.' package="foo/bar" version="1.1" %}
26+
*
2427
* @author Yonel Ceruto <[email protected]>
2528
*
2629
* @internal
@@ -29,11 +32,31 @@ final class DeprecatedTokenParser extends AbstractTokenParser
2932
{
3033
public function parse(Token $token): Node
3134
{
32-
$expr = $this->parser->getExpressionParser()->parseExpression();
35+
$stream = $this->parser->getStream();
36+
$expressionParser = $this->parser->getExpressionParser();
37+
$expr = $expressionParser->parseExpression();
38+
$node = new DeprecatedNode($expr, $token->getLine(), $this->getTag());
39+
40+
while ($stream->test(Token::NAME_TYPE)) {
41+
$k = $stream->getCurrent()->getValue();
42+
$stream->next();
43+
$stream->expect(Token::OPERATOR_TYPE, '=');
44+
45+
switch ($k) {
46+
case 'package':
47+
$node->setNode('package', $expressionParser->parseExpression());
48+
break;
49+
case 'version':
50+
$node->setNode('version', $expressionParser->parseExpression());
51+
break;
52+
default:
53+
throw new SyntaxError(\sprintf('Unknown "%s" option.', $k), $stream->getCurrent()->getLine(), $stream->getSourceContext());
54+
}
55+
}
3356

34-
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
57+
$stream->expect(Token::BLOCK_END_TYPE);
3558

36-
return new DeprecatedNode($expr, $token->getLine(), $this->getTag());
59+
return $node;
3760
}
3861

3962
public function getTag(): string

src/TwigFilter.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public function __construct(string $name, $callable = null, array $options = [])
4646
'preserves_safety' => null,
4747
'node_class' => FilterExpression::class,
4848
'deprecated' => false,
49+
'deprecating_package' => '',
4950
'alternative' => null,
5051
], $options);
5152
}
@@ -128,6 +129,11 @@ public function isDeprecated(): bool
128129
return (bool) $this->options['deprecated'];
129130
}
130131

132+
public function getDeprecatingPackage(): string
133+
{
134+
return $this->options['deprecating_package'];
135+
}
136+
131137
public function getDeprecatedVersion(): string
132138
{
133139
return \is_bool($this->options['deprecated']) ? '' : $this->options['deprecated'];

src/TwigFunction.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public function __construct(string $name, $callable = null, array $options = [])
4444
'is_safe_callback' => null,
4545
'node_class' => FunctionExpression::class,
4646
'deprecated' => false,
47+
'deprecating_package' => '',
4748
'alternative' => null,
4849
], $options);
4950
}
@@ -116,6 +117,11 @@ public function isDeprecated(): bool
116117
return (bool) $this->options['deprecated'];
117118
}
118119

120+
public function getDeprecatingPackage(): string
121+
{
122+
return $this->options['deprecating_package'];
123+
}
124+
119125
public function getDeprecatedVersion(): string
120126
{
121127
return \is_bool($this->options['deprecated']) ? '' : $this->options['deprecated'];

src/TwigTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public function __construct(string $name, $callable = null, array $options = [])
3838
'is_variadic' => false,
3939
'node_class' => TestExpression::class,
4040
'deprecated' => false,
41+
'deprecating_package' => '',
4142
'alternative' => null,
4243
'one_mandatory_argument' => false,
4344
], $options);
@@ -83,6 +84,11 @@ public function isDeprecated(): bool
8384
return (bool) $this->options['deprecated'];
8485
}
8586

87+
public function getDeprecatingPackage(): string
88+
{
89+
return $this->options['deprecating_package'];
90+
}
91+
8692
public function getDeprecatedVersion(): string
8793
{
8894
return \is_bool($this->options['deprecated']) ? '' : $this->options['deprecated'];
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Deprecating a template with "deprecated" tag
3+
--TEMPLATE--
4+
{% deprecated 'The "index.twig" template is deprecated, use "greeting.twig" instead.' package="foo/bar" %}
5+
6+
Hello Fabien
7+
--DATA--
8+
return []
9+
--EXPECT--
10+
Hello Fabien
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Deprecating a template with "deprecated" tag
3+
--TEMPLATE--
4+
{% deprecated 'The "index.twig" template is deprecated, use "greeting.twig" instead.' package="foo/bar" version=1.1 %}
5+
6+
Hello Fabien
7+
--DATA--
8+
return []
9+
--EXPECT--
10+
Hello Fabien

tests/Node/DeprecatedTest.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,29 @@ public function getTests()
3939
$expr = new ConstantExpression('This section is deprecated', 1);
4040
$node = new DeprecatedNode($expr, 1, 'deprecated');
4141
$node->setSourceContext(new Source('', 'foo.twig'));
42+
$node->setNode('package', new ConstantExpression('twig/twig', 1));
43+
$node->setNode('version', new ConstantExpression('1.1', 1));
4244

4345
$tests[] = [$node, <<<EOF
4446
// line 1
45-
@trigger_error("This section is deprecated"." (\"foo.twig\" at line 1).", E_USER_DEPRECATED);
47+
trigger_deprecation("twig/twig", "1.1", "This section is deprecated"." in \"foo.twig\" at line 1.");
4648
EOF
4749
];
4850

4951
$t = new Node([
5052
new ConstantExpression(true, 1),
51-
new DeprecatedNode($expr, 2, 'deprecated'),
53+
$dep = new DeprecatedNode($expr, 2, 'deprecated'),
5254
], [], 1);
5355
$node = new IfNode($t, null, 1);
5456
$node->setSourceContext(new Source('', 'foo.twig'));
57+
$dep->setNode('package', new ConstantExpression('twig/twig', 1));
58+
$dep->setNode('version', new ConstantExpression('1.1', 1));
5559

5660
$tests[] = [$node, <<<EOF
5761
// line 1
5862
if (true) {
5963
// line 2
60-
@trigger_error("This section is deprecated"." (\"foo.twig\" at line 2).", E_USER_DEPRECATED);
64+
trigger_deprecation("twig/twig", "1.1", "This section is deprecated"." in \"foo.twig\" at line 2.");
6165
}
6266
EOF
6367
];
@@ -68,14 +72,16 @@ public function getTests()
6872
$expr = new FunctionExpression('foo', new Node(), 1);
6973
$node = new DeprecatedNode($expr, 1, 'deprecated');
7074
$node->setSourceContext(new Source('', 'foo.twig'));
75+
$node->setNode('package', new ConstantExpression('twig/twig', 1));
76+
$node->setNode('version', new ConstantExpression('1.1', 1));
7177

7278
$compiler = $this->getCompiler($environment);
7379
$varName = $compiler->getVarName();
7480

7581
$tests[] = [$node, <<<EOF
7682
// line 1
7783
\$$varName = foo();
78-
@trigger_error(\$$varName." (\"foo.twig\" at line 1).", E_USER_DEPRECATED);
84+
trigger_deprecation("twig/twig", "1.1", \$$varName." in \"foo.twig\" at line 1.");
7985
EOF
8086
, $environment];
8187

tests/Util/DeprecationCollectorTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ class DeprecationCollectorTest extends TestCase
2525
public function testCollect()
2626
{
2727
$twig = new Environment(new ArrayLoader());
28-
$twig->addFunction(new TwigFunction('deprec', [$this, 'deprec'], ['deprecated' => '1.1']));
28+
$twig->addFunction(new TwigFunction('deprec', [$this, 'deprec'], ['deprecated' => '1.1', 'deprecating_package' => 'foo/bar']));
2929

3030
$collector = new DeprecationCollector($twig);
3131
$deprecations = $collector->collect(new Iterator());
3232

33-
$this->assertEquals(['Twig Function "deprec" is deprecated since version 1.1 in deprec.twig at line 1.'], $deprecations);
33+
$this->assertEquals(['Since foo/bar 1.1: Twig Function "deprec" is deprecated in deprec.twig at line 1.'], $deprecations);
3434
}
3535

3636
public function deprec()

0 commit comments

Comments
 (0)