Added an option to mark filters as preserving the safeness
authorChristophe Coevoet <stof@notk.org>
Fri, 20 Apr 2012 14:23:51 +0000 (16:23 +0200)
committerChristophe Coevoet <stof@notk.org>
Fri, 20 Apr 2012 14:23:51 +0000 (16:23 +0200)
Closes #678

CHANGELOG
lib/Twig/Filter.php
lib/Twig/FilterInterface.php
lib/Twig/NodeVisitor/SafeAnalysis.php
test/Twig/Tests/Fixtures/tags/autoescape/with_preserve_safety_filters.test [new file with mode: 0644]
test/Twig/Tests/integrationTest.php

index 1613419..3d31a12 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,6 @@
 * 1.7.0 (2012-XX-XX)
 
+ * added the preserve_safety option for filters
  * fixed a PHP notice when trying to access a key on a non-object/array variable
  * enhanced error reporting when the template file is an instance of SplFileInfo
  * added Twig_Environment::mergeGlobals()
index f27f08e..b5e400d 100644 (file)
@@ -26,6 +26,7 @@ abstract class Twig_Filter implements Twig_FilterInterface
             'needs_environment' => false,
             'needs_context'     => false,
             'pre_escape'        => null,
+            'preserve_safety' => null,
         ), $options);
     }
 
@@ -59,7 +60,12 @@ abstract class Twig_Filter implements Twig_FilterInterface
             return call_user_func($this->options['is_safe_callback'], $filterArgs);
         }
 
-        return array();
+        return null;
+    }
+
+    public function getPreserveSafety()
+    {
+        return $this->options['preserve_safety'];
     }
 
     public function getPreEscape()
index 866e932..20a29e5 100644 (file)
@@ -30,6 +30,8 @@ interface Twig_FilterInterface
 
     function getSafe(Twig_Node $filterArgs);
 
+    function getPreserveSafety();
+
     function getPreEscape();
 
     function setArguments($arguments);
index 89d8794..c3fc9d3 100644 (file)
@@ -61,7 +61,11 @@ class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
             $name = $node->getNode('filter')->getAttribute('value');
             $args = $node->getNode('arguments');
             if (false !== $filter = $env->getFilter($name)) {
-                $this->setSafe($node, $filter->getSafe($args));
+                $safe = $filter->getSafe($args);
+                if (null === $safe) {
+                    $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreserveSafety());
+                }
+                $this->setSafe($node, $safe);
             } else {
                 $this->setSafe($node, array());
             }
diff --git a/test/Twig/Tests/Fixtures/tags/autoescape/with_preserve_safety_filters.test b/test/Twig/Tests/Fixtures/tags/autoescape/with_preserve_safety_filters.test
new file mode 100644 (file)
index 0000000..cedd1bc
--- /dev/null
@@ -0,0 +1,50 @@
+--TEST--
+"autoescape" tag handles filters preserving the safety
+--TEMPLATE--
+{% autoescape true %}
+
+(preserve_safety is preserving safety for "html")
+
+1. Unsafe values are still unsafe
+( var|preserve_safety|escape )
+{{ var|preserve_safety }}
+
+2. Safe values are still safe
+( var|escape|preserve_safety )
+{{ var|escape|preserve_safety }}
+
+3. Re-escape values that are escaped for an other contexts
+( var|escape_something|preserve_safety|escape )
+{{ var|escape_something|preserve_safety }}
+
+4. Still escape when using filters not declared safe
+( var|escape|preserve_safety|replace({'FABIEN': 'FABPOT'})|escape )
+{{ var|escape|preserve_safety|replace({'FABIEN': 'FABPOT'}) }}
+
+{% endautoescape %}
+--DATA--
+return array('var' => "<Fabien>\nTwig")
+--EXPECT--
+
+(preserve_safety is preserving safety for "html")
+
+1. Unsafe values are still unsafe
+( var|preserve_safety|escape )
+&lt;FABIEN&gt;
+TWIG
+
+2. Safe values are still safe
+( var|escape|preserve_safety )
+&LT;FABIEN&GT;
+TWIG
+
+3. Re-escape values that are escaped for an other contexts
+( var|escape_something|preserve_safety|escape )
+&lt;FABIEN&gt;
+TWIG
+
+4. Still escape when using filters not declared safe
+( var|escape|preserve_safety|replace({'FABIEN': 'FABPOT'})|escape )
+&amp;LT;FABPOT&amp;GT;
+TWIG
+
index 866e86c..b716b86 100644 (file)
@@ -238,6 +238,7 @@ class TestExtension extends Twig_Extension
             'escape_and_nl2br' => new Twig_Filter_Method($this, 'escape_and_nl2br', array('needs_environment' => true, 'is_safe' => array('html'))),
             'nl2br'            => new Twig_Filter_Method($this, 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
             'escape_something' => new Twig_Filter_Method($this, 'escape_something', array('is_safe' => array('something'))),
+            'preserve_safety' => new Twig_Filter_Method($this, 'preserve_safety', array('preserve_safety' => array('html'))),
             '*_path'           => new Twig_Filter_Method($this, 'dynamic_path'),
             '*_foo_*_bar'      => new Twig_Filter_Method($this, 'dynamic_foo'),
         );
@@ -297,6 +298,11 @@ class TestExtension extends Twig_Extension
         return strtoupper($value);
     }
 
+    public function preserve_safety($value)
+    {
+        return strtoupper($value);
+    }
+
     public function br()
     {
         return '<br />';