diff --git a/CHANGELOG b/CHANGELOG index 4fcfde212..762bb9cc7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 1.36.0 (2018-XX-XX) + * added the "deprecated" tag * added support for dynamically named tests * fixed filesystem loader throwing an exception instead of returning false diff --git a/doc/tags/deprecated.rst b/doc/tags/deprecated.rst new file mode 100644 index 000000000..f36743f08 --- /dev/null +++ b/doc/tags/deprecated.rst @@ -0,0 +1,30 @@ +``deprecated`` +============== + +.. versionadded:: 1.36 and 2.6 + The ``deprecated`` tag was added in Twig 1.36 and 2.6. + +Twig generates a deprecation notice (via a call to the ``trigger_error()`` +PHP function) where the ``deprecated`` tag is used in a template: + +.. code-block:: jinja + + {# base.twig #} + {% deprecated 'The "base.twig" template is deprecated, use "layout.twig" instead.' %} + {% extends 'layout.twig' %} + +Also you can deprecate a block in the following way: + +.. code-block:: jinja + + {% block hey %} + {% deprecated 'The "hey" block is deprecated, use "greet" instead.' %} + {{ block('greet') }} + {% endblock %} + + {% block greet %} + Hey you! + {% endblock %} + +Note that by default, the deprecation notices are silenced and never displayed nor logged. +See :ref:`deprecation-notices` to learn how to handle them. diff --git a/doc/tags/index.rst b/doc/tags/index.rst index dbe2459e3..373cf6e65 100644 --- a/doc/tags/index.rst +++ b/doc/tags/index.rst @@ -23,3 +23,4 @@ Tags use verbatim with + deprecated diff --git a/lib/Twig/Extension/Core.php b/lib/Twig/Extension/Core.php index 6fa78e131..7d8c8807c 100644 --- a/lib/Twig/Extension/Core.php +++ b/lib/Twig/Extension/Core.php @@ -136,6 +136,7 @@ class Twig_Extension_Core extends Twig_Extension new Twig_TokenParser_Do(), new Twig_TokenParser_Embed(), new Twig_TokenParser_With(), + new Twig_TokenParser_Deprecated(), ); } diff --git a/lib/Twig/Node/Deprecated.php b/lib/Twig/Node/Deprecated.php new file mode 100644 index 000000000..e2bc55315 --- /dev/null +++ b/lib/Twig/Node/Deprecated.php @@ -0,0 +1,49 @@ + + */ +class Twig_Node_Deprecated extends Twig_Node +{ + public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) + { + parent::__construct(array('expr' => $expr), array(), $lineno, $tag); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->addDebugInfo($this); + + $expr = $this->getNode('expr'); + + if ($expr instanceof Twig_Node_Expression_Constant) { + $compiler->write('@trigger_error(') + ->subcompile($expr); + } else { + $varName = $compiler->getVarName(); + $compiler->write(sprintf('$%s = ', $varName)) + ->subcompile($expr) + ->raw(";\n") + ->write(sprintf('@trigger_error($%s', $varName)); + } + + $compiler + ->raw('.') + ->string(sprintf(' ("%s" at line %d).', $this->getTemplateName(), $this->getTemplateLine())) + ->raw(", E_USER_DEPRECATED);\n") + ; + } +} + +class_alias('Twig_Node_Deprecated', 'Twig\Node\DeprecatedNode', false); diff --git a/lib/Twig/TokenParser/Deprecated.php b/lib/Twig/TokenParser/Deprecated.php new file mode 100644 index 000000000..be5d54960 --- /dev/null +++ b/lib/Twig/TokenParser/Deprecated.php @@ -0,0 +1,42 @@ + + * {% deprecated 'The "base.twig" template is deprecated, use "layout.twig" instead.' %} + * + * {% extends 'layout.html.twig' %} + * + * + * @author Yonel Ceruto + * + * @final + */ +class Twig_TokenParser_Deprecated extends Twig_TokenParser +{ + public function parse(Twig_Token $token) + { + $expr = $this->parser->getExpressionParser()->parseExpression(); + + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + + return new Twig_Node_Deprecated($expr, $token->getLine(), $this->getTag()); + } + + public function getTag() + { + return 'deprecated'; + } +} + +class_alias('Twig_TokenParser_Deprecated', 'Twig\TokenParser\DeprecatedTokenParser', false); diff --git a/src/Node/DeprecatedNode.php b/src/Node/DeprecatedNode.php new file mode 100644 index 000000000..0c0e1b0a9 --- /dev/null +++ b/src/Node/DeprecatedNode.php @@ -0,0 +1,11 @@ +assertEquals($expr, $node->getNode('expr')); + } + + public function getTests() + { + $tests = array(); + + $expr = new Twig_Node_Expression_Constant('This section is deprecated', 1); + $node = new Twig_Node_Deprecated($expr, 1, 'deprecated'); + $node->setTemplateName('foo.twig'); + + $tests[] = array($node, <<setTemplateName('foo.twig'); + + $tests[] = array($node, <<getMockBuilder('Twig_LoaderInterface')->getMock()); + $environment->addFunction(new Twig_SimpleFunction('foo', 'foo', array())); + + $expr = new Twig_Node_Expression_Function('foo', new Twig_Node(), 1); + $node = new Twig_Node_Deprecated($expr, 1, 'deprecated'); + $node->setTemplateName('foo.twig'); + + $compiler = $this->getCompiler($environment); + $varName = $compiler->getVarName(); + + $tests[] = array($node, <<