Skip to content

Commit

Permalink
bug #4091 Fix old escaper signature + add docs (fabpot)
Browse files Browse the repository at this point in the history
This PR was merged into the 3.x branch.

Discussion
----------

Fix old escaper signature + add docs

Closes #4087
Closes #4088

Commits
-------

04b1ad3 Fix old escaper signature + add docs
  • Loading branch information
fabpot committed May 14, 2024
2 parents 0bdc73a + 04b1ad3 commit f553f16
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 29 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 3.10.2 (2024-XX-XX)

* n/a
* Fix support for the deprecated escaper signature

# 3.10.1 (2024-05-12)

Expand Down
29 changes: 24 additions & 5 deletions doc/filters/escape.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,34 @@ to learn more about this topic.
Custom Escapers
---------------

.. versionadded:: 3.10

The ``EscaperRuntime`` class has been added in 3.10. On previous versions,
you can define custom escapers by calling the ``setEscaper()`` method on
the escaper extension instance. The first argument is the escaper strategy
(to be used in the ``escape`` call) and the second one must be a valid PHP
callable::

use Twig\Extension\EscaperExtension;

$twig = new \Twig\Environment($loader);
$twig->getExtension(EscaperExtension::class)->setEscaper('csv', 'csv_escaper');

When called by Twig, the callable receives the Twig environment instance,
the string to escape, and the charset.

You can define custom escapers by calling the ``setEscaper()`` method on the
escaper extension instance. The first argument is the escaper name (to be
used in the ``escape`` call) and the second one must be a valid PHP callable::
escaper runtime instance. It accepts two arguments: the strategy name and a PHP
callable that accepts a string to escape and the charset::

use Twig\Runtime\EscaperRuntime;

$twig = new \Twig\Environment($loader);
$twig->getExtension(\Twig\Extension\EscaperExtension::class)->setEscaper('csv', 'csv_escaper');
$escaper = fn ($string, $charset) => $string;
$twig->getRuntime(EscaperRuntime::class)->setEscaper('identity', $escaper);

When called by Twig, the callable receives the Twig environment instance, the
string to escape, and the charset.
# Usage in a template:
# {{ 'foo'|escape('identity') }}

.. note::

Expand Down
7 changes: 5 additions & 2 deletions doc/internals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,12 @@ using)::
{
protected function doDisplay(array $context, array $blocks = [])
{
$macros = $this->macros;
// line 1
echo "Hello ";
echo twig_escape_filter($this->env, (isset($context["name"]) ? $context["name"] : null), "html", null, true);
yield "Hello ";
// line 2
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["name"]) || array_key_exists("name", $context) ? $context["name"] : (function () { throw new RuntimeError('Variable "name" does not exist.', 2, $this->source); })()), "html", null, true);
return; yield '';
}

// some more code
Expand Down
8 changes: 4 additions & 4 deletions src/Extension/EscaperExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ public function getDefaultStrategy(string $name)
/**
* Defines a new escaper to be used via the escape filter.
*
* @param string $strategy The strategy name that should be used as a strategy in the escape call
* @param callable(Environment, string) $callable A valid PHP callable
* @param string $strategy The strategy name that should be used as a strategy in the escape call
* @param callable(Environment, string, string) $callable A valid PHP callable
*
* @deprecated since Twig 3.10
*/
Expand All @@ -132,7 +132,7 @@ public function setEscaper($strategy, callable $callable)

$this->escapers[$strategy] = $callable;
$callable = function ($string, $charset) use ($callable) {
return $callable($this->environment, $string);
return $callable($this->environment, $string, $charset);
};

$this->escaper->setEscaper($strategy, $callable);
Expand All @@ -141,7 +141,7 @@ public function setEscaper($strategy, callable $callable)
/**
* Gets all defined escapers.
*
* @return array<callable(Environment, string)> An array of escapers
* @return array<callable(Environment, string, string)> An array of escapers
*
* @deprecated since Twig 3.10
*/
Expand Down
22 changes: 11 additions & 11 deletions tests/Extension/EscaperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ public function testCustomEscaper($expected, $string, $strategy)
$twig = new Environment($this->createMock(LoaderInterface::class));
$escaperExt = $twig->getExtension(EscaperExtension::class);
$escaperExt->setEscaper('foo', 'Twig\Tests\legacy_escaper');
$this->assertSame($expected, $twig->getRuntime(EscaperRuntime::class)->escape($string, $strategy));
$this->assertSame($expected, $twig->getRuntime(EscaperRuntime::class)->escape($string, $strategy, 'ISO-8859-1'));
}

