'even' => new Twig_Filter_Function('twig_is_even_filter'),
'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)),
- * changed the automatic-escaping rules to be more sensible (the documentation lists all the rules)
+ * changed the automatic-escaping rules to be more sensible and more configurable in custom filters (the documentation lists all the rules)
* improved the filter system to allow object methods to be used as filters
* changed the Array and String loaders to actually make use of the cache mechanism
* included the default filter function definitions in the extension class files directly (Core, Escaper)
{{ var|foo(bar) }} {# bar will be escaped #}
{{ var|foo(bar|safe) }} {# bar won't be escaped #}
+ * Automatic escaping is not applied if one of the filter in the chain has the
+ `is_escaper` option set to `true` (this is the case for the built-in
+ `escaper`, `safe`, and `urlencode` filters for instance).
+
### Sandbox Extension
The `sandbox` extension can be used to evaluate untrusted code. Access to
}
}
-The `Twig_Filter` classes take flags as their last argument. For instance, if
-you want access to the current environment instance in your filter, set the
-`needs_environment` option to `true`:
-
- [php]
- $filter = new Twig_Filter_Function('str_rot13', array('needs_environment' => true));
-
-Twig will then pass the current environment as the first argument to the
-filter call:
-
- [php]
- function twig_compute_rot13(Twig_Environment $env, $string)
- {
- // get the current charset for instance
- $charset = $env->getCharset();
-
- return str_rot13($string);
- }
-
Parameters passed to the filter are available as extra arguments to the
function call:
-
[php]
- function twig_compute_rot13(Twig_Environment $env, $string, $prefix = '')
+ function twig_compute_rot13($string, $prefix = '')
{
- // get the current charset for instance
- $charset = $env->getCharset();
-
return $prefix.str_rot13($string);
}
polluting the global namespace. This also gives the developer more flexibility
at the cost of a small overhead.
+### Environment aware Filters
+
+The `Twig_Filter` classes take options as their last argument. For instance, if
+you want access to the current environment instance in your filter, set the
+`needs_environment` option to `true`:
+
+ [php]
+ $filter = new Twig_Filter_Function('str_rot13', array('needs_environment' => true));
+
+Twig will then pass the current environment as the first argument to the
+filter call:
+
+ [php]
+ function twig_compute_rot13(Twig_Environment $env, $string)
+ {
+ // get the current charset for instance
+ $charset = $env->getCharset();
+
+ return str_rot13($string);
+ }
+
+### Automatic Escaping
+
+If automatic escaping is enabled, the main value passed to the filters is
+automatically escaped. If your filter acts as an escaper, you will want the
+raw variable value. In such a case, set the `is_escaper` option to `true`:
+
+ [php]
+ $filter = new Twig_Filter_Function('urlencode', array('is_escaper' => true));
+
+>**NOTE**
+>The parameters passed as extra arguments to the filters are not affected by
+>the `is_escaper` option and they are always escaped according to the
+>automatic escaping rules.
+
Overriding default Filters
--------------------------
'floor' => new Twig_Filter_Function('twig_floor_filter'),
// encoding
- 'urlencode' => new Twig_Filter_Function('twig_urlencode_filter'),
+ 'urlencode' => new Twig_Filter_Function('twig_urlencode_filter', array('is_escaper' => true)),
// string filters
'title' => new Twig_Filter_Function('twig_title_string_filter', array('needs_environment' => true)),
'items' => new Twig_Filter_Function('twig_get_array_items_filter'),
// escaping
- 'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)),
- 'e' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)),
+ 'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_escaper' => true)),
+ 'e' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_escaper' => true)),
);
if (function_exists('mb_get_info'))
public function getFilters()
{
return array(
- 'safe' => new Twig_Filter_Function('twig_safe_filter'),
+ 'safe' => new Twig_Filter_Function('twig_safe_filter', array('is_escaper' => true)),
);
}
{
$this->options = array_merge(array(
'needs_environment' => false,
+ 'is_escaper' => false,
), $options);
}
{
return $this->options['needs_environment'];
}
+
+ public function isEscaper()
+ {
+ return $this->options['is_escaper'];
+ }
}
if ($expression instanceof Twig_Node_Expression_Filter)
{
- // don't escape if escape has already been called
- // or if we want the safe string
- if ($expression->hasFilter('escape') || $expression->hasFilter('safe'))
- {
- return $node;
- }
-
// don't escape if the primary node of the filter is not a variable
$nodes = $expression->getNodes();
if (!$nodes[0] instanceof Twig_Node_Expression_Name)
{
return $node;
}
+
+ // don't escape if there is already an "escaper" in the filter chain
+ $filterMap = $this->env->getFilters();
+ foreach ($expression->getFilters() as $filter)
+ {
+ if (isset($filterMap[$filter[0]]) && $filterMap[$filter[0]]->isEscaper())
+ {
+ return $node;
+ }
+ }
}
elseif (!$expression instanceof Twig_Node_Expression_Name)
{