added a way to add custom escaping strategies
authorFabien Potencier <fabien.potencier@gmail.com>
Wed, 11 Sep 2013 17:30:05 +0000 (19:30 +0200)
committerFabien Potencier <fabien.potencier@gmail.com>
Wed, 11 Sep 2013 18:26:15 +0000 (20:26 +0200)
CHANGELOG
doc/filters/escape.rst
lib/Twig/Extension/Core.php
test/Twig/Tests/Extension/CoreTest.php

index 8bdc136..44534ef 100644 (file)
--- 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
index 5ade7d7..ad441de 100644 (file)
@@ -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
 ---------
 
index 7eb7f9b..dac7f1e 100644 (file)
@@ -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));
     }
 }
 
index 5743e34..5f3da18 100644 (file)
@@ -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;
 }