* 1.4.0
+ * added Twig_Filter_Node to allow more complex filters to have their own Node class
* added Twig_Test_Node to allow more complex tests to have their own Node class
* added a better error message when a template is empty but contain a BOM
- * fixed in operator for empty strings
+ * fixed "in" operator for empty strings
* fixed the "defined" test and the "default" filter (now works with more than one call (foo.bar.foo) and for both values of the strict_variables option)
* changed the way extensions are loaded (addFilter/addFunction/addGlobal/addTest/addNodeVisitor/addTokenParser/addExtension can now be called in any order)
* added Twig_Environment::display()
$arguments = $this->parseArguments();
}
- $node = new Twig_Node_Expression_Filter($node, $name, $arguments, $token->getLine(), $tag);
-
- if (Twig_Node_Expression_DefaultFilter::isDefaultFilter($node)) {
- $node = new Twig_Node_Expression_DefaultFilter($node);
+ $filterMap = $this->parser->getEnvironment()->getFilters();
+ if (isset($filterMap[$name->getAttribute('value')]) && $filterMap[$name->getAttribute('value')] instanceof Twig_Filter_Node) {
+ $class = $filterMap[$name->getAttribute('value')]->getClass();
+ } else {
+ $class = 'Twig_Node_Expression_Filter';
}
+ $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
+
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
break;
}
'merge' => new Twig_Filter_Function('twig_array_merge'),
// iteration and runtime
- 'default' => new Twig_Filter_Function('twig_default_filter'),
+ 'default' => new Twig_Filter_Node('Twig_Node_Expression_Filter_Default'),
+ '_default' => new Twig_Filter_Function('_twig_default_filter'),
+
'keys' => new Twig_Filter_Function('twig_get_array_keys_filter'),
// escaping
return implode($glue, (array) $value);
}
-/**
- * Returns the value or the default value when it is undefined or empty.
- *
- * <pre>
- *
- * {{ var.foo|default('foo item on var is not defined') }}
- *
- * </pre>
- *
- * @param mixed $value A value
- * @param mixed $default The default value
- *
- * @param mixed The value or the default value;
- */
-function twig_default_filter($value, $default = '')
+// The '_default' filter is used internally to avoid using the ternary operator
+// which costs a lot for big contexts (before PHP 5.4). So, on average,
+// a function call is cheaper.
+function _twig_default_filter($value, $default = '')
{
if (twig_test_empty($value)) {
return $default;
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2011 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Represents a template filter as a node.
+ *
+ * @package twig
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Twig_Filter_Node extends Twig_Filter
+{
+ protected $class;
+
+ public function __construct($class, array $options = array())
+ {
+ parent::__construct($options);
+
+ $this->class = $class;
+ }
+
+ public function getClass()
+ {
+ return $this->class;
+ }
+
+ public function compile()
+ {
+ }
+}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2011 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Node_Expression_DefaultFilter extends Twig_Node_Expression
-{
- public function __construct(Twig_Node_Expression_Filter $node)
- {
- if (!self::isDefaultFilter($node)) {
- throw new Twig_Error('The default filter node cannot be created from the given node.', $node->getLine());
- }
-
- $test = new Twig_Node_Expression_Test_Defined(clone $node->getNode('node'), 'defined', new Twig_Node(), $node->getLine());
- $default = count($node->getNode('arguments')) ? $node->getNode('arguments')->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
-
- $node = new Twig_Node_Expression_Conditional($test, $node, $default, $node->getLine());
-
- parent::__construct(array('node' => $node), array(), $node->getLine());
- }
-
- public function compile(Twig_Compiler $compiler)
- {
- $compiler->subcompile($this->getNode('node'));
- }
-
- /**
- * Checks whether a node is a default filter that needs to be wrapped with Twig_Node_Expression_DefaultFilter.
- *
- * The default filter needs to be wrapped with an instance of Twig_Node_Expression_DefaultFilter
- * when the filtered value is a name (like obj) or an attribute (like obj.attr).
- *
- * In such a case, it's compiled to {{ obj is defined ? obj|default('bar') : 'bar' }}
- *
- * @param Twig_NodeInterface $node A Twig_NodeInterface instance
- *
- * @return Boolean true if the node must be wrapped with a Twig_Node_Expression_DefaultFilter, false otherwise
- */
- static public function isDefaultFilter(Twig_NodeInterface $node)
- {
- return $node instanceof Twig_Node_Expression_Filter && 'default' === $node->getNode('filter')->getAttribute('value') && ($node->getNode('node') instanceof Twig_Node_Expression_Name || $node->getNode('node') instanceof Twig_Node_Expression_GetAttr);
- }
-}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2011 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Returns the value or the default value when it is undefined or empty.
+ *
+ * <pre>
+ * {{ var.foo|default('foo item on var is not defined') }}
+ * </pre>
+ *
+ * @package twig
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
+{
+ public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
+ {
+ $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('_default', $node->getLine()), $arguments, $node->getLine());
+
+ if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
+ $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine());
+ $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
+
+ $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine());
+ } else {
+ $node = $default;
+ }
+
+ parent::__construct($node, $filterName, $arguments, $lineno, $tag);
+ }
+
+ public function compile(Twig_Compiler $compiler)
+ {
+ $compiler->subcompile($this->getNode('node'));
+ }
+}