added the apply tag

This commit is contained in:
Fabien Potencier
2019-04-24 15:20:18 +02:00
parent f497913961
commit 619bc12f62
17 changed files with 231 additions and 12 deletions
+1
View File
@@ -1,5 +1,6 @@
* 1.40.0 (2019-XX-XX)
* added the "apply" tag as a replacement for the "filter" tag
* allowed Twig\Loader\FilesystemLoader::findTemplate() to return "null" instead of "false" (same meaning)
* added support for "Twig\Markup" instances in the "in" test
* fixed Lexer when using custom options containing the # char
+8 -3
View File
@@ -400,16 +400,21 @@ Most of the time though, a tag is not needed:
{{ '**markdown** text'|markdown }}
If you want use this filter on large amounts of text, wrap it with the
:doc:`filter <tags/filter>` tag:
:doc:`apply <tags/apply>` tag:
.. code-block:: jinja
{% filter markdown %}
{% apply markdown %}
Title
=====
Much better than creating a tag as you can **compose** filters.
{% endfilter %}
{% endapply %}
.. note::
The ``apply`` tag was introduced in Twig 1.40; use the ``filter`` tag with
previous versions.
* If your tag does not output anything, but only exists because of a side
effect, create a **function** that returns nothing and call it via the
+9 -4
View File
@@ -18,19 +18,24 @@ whitespace within HTML tags or whitespace in plain text:
{# output will be <div><strong>foo</strong></div> #}
You can combine ``spaceless`` with the ``filter`` tag to apply the
transformation on large amounts of HTML:
You can combine ``spaceless`` with the ``apply`` tag to apply the transformation
on large amounts of HTML:
.. code-block:: jinja
{% filter spaceless %}
{% apply spaceless %}
<div>
<strong>foo</strong>
</div>
{% endfilter %}
{% endapply %}
{# output will be <div><strong>foo</strong></div> #}
.. note::
The ``apply`` tag was introduced in Twig 1.40; use the ``filter`` tag with
previous versions.
This tag is not meant to "optimize" the size of the generated HTML content but
merely to avoid extra whitespace between HTML tags to avoid browser rendering
quirks under some circumstances.
+20
View File
@@ -0,0 +1,20 @@
``apply``
=========
The ``apply`` tag allows you to apply Twig filters on a block of template data:
.. code-block:: jinja
{% apply upper %}
This text becomes uppercase
{% endapply %}
You can also chain filters and pass arguments to them:
.. code-block:: jinja
{% apply lower|escape('html') %}
<strong>SOME TEXT</strong>
{% endapply %}
{# outputs "&lt;strong&gt;some text&lt;/strong&gt;" #}
+5
View File
@@ -1,6 +1,11 @@
``filter``
==========
.. note::
As of Twig 1.40, you should use the ``apply`` tag instead which does the
same thing except that the wrapped template data is not scoped.
Filter sections allow you to apply regular Twig filters on a block of template
data. Just wrap the code in the special ``filter`` section:
+15 -5
View File
@@ -167,17 +167,22 @@ example will join a list by commas:
{{ list|join(', ') }}
To apply a filter on a section of code, wrap it in the
:doc:`filter<tags/filter>` tag:
:doc:`apply<tags/apply>` tag:
.. code-block:: jinja
{% filter upper %}
{% apply upper %}
This text becomes uppercase
{% endfilter %}
{% endapply %}
Go to the :doc:`filters<filters/index>` page to learn more about built-in
filters.
.. note::
The ``apply`` tag was introduced in Twig 1.40; use the ``filter`` tag with
previous versions.
Functions
---------
@@ -895,14 +900,19 @@ the modifiers on one side of a tag or on both sides:
.. code-block:: jinja
{% filter spaceless %}
{% apply spaceless %}
<div>
<strong>foo bar</strong>
</div>
{% endfilter %}
{% endapply %}
{# output will be <div><strong>foo bar</strong></div> #}
.. note::
The ``apply`` tag was introduced in Twig 1.40; use the ``filter`` tag with
previous versions.
Extensions
----------
+2
View File
@@ -11,6 +11,7 @@
namespace Twig\Extension {
use Twig\ExpressionParser;
use Twig\TokenParser\ApplyTokenParser;
use Twig\TokenParser\BlockTokenParser;
use Twig\TokenParser\DeprecatedTokenParser;
use Twig\TokenParser\DoTokenParser;
@@ -139,6 +140,7 @@ class CoreExtension extends AbstractExtension
public function getTokenParsers()
{
return [
new ApplyTokenParser(),
new ForTokenParser(),
new IfTokenParser(),
new ExtendsTokenParser(),
+1
View File
@@ -111,6 +111,7 @@ class OptimizerNodeVisitor extends AbstractNodeVisitor
if (!$expression && 'Twig_Node' !== \get_class($node) && $prependedNodes = array_shift($this->prependedNodes)) {
$nodes = [];
foreach (array_unique($prependedNodes) as $name) {
die();
$nodes[] = new SetTempNode($name, $node->getTemplateLine());
}
+58
View File
@@ -0,0 +1,58 @@
<?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\TokenParser;
use Twig\Node\Expression\TempNameExpression;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\Node\SetNode;
use Twig\Token;
/**
* Applies filters on a section of a template.
*
* {% apply upper %}
* This text becomes uppercase
* {% endapplys %}
*/
final class ApplyTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$lineno = $token->getLine();
$name = $this->parser->getVarName();
$ref = new TempNameExpression($name, $lineno);
$ref->setAttribute('always_defined', true);
$filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag());
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this, 'decideApplyEnd'], true);
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
return new Node([
new SetNode(true, $ref, $body, $lineno, $this->getTag()),
new PrintNode($filter, $lineno, $this->getTag()),
]);
}
public function decideApplyEnd(Token $token)
{
return $token->test('endapply');
}
public function getTag()
{
return 'apply';
}
}
@@ -0,0 +1,10 @@
--TEST--
"apply" tag applies a filter on its children
--TEMPLATE--
{% apply upper %}
Some text with a {{ var }}
{% endapply %}
--DATA--
return ['var' => 'var']
--EXPECT--
SOME TEXT WITH A VAR
@@ -0,0 +1,8 @@
--TEST--
"apply" tag applies a filter on its children
--TEMPLATE--
{% apply json_encode|raw %}test{% endapply %}
--DATA--
return []
--EXPECT--
"test"
@@ -0,0 +1,10 @@
--TEST--
"apply" tags accept multiple chained filters
--TEMPLATE--
{% apply lower|title %}
{{ var }}
{% endapply %}
--DATA--
return ['var' => 'VAR']
--EXPECT--
Var
@@ -0,0 +1,16 @@
--TEST--
"apply" tags can be nested at will
--TEMPLATE--
{% apply lower|title %}
{{ var }}
{% apply upper %}
{{ var }}
{% endapply %}
{{ var }}
{% endapply %}
--DATA--
return ['var' => 'var']
--EXPECT--
Var
Var
Var
@@ -0,0 +1,15 @@
--TEST--
"apply" tag does not create a new scope
--TEMPLATE--
{% set foo = 'baz' %}
{% apply spaceless %}
{% set foo = 'foo' %}
{% set bar = 'bar' %}
{% endapply %}
{{ 'foo' == foo ? 'OK ' ~ foo : 'KO' }}
{{ 'bar' == bar ? 'OK ' ~ bar : 'KO' }}
--DATA--
return []
--EXPECT--
OK foo
OK bar
@@ -0,0 +1,13 @@
--TEST--
"apply" tag applies the filter on "for" tags
--TEMPLATE--
{% apply upper %}
{% for item in items %}
{{ item }}
{% endfor %}
{% endapply %}
--DATA--
return ['items' => ['a', 'b']]
--EXPECT--
A
B
@@ -0,0 +1,29 @@
--TEST--
"apply" tag applies the filter on "if" tags
--TEMPLATE--
{% apply upper %}
{% if items %}
{{ items|join(', ') }}
{% endif %}
{% if items.3 is defined %}
FOO
{% else %}
{{ items.1 }}
{% endif %}
{% if items.3 is defined %}
FOO
{% elseif items.1 %}
{{ items.0 }}
{% endif %}
{% endapply %}
--DATA--
return ['items' => ['a', 'b']]
--EXPECT--
A, B
B
A
@@ -0,0 +1,11 @@
--TEST--
"scope" tag creates a new scope
--TEMPLATE--
{% filter spaceless %}
{% set item = 'foo' %}
{% endfilter %}
{{ item }}
--DATA--
return []
--EXCEPTION--
Twig\Error\RuntimeError: Variable "item" does not exist in "index.twig" at line 5.