From 55f8b27e1246ea6da24c5a943cb92c68f4ddd673 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 11 Sep 2013 19:30:05 +0200 Subject: [PATCH] added a way to add custom escaping strategies --- CHANGELOG | 1 + doc/filters/escape.rst | 23 ++++++++++++++++++++ lib/Twig/Extension/Core.php | 36 +++++++++++++++++++++++++++++++- test/Twig/Tests/Extension/CoreTest.php | 21 ++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8bdc136..44534ef 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 1.14.0 (2013-XX-XX) + * added a way to add custom escaping strategies * fixed the C extension compilation on Windows * fixed the batch filter when using a fill argument with an exact match of elements to batch * fixed the filesystem loader cache when a template name exists in several namespaces diff --git a/doc/filters/escape.rst b/doc/filters/escape.rst index 5ade7d7..ad441de 100644 --- a/doc/filters/escape.rst +++ b/doc/filters/escape.rst @@ -5,6 +5,9 @@ The ``css``, ``url``, and ``html_attr`` strategies were added in Twig 1.9.0. +.. versionadded:: 1.14.0 + The ability to define custom escapers was added in Twig 1.14.0. + The ``escape`` filter escapes a string for safe insertion into the final output. It supports different escaping strategies depending on the template context. @@ -84,6 +87,26 @@ The ``escape`` filter supports the following escaping strategies: {{ var|escape(strategy)|raw }} {# won't be double-escaped #} {% endautoescape %} +Custom Escapers +--------------- + +You can define custom escapers by calling the ``setEscaper()`` method on the +``core`` 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: + +.. code-block:: php + + $twig = new Twig_Environment($loader); + $twig->getExtension('core')->setEscaper('csv', 'csv_escaper')); + +When called by Twig, the callable receives the Twig environment instance, the +string to escape, and the charset. + +.. note:: + + Built-in escapers cannot be overridden mainly they should be considered as + the final implementation and also for better performance. + Arguments --------- diff --git a/lib/Twig/Extension/Core.php b/lib/Twig/Extension/Core.php index 7eb7f9b..dac7f1e 100644 --- a/lib/Twig/Extension/Core.php +++ b/lib/Twig/Extension/Core.php @@ -17,6 +17,28 @@ class Twig_Extension_Core extends Twig_Extension protected $dateFormats = array('F j, Y H:i', '%d days'); protected $numberFormat = array(0, '.', ','); protected $timezone = null; + protected $escapers = array(); + + /** + * 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 $callable A valid PHP callable + */ + public function setEscaper($strategy, $callable) + { + $this->escapers[$strategy] = $callable; + } + + /** + * Gets all defined escapers. + * + * @return array An array of escapers + */ + public function getEscapers() + { + return $this->escapers; + } /** * Sets the default format to be used by the date filter. @@ -966,7 +988,19 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', return rawurlencode($string); default: - throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: html, js, url, css, and html_attr).', $strategy)); + static $escapers; + + if (null === $escapers) { + $escapers = $env->getExtension('core')->getEscapers(); + } + + if (isset($escapers[$strategy])) { + return call_user_func($escapers[$strategy], $env, $string, $charset); + } + + $validStrategies = implode(', ', array_merge(array('html', 'js', 'url', 'css', 'html_attr'), array_keys($escapers))); + + throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies)); } } diff --git a/test/Twig/Tests/Extension/CoreTest.php b/test/Twig/Tests/Extension/CoreTest.php index 5743e34..5f3da18 100644 --- a/test/Twig/Tests/Extension/CoreTest.php +++ b/test/Twig/Tests/Extension/CoreTest.php @@ -114,4 +114,25 @@ class Twig_Tests_Extension_CoreTest extends PHPUnit_Framework_TestCase $this->assertEquals($output, 'éÄ'); } + + public function testCustomEscaper() + { + $twig = new Twig_Environment(); + $twig->getExtension('core')->setEscaper('foo', 'foo_escaper_for_test'); + + $this->assertEquals('fooUTF-8', twig_escape_filter($twig, 'foo', 'foo')); + } + + /** + * @expectedException Twig_Error_Runtime + */ + public function testUnknownCustomEscaper() + { + twig_escape_filter(new Twig_Environment(), 'foo', 'bar'); + } +} + +function foo_escaper_for_test(Twig_Environment $env, $string, $charset) +{ + return $string.$charset; } -- 1.7.2.5