public function provideCustomEscaperCases()
{
return [
['fooUTF-8', 'foo', 'foo'],
['UTF-8', null, 'foo'],
['42UTF-8', 42, 'foo'],
['foo**ISO-8859-1**UTF-8', 'foo', 'foo'],
['**ISO-8859-1**UTF-8', null, 'foo'],
['42**ISO-8859-1**UTF-8', 42, 'foo'],
];
}

Expand All @@ -51,7 +51,7 @@ public function testCustomEscaperWithoutCallingSetEscaperRuntime($expected, $str
$twig = new Environment($this->createMock(LoaderInterface::class));
$escaperExt = $twig->getExtension(EscaperExtension::class);
$escaperExt->setEscaper('foo', 'Twig\Tests\legacy_escaper');
$this->assertSame($expected, $twig->getRuntime(EscaperRuntime::class)->escape($string, $strategy));
$this->assertSame($expected, $twig->getRuntime(EscaperRuntime::class)->escape($string, $strategy, 'ISO-8859-1'));
}

/**
Expand All @@ -67,17 +67,17 @@ public function testCustomEscapersOnMultipleEnvs()
$escaperExt2 = $env2->getExtension(EscaperExtension::class);
$escaperExt2->setEscaper('foo', 'Twig\Tests\legacy_escaper_again');

$this->assertSame('fooUTF-8', $env1->getRuntime(EscaperRuntime::class)->escape('foo', 'foo'));
$this->assertSame('fooUTF-81', $env2->getRuntime(EscaperRuntime::class)->escape('foo', 'foo'));
$this->assertSame('foo**ISO-8859-1**UTF-8', $env1->getRuntime(EscaperRuntime::class)->escape('foo', 'foo', 'ISO-8859-1'));
$this->assertSame('foo**ISO-8859-1**UTF-8**again', $env2->getRuntime(EscaperRuntime::class)->escape('foo', 'foo', 'ISO-8859-1'));
}
}

function legacy_escaper(Environment $twig, $string)
function legacy_escaper(Environment $twig, $string, $charset)
{
return $string.$twig->getCharset();
return $string.'**'.$charset.'**'.$twig->getCharset();
}

function legacy_escaper_again(Environment $twig, $string)
function legacy_escaper_again(Environment $twig, $string, $charset)
{
return $string.$twig->getCharset().'1';
return $string.'**'.$charset.'**'.$twig->getCharset().'**again';
}
12 changes: 6 additions & 6 deletions tests/Runtime/EscaperRuntimeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -350,19 +350,19 @@ public function testUnknownCustomEscaper()
/**
* @dataProvider provideCustomEscaperCases
*/
public function testCustomEscaper($expected, $string, $strategy)
public function testCustomEscaper($expected, $string, $strategy, $charset)
{
$escaper = new EscaperRuntime();
$escaper->setEscaper('foo', 'Twig\Tests\escaper');
$this->assertSame($expected, $escaper->escape($string, $strategy));
$this->assertSame($expected, $escaper->escape($string, $strategy, $charset));
}

public function provideCustomEscaperCases()
{
return [
['fooUTF-8', 'foo', 'foo'],
['UTF-8', null, 'foo'],
['42UTF-8', 42, 'foo'],
['foo**ISO-8859-1', 'foo', 'foo', 'ISO-8859-1'],
['**ISO-8859-1', null, 'foo', 'ISO-8859-1'],
['42**UTF-8', 42, 'foo', null],
];
}

Expand Down Expand Up @@ -391,7 +391,7 @@ public function provideObjectsForEscaping()

function escaper($string, $charset)
{
return $string.$charset;
return $string.'**'.$charset;
}

interface Extension_SafeHtmlInterface
Expand Down

0 comments on commit f553f16

Please sign in to comment.