* 0.9.7-DEV
Backward incompatibilities:
- * The short notation of the `block` tag changed.
-
+ * added a 'as' string to the block tag short notation ({% block title "Title" %} must now be {% block title as "Title" %})
+ * removed the sandboxed attribute of the include tag (use the new sandbox tag instead)
+ * refactored the Node system (if you have custom nodes, you will have to update them to use the new API)
+
+ * removed the Twig_Resource::resolveMissingFilter() method
+ * fixed the filter tag which did not apply filtering to included files
+ * added a bunch of unit tests
+ * added a bunch of phpdoc
+ * added a sandbox tag in the sandbox extension
* fixed iterator_to_array() usage
* changed the date filter to support any date format supported by DateTime
* added strict_variable setting to throw an exception when an invalid variable is used in a template (disabled by default when debug is false)
* added three interfaces: Twig_NodeInterface, Twig_TokenParserInterface, and Twig_FilterInterface
* changed the generated code to match the new coding standards
* fixed sandbox mode (__toString() method check was not enforced if called implicitly from a simple statement like {{ article }})
- * added a 'as' string to the block tag short notation ({% block title "Title" %} must now be {% block title as "Title" %})
* added an exception when a child template has a non-empty body (as it is always ignored when rendering)
* 0.9.6 (2010-05-12)
Included templates have access to the variables of the active context.
-An included file can be evaluated in the sandbox environment by appending
-`sandboxed` at the end if the `escaper` extension has been enabled:
-
- [twig]
- {% include 'user.html' sandboxed %}
-
You can also restrict the variables passed to the template by explicitly pass
them as an array:
{% set vars as ['foo': 'bar'] %}
{% include 'foo' with vars %}
-The most secure way to include a template is to use both the `sandboxed` mode,
-and to pass the minimum amount of variables needed for the template to be
-rendered correctly:
-
- [twig]
- {% include 'foo' sandboxed with vars %}
-
>**NOTE**
>The `with` keyword is supported as of Twig 0.9.5.
+-
+
+>**TIP**
+>When including a template created by an end user, you should consider
+>sandboxing it. More information in the "Twig for Developers" chapter.
+
### Import
Twig supports putting often used code into macros. These macros can go into
$twig->addExtension($sandbox);
By default, the sandbox mode is disabled and should be enabled when including
-untrusted templates:
+untrusted template code by using the `sandbox` tag:
- [php]
- {% include "user.html" sandboxed %}
+ [twig]
+ {% sandbox %}
+ {% include 'user.html' %}
+ {% endsandbox %}
You can sandbox all templates by passing `true` as the second argument of the
extension constructor:
[php]
class Project_Set_Node extends Twig_Node
{
- protected $name;
- protected $value;
-
public function __construct($name, Twig_Node_Expression $value, $lineno)
{
- parent::__construct($lineno);
-
- $this->name = $name;
- $this->value = $value;
+ parent::__construct(array('value' => $value), array('name' => $name), $lineno);
}
public function compile($compiler)
{
$compiler
->addDebugInfo($this)
- ->write('$context[\''.$this->name.'\'] = ')
+ ->write('$context[\''.$this['name'].'\'] = ')
->subcompile($this->value)
->raw(";\n")
;
* `outdent()`: Outdents the generated code (see `Twig_Node_Block` for a usage
example).
-Creating a Node Transformer
----------------------------
+Creating a Node Visitor
+-----------------------
To be written...
static public function autoload($class)
{
if (0 !== strpos($class, 'Twig')) {
- return false;
+ return;
}
require dirname(__FILE__).'/../'.str_replace('_', '/', $class).'.php';
-
- return true;
}
}
}
/**
+ * Returns the environment instance related to this compiler.
+ *
+ * @return Twig_Environment The environment instance
+ */
+ public function getEnvironment()
+ {
+ return $this->env;
+ }
+
+ /**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
return $this;
}
-
- /**
- * Returns the environment instance related to this compiler.
- *
- * @return Twig_Environment The environment instance
- */
- public function getEnvironment()
- {
- return $this->env;
- }
-
- public function getTemplateClass($name)
- {
- return $this->getEnvironment()->getTemplateClass($name);
- }
}
/**
* Loads a template by name.
*
- * @param string $name The template name
+ * @param string $name The template name
+ * @param Boolean $macro Whether to return the macro object if any, or the template one
*
* @return Twig_TemplateInterface A template instance representing the given template name
*/
- public function loadTemplate($name)
+ public function loadTemplate($name, $macro = false)
{
- $cls = $this->getTemplateClass($name);
+ $cls = $this->getTemplateClass($name).($macro ? '_Macro' : '');
if (isset($this->loadedTemplates[$cls])) {
return $this->loadedTemplates[$cls];
public function getExtension($name)
{
+ if (!isset($this->extensions[$name])) {
+ throw new LogicException(sprintf('The "%s" extension is not enabled.', $name));
+ }
+
return $this->extensions[$name];
}
||
$this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'in')
) {
- $ops[] = array($this->parser->getStream()->next()->getValue(), $this->parseAddExpression());
+ $ops[] = new Twig_Node_Expression_Constant($this->parser->getStream()->next()->getValue(), $lineno);
+ $ops[] = $this->parseAddExpression();
}
if (empty($ops)) {
return $expr;
}
- return new Twig_Node_Expression_Compare($expr, $ops, $lineno);
+ return new Twig_Node_Expression_Compare($expr, new Twig_Node($ops), $lineno);
}
public function parseAddExpression()
throw new Twig_SyntaxError(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::getTypeAsString($token->getType()), $token->getValue()), $token->getLine());
}
}
+
if (!$assignment) {
$node = $this->parsePostfixExpression($node);
}
$end = $this->parseExpression();
- return new Twig_Node_Expression_Filter($node, array(array('range', array($end))), $lineno);
+ $filters = new Twig_Node(array(new Twig_Node_Expression_Constant('range', $lineno), new Twig_Node(array($end))));
+
+ return new Twig_Node_Expression_Filter($node, $filters, $lineno);
}
public function parseSubscriptExpression($node)
{
$token = $this->parser->getStream()->next();
$lineno = $token->getLine();
- $arguments = array();
+ $arguments = new Twig_Node();
if ($token->getValue() == '.') {
$token = $this->parser->getStream()->next();
if ($token->getType() == Twig_Token::NAME_TYPE || $token->getType() == Twig_Token::NUMBER_TYPE) {
while (true) {
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
- $filters[] = array($token->getValue(), $this->parseArguments());
+ $filters[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
+ $filters[] = $this->parseArguments();
if (!$this->parser->getStream()->test(Twig_Token::OPERATOR_TYPE, '|')) {
break;
$this->parser->getStream()->next();
}
- return $filters;
+ return new Twig_Node($filters);
}
public function parseArguments()
{
if (!$this->parser->getStream()->test(Twig_Token::OPERATOR_TYPE, '(')) {
- return array();
+ return new Twig_Node();
}
$args = array();
}
$this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, ')');
- return $args;
+ return new Twig_Node($args);
}
public function parseAssignmentExpression()
{
$lineno = $this->parser->getCurrentToken()->getLine();
$targets = array();
- $is_multitarget = false;
while (true) {
if (!empty($targets)) {
$this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, ',');
if (!$this->parser->getStream()->test(Twig_Token::OPERATOR_TYPE, ',')) {
break;
}
- $is_multitarget = true;
- }
- if (!$is_multitarget && count($targets) == 1) {
- return array(false, $targets[0]);
}
- return array(true, $targets);
+ return new Twig_Node($targets);
}
public function parseMultitargetExpression()
}
$is_multitarget = true;
}
- if (!$is_multitarget && count($targets) == 1) {
- return array(false, $targets[0]);
- }
- return array(true, $targets);
+ return array($is_multitarget, new Twig_Node($targets));
}
}
}
/**
- * Returns the node visitor instances to add to the existing list.
- *
- * @return array An array of Twig_NodeVisitorInterface instances
- */
- public function getNodeVisitors()
- {
- return array(new Twig_NodeVisitor_Filter());
- }
-
- /**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
}
/**
+ * Returns the token parser instance to add to the existing list.
+ *
+ * @return array An array of Twig_TokenParser instances
+ */
+ public function getTokenParsers()
+ {
+ return array(new Twig_TokenParser_Sandbox());
+ }
+
+ /**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-abstract class Twig_Node implements Twig_NodeInterface
+class Twig_Node implements Twig_NodeInterface, ArrayAccess, Countable, Iterator
{
+ protected $nodes;
+ protected $attributes;
protected $lineno;
protected $tag;
- public function __construct($lineno, $tag = null)
+ public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
{
+ $this->nodes = array();
+ foreach ($nodes as $name => $node) {
+ $this->$name = $node;
+ }
+ $this->attributes = $attributes;
$this->lineno = $lineno;
$this->tag = $tag;
}
public function __toString()
{
- return get_class($this).'()';
+ $attributes = array();
+ foreach ($this->attributes as $name => $value) {
+ $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
+ }
+
+ $repr = array(get_class($this).'('.implode(', ', $attributes));
+
+ if (count($this->nodes)) {
+ foreach ($this->nodes as $name => $node) {
+ $len = strlen($name) + 4;
+ $noderepr = array();
+ foreach (explode("\n", (string) $node) as $line) {
+ $noderepr[] = str_repeat(' ', $len).$line;
+ }
+
+ $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
+ }
+
+ $repr[] = ')';
+ } else {
+ $repr[0] .= ')';
+ }
+
+ return implode("\n", $repr);
+ }
+
+ public function compile($compiler)
+ {
+ foreach ($this->nodes as $node) {
+ $node->compile($compiler);
+ }
}
public function getLine()
{
return $this->tag;
}
+
+ /**
+ * Returns true if the attribute is defined.
+ *
+ * @param string The attribute name
+ *
+ * @return Boolean true if the attribute is defined, false otherwise
+ */
+ public function offsetExists($name)
+ {
+ return $this->attributes[$name];
+ }
+
+ /**
+ * Gets an attribute.
+ *
+ * @param string The attribute name
+ *
+ * @return mixed The attribute value
+ */
+ public function offsetGet($name)
+ {
+ if (!array_key_exists($name, $this->attributes)) {
+ throw new InvalidArgumentException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
+ }
+
+ return $this->attributes[$name];
+ }
+
+ /**
+ * Sets an attribute.
+ *
+ * @param string The attribute name
+ * @param mixed The attribute value
+ */
+ public function offsetSet($name, $value)
+ {
+ $this->attributes[$name] = $value;
+ }
+
+ /**
+ * Removes an attribute.
+ *
+ * @param string The attribute name
+ */
+ public function offsetUnset($name)
+ {
+ unset($this->attributes[$name]);
+ }
+
+ /**
+ * Returns true if the node with the given identifier exists.
+ *
+ * @param string The node name
+ *
+ * @return Boolean true if the node with the given name exists, false otherwise
+ */
+ public function __isset($name)
+ {
+ return array_key_exists($name, $this->nodes);
+ }
+
+ /**
+ * Gets a node by name.
+ *
+ * @param string The node name
+ *
+ * @return Twig_Node A Twig_Node instance
+ */
+ public function __get($name)
+ {
+ if (!array_key_exists($name, $this->nodes)) {
+ throw new InvalidArgumentException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
+ }
+
+ return $this->nodes[$name];
+ }
+
+ /**
+ * Sets a node.
+ *
+ * @param string The node name
+ * @param Twig_Node A Twig_Node instance
+ */
+ public function __set($name, $node = null)
+ {
+ $this->nodes[$name] = $node;
+ }
+
+ /**
+ * Removes a node by name.
+ *
+ * @param string The node name
+ */
+ public function __unset($name)
+ {
+ unset($this->nodes[$name]);
+ }
+
+ public function count()
+ {
+ return count($this->nodes);
+ }
+
+ public function rewind()
+ {
+ reset($this->nodes);
+ }
+
+ public function current()
+ {
+ return current($this->nodes);
+ }
+
+ public function key()
+ {
+ return key($this->nodes);
+ }
+
+ public function next()
+ {
+ return next($this->nodes);
+ }
+
+ public function valid()
+ {
+ return false !== current($this->nodes);
+ }
}
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_AutoEscape extends Twig_Node implements Twig_NodeListInterface
+class Twig_Node_AutoEscape extends Twig_Node
{
- protected $value;
- protected $body;
-
- public function __construct($value, Twig_NodeList $body, $lineno, $tag = null)
- {
- parent::__construct($lineno, $tag);
- $this->value = $value;
- $this->body = $body;
- }
-
- public function __toString()
- {
- $repr = array(get_class($this).'('.($this->value ? 'on' : 'off'));
- foreach (explode("\n", $this->body) as $line) {
- $repr[] = ' '.$line;
- }
- $repr[] = ')';
-
- return implode("\n", $repr);
- }
-
- public function getNodes()
- {
- return $this->body->getNodes();
- }
-
- public function setNodes(array $nodes)
+ public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
{
- $this->body = new Twig_NodeList($nodes, $this->lineno);
+ parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
}
public function compile($compiler)
{
$compiler->subcompile($this->body);
}
-
- public function getValue()
- {
- return $this->value;
- }
}
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_Block extends Twig_Node implements Twig_NodeListInterface
+class Twig_Node_Block extends Twig_Node
{
- protected $name;
- protected $body;
- protected $parent;
-
- public function __construct($name, Twig_NodeList $body, $lineno, $parent = null, $tag = null)
- {
- parent::__construct($lineno, $tag);
- $this->name = $name;
- $this->body = $body;
- $this->parent = $parent;
- }
-
- public function __toString()
- {
- $repr = array(get_class($this).' '.$this->name.'(');
- foreach ($this->body->getNodes() as $node) {
- foreach (explode("\n", $node->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
- }
- $repr[] = ')';
-
- return implode("\n", $repr);
- }
-
- public function getNodes()
- {
- return $this->body->getNodes();
- }
-
- public function setNodes(array $nodes)
+ public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
{
- $this->body = new Twig_NodeList($nodes, $this->lineno);
- }
-
- public function replace($other)
- {
- $this->body = $other->body;
+ parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
}
public function compile($compiler)
{
$compiler
->addDebugInfo($this)
- ->write(sprintf("public function block_%s(\$context)\n", $this->name), "{\n")
+ ->write(sprintf("public function block_%s(\$context)\n", $this['name']), "{\n")
->indent()
;
->write("}\n\n")
;
}
-
- public function getName()
- {
- return $this->name;
- }
-
- public function getParent()
- {
- return $this->parent;
- }
-
- public function setParent($parent)
- {
- $this->parent = $parent;
- }
}
*/
class Twig_Node_BlockReference extends Twig_Node
{
- protected $name;
-
public function __construct($name, $lineno, $tag = null)
{
- parent::__construct($lineno, $tag);
- $this->name = $name;
- }
-
- public function __toString()
- {
- return get_class($this).'('.$this->name.')';
+ parent::__construct(array(), array('name' => $name), $lineno, $tag);
}
public function compile($compiler)
{
$compiler
->addDebugInfo($this)
- ->write(sprintf('$this->block_%s($context);'."\n", $this->name))
+ ->write(sprintf('$this->block_%s($context);'."\n", $this['name']))
;
}
-
- public function getName()
- {
- return $this->name;
- }
}
<?php
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2010 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Represents a debug node.
+ *
+ * @package twig
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id$
+ */
class Twig_Node_Debug extends Twig_Node
{
- protected $expr;
-
public function __construct(Twig_Node_Expression $expr = null, $lineno, $tag = null)
{
- parent::__construct($lineno, $tag);
-
- $this->expr = $expr;
- }
-
- public function __toString()
- {
- return get_class($this).'('.$this->expr.')';
+ parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
}
public function compile($compiler)
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-class Twig_Node_Expression_Array extends Twig_Node_Expression implements Twig_NodeListInterface
+class Twig_Node_Expression_Array extends Twig_Node_Expression
{
- protected $elements;
-
- public function __construct($elements, $lineno)
+ public function __construct(array $elements, $lineno)
{
- parent::__construct($lineno);
-
- $this->elements = $elements;
- }
-
- public function __toString()
- {
- $repr = array(get_class($this).'(');
- foreach ($this->elements as $name => $node) {
- foreach (explode("\n", '\''.$name.'\' => '.$node) as $line) {
- $repr[] = ' '.$line;
- }
- }
- $repr[] = ')';
-
- return implode("\n", $repr);
- }
-
- public function getNodes()
- {
- return $this->elements;
- }
-
- public function setNodes(array $nodes)
- {
- $this->elements = $nodes;
+ parent::__construct($elements, array(), $lineno);
}
public function compile($compiler)
{
$compiler->raw('array(');
$first = true;
- foreach ($this->elements as $name => $node) {
+ foreach ($this->nodes as $name => $node) {
if (!$first) {
$compiler->raw(', ');
}
}
$compiler->raw(')');
}
-
- public function getElements()
- {
- return $this->elements;
- }
}
{
public function compile($compiler)
{
- $compiler->raw(sprintf('$context[\'%s\']', $this->name));
+ $compiler->raw(sprintf('$context[\'%s\']', $this['name']));
}
}
*/
abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
{
- protected $left;
- protected $right;
-
public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
{
- parent::__construct($lineno);
- $this->left = $left;
- $this->right = $right;
- }
-
- public function __toString()
- {
- $repr = array(get_class($this).'(');
-
- foreach (explode("\n", $this->left->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
-
- $repr[] = ', ';
-
- foreach (explode("\n", $this->right->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
-
- $repr[] = ')';
-
- return implode("\n", $repr);
+ parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
}
public function compile($compiler)
{
public function compile($compiler)
{
- $compiler
- ->raw('floor(')
- ->subcompile($this->left)
- ->raw(' / ')
- ->subcompile($this->right)
- ->raw(')')
- ;
+ $compiler->raw('floor(');
+ parent::compile($compiler);
+ $compiler->raw(')');
}
public function operator($compiler)
{
- return;
+ return $compiler->raw('/');
}
}
*/
class Twig_Node_Expression_Compare extends Twig_Node_Expression
{
- protected $expr;
- protected $ops;
-
- public function __construct(Twig_Node_Expression $expr, $ops, $lineno)
+ public function __construct(Twig_Node_Expression $expr, Twig_NodeInterface $ops, $lineno)
{
- parent::__construct($lineno);
- $this->expr = $expr;
- $this->ops = $ops;
+ parent::__construct(array('expr' => $expr, 'ops' => $ops), array(), $lineno);
}
public function compile($compiler)
{
- $nbOps = count($this->ops) > 1;
- if ('in' === $this->ops[0][0]) {
+ if ('in' === $this->ops->{0}['value']) {
return $this->compileIn($compiler);
}
$this->expr->compile($compiler);
- $i = 0;
- foreach ($this->ops as $op) {
- if ($i) {
- $compiler->raw(' && ($tmp'.$i);
+
+ $nbOps = count($this->ops);
+ for ($i = 0; $i < $nbOps; $i += 2) {
+ if ($i > 0) {
+ $compiler->raw(' && ($tmp'.($i / 2));
}
- list($op, $node) = $op;
- $compiler->raw(' '.$op.' ');
- if ($nbOps) {
+ $compiler->raw(' '.$this->ops->{$i}['value'].' ');
+
+ if ($i != $nbOps - 2) {
$compiler
- ->raw('($tmp'.++$i.' = ')
- ->subcompile($node)
+ ->raw('($tmp'.(($i / 2) + 1).' = ')
+ ->subcompile($this->ops->{($i + 1)})
->raw(')')
;
} else {
- $compiler->subcompile($node);
+ $compiler->subcompile($this->ops->{($i + 1)});
}
}
- for ($j = 1; $j < $i; $j++) {
+ for ($j = 1; $j < $i / 2; $j++) {
$compiler->raw(')');
}
}
->raw('twig_in_filter(')
->subcompile($this->expr)
->raw(', ')
- ->subcompile($this->ops[0][1])
+ ->subcompile($this->ops->{1})
->raw(')')
;
}
*/
class Twig_Node_Expression_Conditional extends Twig_Node_Expression
{
- protected $expr1;
- protected $expr2;
- protected $expr3;
-
public function __construct(Twig_Node_Expression $expr1, Twig_Node_Expression $expr2, Twig_Node_Expression $expr3, $lineno)
{
- parent::__construct($lineno);
- $this->expr1 = $expr1;
- $this->expr2 = $expr2;
- $this->expr3 = $expr3;
+ parent::__construct(array('expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno);
}
public function compile($compiler)
*/
class Twig_Node_Expression_Constant extends Twig_Node_Expression
{
- protected $value;
-
public function __construct($value, $lineno)
{
- parent::__construct($lineno);
- $this->value = $value;
- }
-
- public function __toString()
- {
- return get_class($this).'(\''.$this->value.'\')';
+ parent::__construct(array(), array('value' => $value), $lineno);
}
public function compile($compiler)
{
- $compiler->repr($this->value);
- }
-
- public function getValue()
- {
- return $this->value;
+ $compiler->repr($this['value']);
}
}
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-class Twig_Node_Expression_Filter extends Twig_Node_Expression implements Twig_NodeListInterface
+class Twig_Node_Expression_Filter extends Twig_Node_Expression
{
- protected $node;
- protected $filters;
-
- public function __construct(Twig_NodeInterface $node, array $filters, $lineno, $tag = null)
- {
- parent::__construct($lineno, $tag);
-
- $this->node = $node;
- $this->filters = $filters;
- }
-
- public function __toString()
- {
- $filters = array();
- foreach ($this->filters as $filter) {
- $filters[] = $filter[0].'('.implode(', ', $filter[1]).')';
- }
-
- $repr = array(get_class($this).'('.implode(', ', $filters));
-
- foreach (explode("\n", $this->node->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
-
- $repr[] = ')';
-
- return implode("\n", $repr);
- }
-
- public function getNodes()
- {
- return array($this->node);
- }
-
- public function setNodes(array $nodes)
+ public function __construct(Twig_NodeInterface $node, Twig_NodeInterface $filters, $lineno, $tag = null)
{
- $this->node = $nodes[0];
+ parent::__construct(array('node' => $node, 'filters' => $filters), array(), $lineno, $tag);
}
public function compile($compiler)
$filterMap = $compiler->getEnvironment()->getFilters();
$postponed = array();
- for ($i = count($this->filters) - 1; $i >= 0; --$i) {
- list($name, $attrs) = $this->filters[$i];
+ for ($i = count($this->filters) - 1; $i >= 0; $i -= 2) {
+ $name = $this->filters->{$i - 1}['value'];
+ $attrs = $this->filters->{$i};
if (!isset($filterMap[$name])) {
- $compiler
- ->raw('$this->resolveMissingFilter(')
- ->repr($name)
- ->raw(', ')
- ;
+ throw new Twig_SyntaxError(sprintf('The filter "%s" does not exist', $name), $this->getLine());
} else {
$compiler->raw($filterMap[$name]->compile().($filterMap[$name]->needsEnvironment() ? '($this->getEnvironment(), ' : '('));
}
$postponed[] = $attrs;
}
+
$this->node->compile($compiler);
+
foreach (array_reverse($postponed) as $attributes) {
foreach ($attributes as $node) {
$compiler
}
}
- public function getFilters()
+ public function prependFilter(Twig_Node_Expression_Constant $name, Twig_Node $end)
{
- return $this->filters;
- }
+ $filters = array($name, $end);
+ foreach ($this->filters as $node) {
+ $filters[] = $node;
+ }
- public function setFilters(array $filters)
- {
- $this->filters = $filters;
+ $this->filters = new Twig_Node($filters, array(), $this->filters->getLine());
}
- public function prependFilter($filter)
+ public function appendFilter(Twig_Node_Expression_Constant $name, Twig_Node $end)
{
- $this->filters = array_merge(array($filter), $this->filters);
- }
+ $filters = array();
+ foreach ($this->filters as $node) {
+ $filters[] = $node;
+ }
- public function appendFilter($filter)
- {
- $this->filters[] = $filter;
+ $filters[] = $name;
+ $filters[] = $end;
+
+ $this->filters = new Twig_Node($filters, array(), $this->filters->getLine());
}
- public function appendFilters(array $filters)
+ public function appendFilters(Twig_NodeInterface $filters)
{
- $this->filters = array_merge($this->filters, $filters);
+ for ($i = 0; $i < count($filters); $i += 2) {
+ $this->appendFilter($filters->{$i}, $filters->{$i + 1});
+ }
}
public function hasFilter($name)
{
- foreach ($this->filters as $filter) {
- if ($name == $filter[0]) {
+ for ($i = 0; $i < count($this->filters); $i += 2) {
+ if ($name == $this->filters->{$i}['value']) {
return true;
}
}
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-class Twig_Node_Expression_GetAttr extends Twig_Node_Expression implements Twig_NodeListInterface
+class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
{
- protected $node;
- protected $attr;
- protected $arguments;
-
- public function __construct(Twig_NodeInterface $node, $attr, $arguments, $lineno, $token_value)
- {
- parent::__construct($lineno);
- $this->node = $node;
- $this->attr = $attr;
- $this->arguments = $arguments;
- $this->token_value = $token_value;
- }
-
- public function __toString()
- {
- return get_class($this).'('.$this->node.', '.$this->attr.')';
- }
-
- public function getNode()
- {
- return $this->node;
- }
-
- public function getNodes()
- {
- return array($this->node);
- }
-
- public function setNodes(array $nodes)
+ public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_NodeInterface $arguments, $lineno, $token_value = null)
{
- $this->node = $nodes[0];
+ parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('token_value' => $token_value), $lineno);
}
public function compile($compiler)
->raw('$this->getAttribute(')
->subcompile($this->node)
->raw(', ')
- ->subcompile($this->attr)
+ ->subcompile($this->attribute)
->raw(', array(')
;
$compiler->raw(')');
// Don't look for functions if they're using foo[bar]
- if ('[' == $this->token_value) {
+ if ('[' == $this['token_value']) {
$compiler->raw(', true');
}
*/
class Twig_Node_Expression_Name extends Twig_Node_Expression
{
- protected $name;
-
public function __construct($name, $lineno)
{
- parent::__construct($lineno);
- $this->name = $name;
- }
-
- public function __toString()
- {
- return get_class($this).'(\''.$this->name.'\')';
+ parent::__construct(array(), array('name' => $name), $lineno);
}
public function compile($compiler)
{
- $compiler->raw(sprintf('$this->getContext($context, \'%s\')', $this->name, $this->name));
- }
-
- public function getName()
- {
- return $this->name;
+ $compiler->raw(sprintf('$this->getContext($context, \'%s\')', $this['name'], $this['name']));
}
}
*/
abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression
{
- protected $node;
-
public function __construct(Twig_NodeInterface $node, $lineno)
{
- parent::__construct($lineno);
- $this->node = $node;
- }
-
- public function __toString()
- {
- $repr = array(get_class($this).'(');
-
- foreach (explode("\n", $this->node->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
-
- $repr[] = ')';
-
- return implode("\n", $repr);
+ parent::__construct(array('node' => $node), array(), $lineno);
}
public function compile($compiler)
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a filter node.
- *
- * @package twig
- * @author Fabien Potencier <fabien.potencier@symfony-project.com>
- * @version SVN: $Id$
- */
-class Twig_Node_Filter extends Twig_Node implements Twig_NodeListInterface
-{
- protected $filters;
- protected $body;
-
- public function __construct($filters, Twig_NodeList $body, $lineno, $tag = null)
- {
- parent::__construct($lineno, $tag);
- $this->filters = $filters;
- $this->body = $body;
- }
-
- public function __toString()
- {
- $filters = array();
- foreach ($this->filters as $filter) {
- $filters[] = $filter[0].'('.implode(', ', $filter[1]).')';
- }
-
- $repr = array(get_class($this).'('.implode(', ', $filters));
-
- foreach (explode("\n", $this->body->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
-
- $repr[] = ')';
-
- return implode("\n", $repr);
- }
-
- public function getNodes()
- {
- return $this->body->getNodes();
- }
-
- public function setNodes(array $nodes)
- {
- $this->body = new Twig_NodeList($nodes, $this->lineno);
- }
-
- public function compile($compiler)
- {
- $compiler->subcompile($this->body);
- }
-
- public function getFilters()
- {
- return $this->filters;
- }
-}
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_For extends Twig_Node implements Twig_NodeListInterface
+class Twig_Node_For extends Twig_Node
{
- protected $isMultitarget;
- protected $item;
- protected $seq;
- protected $body;
- protected $else;
- protected $withLoop;
-
- public function __construct($isMultitarget, $item, $seq, Twig_NodeList $body, Twig_Node $else = null, $withLoop = false, $lineno, $tag = null)
+ public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $withLoop = false, $lineno, $tag = null)
{
- parent::__construct($lineno, $tag);
- $this->isMultitarget = $isMultitarget;
- $this->item = $item;
- $this->seq = $seq;
- $this->body = $body;
- $this->else = $else;
- $this->withLoop = $withLoop;
- $this->lineno = $lineno;
- }
-
- public function getNodes()
- {
- return $this->body->getNodes();
- }
-
- public function setNodes(array $nodes)
- {
- $this->body = new Twig_NodeList($nodes, $this->lineno);
+ parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => $withLoop), $lineno, $tag);
}
public function compile($compiler)
$compiler->write("\$context['_iterated'] = false;\n");
}
- if ($this->isMultitarget) {
- $loopVars = array($this->item[0]->getName(), $this->item[1]->getName());
- } else {
- $loopVars = array('_key', $this->item->getName());
- }
-
$compiler
->write("\$context['_seq'] = twig_iterator_to_array(")
->subcompile($this->seq)
- ->raw(", ".($this->isMultitarget ? 'true' : 'false').");\n")
+ ->raw(", ".(null !== $this->key_target ? 'true' : 'false').");\n")
;
- if ($this->withLoop) {
+ if ($this['with_loop']) {
$compiler
->write("\$length = count(\$context['_seq']);\n")
}
$compiler
- ->write("foreach (\$context['_seq'] as \$context[")
- ->repr($loopVars[0])
- ->raw("] => \$context[")
- ->repr($loopVars[1])
- ->raw("]) {\n")
+ ->write("foreach (\$context['_seq'] as ")
+ ->subcompile($this->key_target)
+ ->raw(" => ")
+ ->subcompile($this->value_target)
+ ->raw(") {\n")
->indent()
;
$compiler->subcompile($this->body);
- if ($this->withLoop) {
+ if ($this['with_loop']) {
$compiler
->write("++\$context['loop']['index0'];\n")
->write("++\$context['loop']['index'];\n")
if (!is_null($this->else)) {
$compiler
- ->write("if (!\$context['_iterated'])\n")
- ->write("{\n")
+ ->write("if (!\$context['_iterated']) {\n")
->indent()
->subcompile($this->else)
->outdent()
$compiler->write('$_parent = $context[\'_parent\'];'."\n");
// remove some "private" loop variables (needed for nested loops)
- $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$loopVars[0].'\'], $context[\''.$loopVars[1].'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
+ $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->key_target['name'].'\'], $context[\''.$this->value_target['name'].'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
/// keep the values set in the inner context for variables defined in the outer context
$compiler->write('$context = array_merge($_parent, array_intersect_key($context, $_parent));'."\n");
}
-
- public function setWithLoop($boolean)
- {
- $this->withLoop = (Boolean) $boolean;
- }
}
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_If extends Twig_Node implements Twig_NodeListInterface
+class Twig_Node_If extends Twig_Node
{
- protected $tests;
- protected $else;
-
- public function __construct($tests, Twig_NodeList $else = null, $lineno, $tag = null)
- {
- parent::__construct($lineno, $tag);
- $this->tests = $tests;
- $this->else = $else;
- }
-
- public function __toString()
- {
- $repr = array(get_class($this).'(');
- foreach ($this->tests as $test) {
- foreach (explode("\n", $test[0].' => '.$test[1]) as $line) {
- $repr[] = ' '.$line;
- }
- }
- $repr[] = ')';
-
- if ($this->else) {
- foreach (explode("\n", $this->else) as $line) {
- $repr[] = ' '.$line;
- }
- }
-
- return implode("\n", $repr);
- }
-
- public function getNodes()
- {
- $nodes = array();
- foreach ($this->tests as $test) {
- $nodes[] = $test[1];
- }
-
- if ($this->else) {
- $nodes[] = $this->else;
- }
-
- return $nodes;
- }
-
- public function setNodes(array $nodes)
+ public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null)
{
- foreach ($this->tests as $i => $test) {
- $this->tests[$i][1] = $nodes[$i];
- }
-
- if ($this->else) {
- $nodes = $nodes[count($nodes) - 1];
- }
+ parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag);
}
public function compile($compiler)
{
$compiler->addDebugInfo($this);
- $idx = 0;
- foreach ($this->tests as $test) {
- if ($idx++) {
+ for ($i = 0; $i < count($this->tests); $i += 2) {
+ if ($i > 0) {
$compiler
->outdent()
->write("} elseif (")
}
$compiler
- ->subcompile($test[0])
+ ->subcompile($this->tests->{$i})
->raw(") {\n")
->indent()
- ->subcompile($test[1])
+ ->subcompile($this->tests->{($i + 1)})
;
}
- if (!is_null($this->else)) {
+
+ if (isset($this->else) && null !== $this->else) {
$compiler
->outdent()
->write("} else {\n")
*/
class Twig_Node_Import extends Twig_Node
{
- protected $macro;
- protected $var;
-
- public function __construct($macro, $var, $lineno, $tag = null)
+ public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression_AssignName $var, $lineno, $tag = null)
{
- parent::__construct($lineno, $tag);
- $this->macro = $macro;
- $this->var = $var;
- }
-
- public function __toString()
- {
- return get_class($this).'('.$this->macro.', '.$this->var.')';
+ parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag);
}
public function compile($compiler)
{
$compiler
->addDebugInfo($this)
- ->write('$this->env->loadTemplate(')
- ->string($this->macro)
- ->raw(");\n\n")
- ->write("if (!class_exists(")
- ->string($compiler->getTemplateClass($this->macro).'_Macro')
- ->raw(")) {\n")
- ->indent()
- ->write(sprintf("throw new InvalidArgumentException('There is no defined macros in template \"%s\".');\n", $this->macro))
- ->outdent()
- ->write("}\n")
- ->write(sprintf("\$context["))
- ->string($this->var)
- ->raw(sprintf("] = new %s_Macro(\$this->env);\n", $compiler->getTemplateClass($this->macro)))
+ ->write('')
+ ->subcompile($this->var)
+ ->raw(' = ')
+ ->raw('$this->env->loadTemplate(')
+ ->subcompile($this->expr)
+ ->raw(", true);\n")
;
}
-
- public function getMacro()
- {
- return $this->macro;
- }
-
- public function getVar()
- {
- return $this->var;
- }
}
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_Include extends Twig_Node implements Twig_NodeListInterface
+class Twig_Node_Include extends Twig_Node
{
- protected $expr;
- protected $sandboxed;
- protected $variables;
-
- public function __construct(Twig_Node_Expression $expr, $sandboxed, $variables, $lineno, $tag = null)
- {
- parent::__construct($lineno, $tag);
-
- $this->expr = $expr;
- $this->sandboxed = $sandboxed;
- $this->variables = $variables;
- }
-
- public function __toString()
+ public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $lineno, $tag = null)
{
- return get_class($this).'('.$this->expr.($this->sandboxed ? ', sandboxed' : '').($this->variables ? ', '.$this->variables : '').')';
- }
-
- public function getNodes()
- {
- if (null === $this->variables) {
- return array(new Twig_Node_Text('', -1));
- } else {
- return array($this->variables);
- }
-
- return $this->variables->getNodes();
- }
-
- public function setNodes(array $nodes)
- {
- if (isset($nodes[0]) && -1 === $nodes[0]->getLine()) {
- $this->variables = null;
- } else {
- $this->variables = $nodes[0];
- }
- }
-
- public function getIncludedFile()
- {
- return $this->expr;
- }
-
- public function isSandboxed()
- {
- return $this->sandboxed;
- }
-
- public function getVariables()
- {
- return $this->variables;
+ parent::__construct(array('expr' => $expr, 'variables' => $variables), array(), $lineno, $tag);
}
public function compile($compiler)
{
- if (!$compiler->getEnvironment()->hasExtension('sandbox') && $this->sandboxed) {
- throw new Twig_SyntaxError('Unable to use the sanboxed attribute on an include if the sandbox extension is not enabled.', $this->lineno);
- }
-
- $compiler->addDebugInfo($this);
-
- if ($this->sandboxed) {
- $compiler
- ->write("\$sandbox = \$this->env->getExtension('sandbox');\n")
- ->write("\$alreadySandboxed = \$sandbox->isSandboxed();\n")
- ->write("\$sandbox->enableSandbox();\n")
- ;
- }
-
$compiler
+ ->addDebugInfo($this)
->write('$this->env->loadTemplate(')
->subcompile($this->expr)
->raw(')->display(')
}
$compiler->raw(");\n");
-
- if ($this->sandboxed) {
- $compiler
- ->write("if (!\$alreadySandboxed) {\n")
- ->indent()
- ->write("\$sandbox->disableSandbox();\n")
- ->outdent()
- ->write("}\n")
- ;
- }
}
}
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_Macro extends Twig_Node implements Twig_NodeListInterface
+class Twig_Node_Macro extends Twig_Node
{
- protected $name;
- protected $body;
- protected $arguments;
-
- public function __construct($name, Twig_NodeList $body, $arguments, $lineno, $parent = null, $tag = null)
- {
- parent::__construct($lineno, $tag);
- $this->name = $name;
- $this->body = $body;
- $this->arguments = $arguments;
- }
-
- public function __toString()
- {
- $repr = array(get_class($this).' '.$this->name.'(');
- foreach ($this->body->getNodes() as $node) {
- foreach (explode("\n", $node->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
- }
- $repr[] = ')';
-
- return implode("\n", $repr);
- }
-
- public function getNodes()
- {
- return $this->body->getNodes();
- }
-
- public function setNodes(array $nodes)
- {
- $this->body = new Twig_NodeList($nodes, $this->lineno);
- }
-
- public function replace($other)
+ public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
{
- $this->body = $other->body;
+ parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
}
public function compile($compiler)
{
$arguments = array();
foreach ($this->arguments as $argument) {
- $arguments[] = '$'.$argument->getName().' = null';
+ $arguments[] = '$'.$argument['name'].' = null';
}
$compiler
->addDebugInfo($this)
- ->write(sprintf("public function get%s(%s)\n", $this->name, implode(', ', $arguments)), "{\n")
+ ->write(sprintf("public function get%s(%s)\n", $this['name'], implode(', ', $arguments)), "{\n")
->indent()
->write("\$context = array(\n")
->indent()
foreach ($this->arguments as $argument) {
$compiler
->write('')
- ->string($argument->getName())
- ->raw(' => $'.$argument->getName())
+ ->string($argument['name'])
+ ->raw(' => $'.$argument['name'])
->raw(",\n")
;
}
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_Module extends Twig_Node implements Twig_NodeListInterface
+class Twig_Node_Module extends Twig_Node
{
- protected $body;
- protected $extends;
- protected $blocks;
- protected $macros;
- protected $filename;
- protected $usedFilters;
- protected $usedTags;
-
- public function __construct(Twig_NodeList $body, $extends, array $blocks, array $macros, $filename)
+ public function __construct(Twig_NodeInterface $body, $extends, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, $filename)
{
- parent::__construct(1);
-
- $this->body = $body;
- $this->extends = $extends;
- $this->blocks = array_values($blocks);
- $this->macros = $macros;
- $this->filename = $filename;
- $this->usedFilters = array();
- $this->usedTags = array();
+ parent::__construct(array('body' => $body, 'blocks' => $blocks, 'macros' => $macros), array('filename' => $filename, 'extends' => $extends), 1);
}
- public function __toString()
+ public function compile($compiler)
{
- $repr = array(get_class($this).'(');
-
- if ($this->extends)
- {
- $repr[] = ' extends: '.$this->extends;
- }
-
- $repr[] = ' body:';
- foreach ($this->body->getNodes() as $node) {
- foreach (explode("\n", $node->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
- }
+ $this->compileTemplate($compiler);
+ $this->compileMacros($compiler);
+ }
- $repr[] = ' blocks: ';
- foreach ($this->blocks as $node) {
- foreach (explode("\n", $node->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
- }
+ protected function compileTemplate($compiler)
+ {
+ $this->compileClassHeader($compiler);
- $repr[] = ' macros: ';
- foreach ($this->macros as $node) {
- foreach (explode("\n", $node->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
- }
+ $this->compileDisplayHeader($compiler);
- $repr[] = ')';
+ $this->compileDisplayBody($compiler);
- return implode("\n", $repr);
- }
+ $this->compileDisplayFooter($compiler);
- public function getFilename()
- {
- return $this->filename;
- }
+ $compiler->subcompile($this->blocks);
- public function getBody()
- {
- return $this->body;
- }
+ $this->compileGetName($compiler);
- public function getNodes()
- {
- return array_merge(array($this->body), $this->blocks, $this->macros);
+ $this->compileClassFooter($compiler);
}
- public function setNodes(array $nodes)
+ protected function compileDisplayBody($compiler)
{
- $this->body = array_shift($nodes);
- $this->blocks = array();
- $this->macros = array();
- foreach ($nodes as $node) {
- if ($node instanceof Twig_Node_Macro) {
- $this->macros[] = $node;
- } else {
- $this->blocks[] = $node;
+ if (null !== $this['extends']) {
+ // remove all but import nodes
+ foreach ($this->body as $node) {
+ if ($node instanceof Twig_Node_Import) {
+ $compiler->subcompile($node);
+ }
}
- }
- }
- public function setUsedFilters(array $filters)
- {
- $this->usedFilters = $filters;
- }
-
- public function setUsedTags(array $tags)
- {
- $this->usedTags = $tags;
- }
-
- public function compile($compiler)
- {
- $this->compileTemplate($compiler);
- $this->compileMacros($compiler);
+ $compiler
+ ->raw("\n")
+ ->write("parent::display(\$context);\n")
+ ;
+ } else {
+ $compiler->subcompile($this->body);
+ }
}
- protected function compileTemplate($compiler)
+ protected function compileClassHeader($compiler)
{
- $sandboxed = $compiler->getEnvironment()->hasExtension('sandbox');
-
$compiler->write("<?php\n\n");
- if (!is_null($this->extends)) {
+ if (null !== $this['extends']) {
$compiler
->write('$this->loadTemplate(')
- ->repr($this->extends)
+ ->repr($this['extends'])
->raw(");\n\n")
;
}
$compiler
// if the filename contains */, add a blank to avoid a PHP parse error
- ->write("/* ".str_replace('*/', '* /', $this->filename)." */\n")
- ->write('class '.$compiler->getTemplateClass($this->filename))
+ ->write("/* ".str_replace('*/', '* /', $this['filename'])." */\n")
+ ->write('class '.$compiler->getEnvironment()->getTemplateClass($this['filename']))
;
- $parent = null === $this->extends ? $compiler->getEnvironment()->getBaseTemplateClass() : $compiler->getTemplateClass($this->extends);
+ $parent = null === $this['extends'] ? $compiler->getEnvironment()->getBaseTemplateClass() : $compiler->getEnvironment()->getTemplateClass($this['extends']);
$compiler
->raw(" extends $parent\n")
->write("{\n")
->indent()
+ ;
+ }
+
+ protected function compileDisplayHeader($compiler)
+ {
+ $compiler
->write("public function display(array \$context)\n", "{\n")
->indent()
;
+ }
- if (null !== $this->extends) {
- // remove all but import nodes
- $nodes = array();
- foreach ($this->body->getNodes() as $node) {
- if ($node instanceof Twig_Node_Import) {
- $nodes[] = $node;
- }
- }
-
- $compiler
- ->subcompile(new Twig_NodeList($nodes))
- ->write("\n")
- ->write("parent::display(\$context);\n")
- ->outdent()
- ->write("}\n\n")
- ;
- } else {
- if ($sandboxed) {
- $compiler->write("\$this->checkSecurity();\n");
- }
-
- $compiler
- ->subcompile($this->body)
- ->outdent()
- ->write("}\n\n")
- ;
- }
-
- // blocks
- foreach ($this->blocks as $node) {
- $compiler->subcompile($node);
- }
-
- if ($sandboxed) {
- // sandbox information
- $compiler
- ->write("protected function checkSecurity()\n", "{\n")
- ->indent()
- ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
- ->indent()
- ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
- ->write(!$this->usedFilters ? "array()\n" : "array('".implode('\', \'', $this->usedFilters)."')\n")
- ->outdent()
- ->write(");\n")
- ->outdent()
- ->write("}\n\n")
- ;
- }
-
- // debug information
- if ($compiler->getEnvironment()->isDebug()) {
- $compiler
- ->write("public function __toString()\n", "{\n")
- ->indent()
- ->write('return ')
- ->string($this)
- ->raw(";\n")
- ->outdent()
- ->write("}\n\n")
- ;
- }
-
- // original template name
+ protected function compileGetName($compiler)
+ {
$compiler
->write("public function getName()\n", "{\n")
->indent()
->write('return ')
- ->string($this->filename)
+ ->string($this['filename'])
->raw(";\n")
->outdent()
->write("}\n\n")
;
+ }
+ protected function compileDisplayFooter($compiler)
+ {
+ $compiler
+ ->outdent()
+ ->write("}\n\n")
+ ;
+ }
+
+ protected function compileClassFooter($compiler)
+ {
$compiler
->outdent()
->write("}\n")
protected function compileMacros($compiler)
{
- if (!$this->macros) {
- return;
- }
-
$compiler
->write("\n")
- ->write('class '.$compiler->getTemplateClass($this->filename).'_Macro extends Twig_Macro'."\n")
+ ->write('class '.$compiler->getEnvironment()->getTemplateClass($this['filename']).'_Macro extends Twig_Macro'."\n")
->write("{\n")
->indent()
;
// macros
- foreach ($this->macros as $node) {
- $compiler->subcompile($node);
- }
+ $compiler->subcompile($this->macros);
$compiler
->outdent()
*/
class Twig_Node_Parent extends Twig_Node
{
- protected $blockName;
-
- public function __construct($blockName, $lineno, $tag = null)
- {
- parent::__construct($lineno, $tag);
- $this->blockName = $blockName;
- }
-
- public function __toString()
+ public function __construct($name, $lineno, $tag = null)
{
- return get_class($this).'('.$this->blockName.')';
+ parent::__construct(array(), array('name' => $name), $lineno, $tag);
}
public function compile($compiler)
{
$compiler
->addDebugInfo($this)
- ->write('parent::block_'.$this->blockName.'($context);'."\n")
+ ->write('parent::block_'.$this['name'].'($context);'."\n")
;
}
}
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_Print extends Twig_Node implements Twig_NodeListInterface
+class Twig_Node_Print extends Twig_Node
{
- protected $expr;
-
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
{
- parent::__construct($lineno, $tag);
- $this->expr = $expr;
- }
-
- public function __toString()
- {
- $repr = array(get_class($this).'(');
- foreach (explode("\n", $this->expr->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
- $repr[] = ')';
-
- return implode("\n", $repr);
- }
-
- public function getNodes()
- {
- return array($this->expr);
- }
-
- public function setNodes(array $nodes)
- {
- $this->expr = $nodes[0];
+ parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
}
public function compile($compiler)
->raw(";\n")
;
}
-
- public function getExpression()
- {
- return $this->expr;
- }
}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2010 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Represents a sandbox node.
+ *
+ * @package twig
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id$
+ */
+class Twig_Node_Sandbox extends Twig_Node
+{
+ public function __construct(Twig_NodeInterface $body, $lineno, $tag = null)
+ {
+ parent::__construct(array('body' => $body), array(), $lineno, $tag);
+ }
+
+ public function compile($compiler)
+ {
+ $compiler
+ ->addDebugInfo($this)
+ ->write("\$sandbox = \$this->env->getExtension('sandbox');\n")
+ ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n")
+ ->indent()
+ ->write("\$sandbox->enableSandbox();\n")
+ ->outdent()
+ ->write("}\n")
+ ->subcompile($this->body)
+ ->write("if (!\$alreadySandboxed) {\n")
+ ->indent()
+ ->write("\$sandbox->disableSandbox();\n")
+ ->outdent()
+ ->write("}\n")
+ ;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2009 Fabien Potencier
+ * (c) 2009 Armin Ronacher
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Represents a module node.
+ *
+ * @package twig
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id$
+ */
+class Twig_Node_SandboxedModule extends Twig_Node_Module
+{
+ protected $usedFilters;
+ protected $usedTags;
+
+ public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags)
+ {
+ parent::__construct($node->body, $node['extends'], $node->blocks, $node->macros, $node['filename'], $node->getLine(), $node->getNodeTag());
+
+ $this->usedFilters = $usedFilters;
+ $this->usedTags = $usedTags;
+ }
+
+ protected function compileDisplayBody($compiler)
+ {
+ if (null === $this['extends']) {
+ $compiler->write("\$this->checkSecurity();\n");
+ }
+
+ parent::compileDisplayBody($compiler);
+ }
+
+ protected function compileDisplayFooter($compiler)
+ {
+ parent::compileDisplayFooter($compiler);
+
+ $compiler
+ ->write("protected function checkSecurity() {\n")
+ ->indent()
+ ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
+ ->indent()
+ ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
+ ->write(!$this->usedFilters ? "array()\n" : "array('".implode('\', \'', $this->usedFilters)."')\n")
+ ->outdent()
+ ->write(");\n")
+ ;
+
+ if (null !== $this['extends']) {
+ $compiler
+ ->raw("\n")
+ ->write("parent::checkSecurity();\n")
+ ;
+ }
+
+ $compiler
+ ->outdent()
+ ->write("}\n\n")
+ ;
+ }
+}
*/
/**
- * Twig_Node_SandboxPrint adds a check for the __toString() method
+ * Twig_Node_SandboxedPrint adds a check for the __toString() method
* when the variable is an object and the sandbox is activated.
*
* When there is a simple Print statement, like {{ article }},
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_SandboxPrint extends Twig_Node_Print
+class Twig_Node_SandboxedPrint extends Twig_Node_Print
{
+ public function __construct(Twig_Node_Print $node)
+ {
+ parent::__construct($node->expr, $node->getLine(), $node->getNodeTag());
+ }
+
public function compile($compiler)
{
$compiler
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
-class Twig_Node_Set extends Twig_Node implements Twig_NodeListInterface
+class Twig_Node_Set extends Twig_Node
{
- protected $names;
- protected $values;
- protected $isMultitarget;
- protected $capture;
-
- public function __construct($isMultitarget, $capture, $names, $values, $lineno, $tag = null)
- {
- parent::__construct($lineno, $tag);
-
- $this->isMultitarget = $isMultitarget;
- $this->capture = $capture;
- $this->names = $names;
- $this->values = $values;
- }
-
- public function __toString()
+ public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null)
{
- $repr = array(get_class($this).'('.($this->isMultitarget ? implode(', ', $this->names) : $this->names).',');
- foreach ($this->isMultitarget ? $this->values : array($this->values) as $node) {
- foreach (explode("\n", $node->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
- }
- $repr[] = ')';
-
- return implode("\n", $repr);
- }
-
- public function getNodes()
- {
- if ($this->isMultitarget) {
- return $this->values;
- } else {
- return array($this->values);
- }
- }
-
- public function setNodes(array $nodes)
- {
- $this->values = $this->isMultitarget ? $nodes : $nodes[0];
+ parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture), $lineno, $tag);
}
public function compile($compiler)
{
$compiler->addDebugInfo($this);
- if ($this->isMultitarget) {
+ if (count($this->names) > 1) {
$compiler->write('list(');
foreach ($this->names as $idx => $node) {
if ($idx) {
}
$compiler->raw(')');
} else {
- if ($this->capture) {
+ if ($this['capture']) {
$compiler
->write("ob_start();\n")
->subcompile($this->values)
$compiler->subcompile($this->names, false);
- if ($this->capture) {
+ if ($this['capture']) {
$compiler->raw(" = ob_get_clean()");
}
}
- if (!$this->capture) {
+ if (!$this['capture']) {
$compiler->raw(' = ');
- if ($this->isMultitarget) {
+ if (count($this->names) > 1) {
$compiler->write('array(');
foreach ($this->values as $idx => $value) {
if ($idx) {
$compiler->raw(";\n");
}
-
- public function getNames()
- {
- return $this->names;
- }
}
*/
class Twig_Node_Text extends Twig_Node
{
- protected $data;
-
public function __construct($data, $lineno)
{
- parent::__construct($lineno);
- $this->data = $data;
- }
-
- public function __toString()
- {
- return get_class($this).'(\''.str_replace("\n", '\n', $this->data).'\')';
+ parent::__construct(array(), array('data' => $data), $lineno);
}
public function compile($compiler)
$compiler
->addDebugInfo($this)
->write('echo ')
- ->string($this->data)
+ ->string($this['data'])
->raw(";\n")
;
}
-
- public function getData()
- {
- return $this->data;
- }
}
*/
class Twig_Node_Trans extends Twig_Node
{
- protected $count, $body, $plural;
-
- public function __construct($count, Twig_NodeList $body, $plural, $lineno, $tag = null)
+ public function __construct(Twig_Node_Expression $count = null, Twig_NodeInterface $body, Twig_NodeInterface $plural = null, $lineno, $tag = null)
{
- parent::__construct($lineno, $tag);
-
- $this->count = $count;
- $this->body = $body;
- $this->plural = $plural;
- }
-
- public function __toString()
- {
- return get_class($this).'('.$this->body.', '.$this->count.')';
+ parent::__construct(array('count' => $count, 'body' => $body, 'plural' => $plural), array(), $lineno, $tag);
}
public function compile($compiler)
list($msg, $vars) = $this->compileString($this->body);
- if (false !== $this->plural) {
+ if (null !== $this->plural) {
list($msg1, $vars1) = $this->compileString($this->plural);
$vars = array_merge($vars, $vars1);
}
- $function = false === $this->plural ? 'gettext' : 'ngettext';
+ $function = null === $this->plural ? 'gettext' : 'ngettext';
if ($vars) {
$compiler
->string($msg)
;
- if (false !== $this->plural) {
+ if (null !== $this->plural) {
$compiler
->raw(', ')
->string($msg1)
$compiler->raw('), array(');
foreach ($vars as $var) {
- if ('count' === $var->getName()) {
+ if ('count' === $var['name']) {
$compiler
->string('%count%')
->raw(' => abs(')
;
} else {
$compiler
- ->string('%'.$var->getName().'%')
+ ->string('%'.$var['name'].'%')
->raw(' => ')
->subcompile($var)
->raw(', ')
}
}
- public function getBody()
- {
- return $this->body;
- }
-
- public function getPlural()
- {
- return $this->plural;
- }
-
- public function getCount()
- {
- return $this->count;
- }
-
- protected function compileString(Twig_NodeList $body)
+ protected function compileString(Twig_NodeInterface $body)
{
$msg = '';
$vars = array();
- foreach ($body->getNodes() as $i => $node) {
+ foreach ($body as $i => $node) {
if ($node instanceof Twig_Node_Text) {
- $msg .= $node->getData();
- } elseif ($node instanceof Twig_Node_Print && $node->getExpression() instanceof Twig_Node_Expression_Name) {
- $msg .= sprintf('%%%s%%', $node->getExpression()->getName());
- $vars[] = $node->getExpression();
+ $msg .= $node['data'];
+ } elseif ($node instanceof Twig_Node_Print && $node->expr instanceof Twig_Node_Expression_Name) {
+ $msg .= sprintf('%%%s%%', $node->expr['name']);
+ $vars[] = $node->expr;
} else {
- throw new Twig_SyntaxError(sprintf('The text to be translated with "trans" can only contain references to simple variable'), $this->lineno);
+ throw new Twig_SyntaxError(sprintf('The text to be translated with "trans" can only contain references to simple variables'), $this->lineno);
}
}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- * (c) 2009 Armin Ronacher
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a list of nodes.
- *
- * @package twig
- * @author Fabien Potencier <fabien.potencier@symfony-project.com>
- * @version SVN: $Id$
- */
-class Twig_NodeList extends Twig_Node implements Twig_NodeListInterface
-{
- protected $nodes;
-
- public function __construct(array $nodes, $lineno = 0)
- {
- parent::__construct($lineno);
-
- $this->nodes = $nodes;
- }
-
- public function __toString()
- {
- $repr = array(get_class($this).'(');
- foreach ($this->nodes as $node) {
- foreach (explode("\n", $node->__toString()) as $line) {
- $repr[] = ' '.$line;
- }
- }
-
- return implode("\n", $repr);
- }
-
- public function compile($compiler)
- {
- foreach ($this->nodes as $node) {
- $node->compile($compiler);
- }
- }
-
- public function getNodes()
- {
- return $this->nodes;
- }
-
- public function setNodes(array $nodes)
- {
- $this->nodes = $nodes;
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Interface implemented by node list classes.
- *
- * @package twig
- * @author Fabien Potencier <fabien.potencier@symfony-project.com>
- * @version SVN: $Id$
- */
-interface Twig_NodeListInterface
-{
- /**
- * Returns an array of embedded nodes
- */
- public function getNodes();
-
- /**
- * Sets the array of embedded nodes
- */
- public function setNodes(array $nodes);
-}
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+
+/**
+ * Twig_NodeTraverser is a node traverser.
+ *
+ * It visits all nodes and their children and call the given visitor for each.
+ *
+ * @package twig
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id$
+ */
class Twig_NodeTraverser
{
protected $env;
+ protected $visitors;
- public function __construct(Twig_Environment $env)
+ /**
+ * Constructor.
+ *
+ * @param Twig_Environment $env A Twig_Environment instance
+ * @param array $visitors An array of Twig_NodeVisitorInterface instances
+ */
+ public function __construct(Twig_Environment $env, array $visitors = array())
{
$this->env = $env;
+ $this->visitors = array();
+ foreach ($visitors as $visitor) {
+ $this->addVisitor($visitor);
+ }
+ }
+
+ /**
+ * Adds a visitor.
+ *
+ * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
+ */
+ public function addVisitor(Twig_NodeVisitorInterface $visitor)
+ {
+ $this->visitors[] = $visitor;
}
- public function traverse(Twig_NodeInterface $node, Twig_NodeVisitorInterface $visitor)
+ /**
+ * Traverses a node and calls the registered visitors.
+ *
+ * @param Twig_NodeInterface $node A Twig_NodeInterface instance
+ */
+ public function traverse(Twig_NodeInterface $node = null)
{
- $node = $visitor->enterNode($node, $this->env);
-
- if ($node instanceof Twig_NodeListInterface) {
- $newNodes = array();
- foreach ($nodes = $node->getNodes() as $k => $n) {
- if (null !== $n = $this->traverse($n, $visitor)) {
- $newNodes[$k] = $n;
- }
+ if (null === $node) {
+ return null;
+ }
+
+ foreach ($this->visitors as $visitor) {
+ $node = $visitor->enterNode($node, $this->env);
+ }
+
+ foreach ($node as $k => $n) {
+ if (false !== $n = $this->traverse($n)) {
+ $node->$k = $n;
+ } else {
+ unset($node->$k);
}
- $node->setNodes($newNodes);
}
- return $visitor->leaveNode($node, $this->env);
+ foreach ($this->visitors as $visitor) {
+ $node = $visitor->leaveNode($node, $this->env);
+ }
+
+ return $node;
}
}
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+
+/**
+ * Twig_NodeVisitor_Escaper implements output escaping.
+ *
+ * @package twig
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id$
+ */
class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
{
protected $statusStack = array();
protected $blocks = array();
+ /**
+ * Called before child nodes are visited.
+ *
+ * @param Twig_NodeInterface $node The node to visit
+ * @param Twig_Environment $env The Twig environment instance
+ *
+ * @param Twig_NodeInterface The modified node
+ */
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_AutoEscape) {
- $this->statusStack[] = $node->getValue();
+ $this->statusStack[] = $node['value'];
} elseif ($node instanceof Twig_Node_Print) {
return $this->escapeNode($node, $env, $this->needEscaping($env));
} elseif ($node instanceof Twig_Node_Block) {
- $this->statusStack[] = isset($this->blocks[$node->getName()]) ? $this->blocks[$node->getName()] : $this->needEscaping($env);
+ $this->statusStack[] = isset($this->blocks[$node['name']]) ? $this->blocks[$node['name']] : $this->needEscaping($env);
}
return $node;
}
+ /**
+ * Called after child nodes are visited.
+ *
+ * @param Twig_NodeInterface $node The node to visit
+ * @param Twig_Environment $env The Twig environment instance
+ *
+ * @param Twig_NodeInterface The modified node
+ */
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) {
array_pop($this->statusStack);
} elseif ($node instanceof Twig_Node_BlockReference) {
- $this->blocks[$node->getName()] = $this->needEscaping($env);
+ $this->blocks[$node['name']] = $this->needEscaping($env);
}
return $node;
return $node;
}
- $expression = $node instanceof Twig_Node_Print ? $node->getExpression() : $node;
+ $expression = $node instanceof Twig_Node_Print ? $node->expr : $node;
if ($expression instanceof Twig_Node_Expression_Filter) {
// 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) {
+ if (!$expression->node instanceof Twig_Node_Expression_Name) {
return $node;
}
// don't escape if there is already an "escaper" in the filter chain
$filterMap = $env->getFilters();
- foreach ($expression->getFilters() as $filter) {
- if (isset($filterMap[$filter[0]]) && $filterMap[$filter[0]]->isEscaper()) {
+ for ($i = 0; $i < count($expression->filters); $i += 2) {
+ $name = $expression->filters->{$i}['value'];
+ if (isset($filterMap[$name]) && $filterMap[$name]->isEscaper()) {
return $node;
}
}
// escape
if ($expression instanceof Twig_Node_Expression_Filter) {
// escape all variables in filters arguments
- $filters = $expression->getFilters();
- foreach ($filters as $i => $filter) {
- foreach ($filter[1] as $j => $argument) {
- $filters[$i][1][$j] = $this->escapeNode($argument, $env, $type);
+ for ($i = 0; $i < count($expression->filters); $i += 2) {
+ foreach ($expression->filters->{$i + 1} as $j => $n) {
+ $expression->filters->{$i + 1}->{$j} = $this->escapeNode($n, $env, $type);
}
}
- $expression->setFilters($filters);
- $expression->prependFilter($this->getEscaperFilter($type));
+ $filter = $this->getEscaperFilter($type, $expression->getLine());
+ $expression->prependFilter($filter[0], $filter[1]);
return $node;
} elseif ($node instanceof Twig_Node_Print) {
return new Twig_Node_Print(
- new Twig_Node_Expression_Filter($expression, array($this->getEscaperFilter($type)), $node->getLine())
+ new Twig_Node_Expression_Filter($expression, new Twig_Node($this->getEscaperFilter($type, $node->getLine())), $node->getLine())
, $node->getLine()
);
} else {
- return new Twig_Node_Expression_Filter($node, array($this->getEscaperFilter($type)), $node->getLine());
+ return new Twig_Node_Expression_Filter($node, new Twig_Node($this->getEscaperFilter($type, $node->getLine())), $node->getLine());
}
}
}
}
- protected function getEscaperFilter($type)
+ protected function getEscaperFilter($type, $line)
{
- return array('escape', array(new Twig_Node_Expression_Constant((string) $type, -1)));
+ return array(new Twig_Node_Expression_Constant('escape', $line), new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line))));
}
}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2009 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_NodeVisitor_Filter implements Twig_NodeVisitorInterface
-{
- protected $statusStack = array();
-
- public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if ($node instanceof Twig_Node_Filter) {
- $this->statusStack[] = $node->getFilters();
- } elseif ($node instanceof Twig_Node_Print || $node instanceof Twig_Node_Text) {
- return $this->applyFilters($node);
- }
-
- return $node;
- }
-
- public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
- {
- if ($node instanceof Twig_Node_Filter) {
- array_pop($this->statusStack);
- }
-
- return $node;
- }
-
- protected function applyFilters(Twig_NodeInterface $node)
- {
- if (false === $filters = $this->getCurrentFilters()) {
- return $node;
- }
-
- if ($node instanceof Twig_Node_Text) {
- $expression = new Twig_Node_Expression_Constant($node->getData(), $node->getLine());
- } else {
- $expression = $node->getExpression();
- }
-
- // filters
- if ($expression instanceof Twig_Node_Expression_Filter) {
- $expression->appendFilters($filters);
-
- return $node;
- } else {
- return new Twig_Node_Print(
- new Twig_Node_Expression_Filter($expression, $filters, $node->getLine())
- , $node->getLine()
- );
- }
- }
-
- protected function getCurrentFilters()
- {
- return count($this->statusStack) ? $this->statusStack[count($this->statusStack) - 1] : false;
- }
-}
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+
+/**
+ * Twig_NodeVisitor_Sandbox implements sandboxing.
+ *
+ * @package twig
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id$
+ */
class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
{
protected $inAModule = false;
protected $tags;
protected $filters;
+ /**
+ * Called before child nodes are visited.
+ *
+ * @param Twig_NodeInterface $node The node to visit
+ * @param Twig_Environment $env The Twig environment instance
+ *
+ * @param Twig_NodeInterface The modified node
+ */
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Module) {
} elseif ($this->inAModule) {
// look for tags
if ($node->getNodeTag()) {
- $this->tags[$node->getNodeTag()] = true;
+ $this->tags[] = $node->getNodeTag();
}
// look for filters
if ($node instanceof Twig_Node_Expression_Filter) {
- foreach ($node->getFilters() as $filter) {
- $this->filters[$filter[0]] = true;
+ for ($i = 0; $i < count($node->filters); $i += 2) {
+ $this->filters[] = $node->filters->{$i}['value'];
}
}
- // look for simple print statement ({{ article }})
- if ($node instanceof Twig_Node_Print && $node->getExpression() instanceof Twig_Node_Expression_Name) {
- return new Twig_Node_SandboxPrint($node->getExpression(), $node->getLine(), $node->getNodeTag());
+ // look for simple print statements ({{ article }})
+ if ($node instanceof Twig_Node_Print && $node->expr instanceof Twig_Node_Expression_Name) {
+ return new Twig_Node_SandboxedPrint($node);
}
}
return $node;
}
+ /**
+ * Called after child nodes are visited.
+ *
+ * @param Twig_NodeInterface $node The node to visit
+ * @param Twig_Environment $env The Twig environment instance
+ *
+ * @param Twig_NodeInterface The modified node
+ */
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
{
if ($node instanceof Twig_Node_Module) {
- $node->setUsedFilters(array_keys($this->filters));
- $node->setUsedTags(array_keys($this->tags));
$this->inAModule = false;
+
+ return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags));
}
return $node;
<?php
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2009 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Twig_NodeVisitorInterface is the interface the all node visitor classes must implement.
+ *
+ * @package twig
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id$
+ */
interface Twig_NodeVisitorInterface
{
+ /**
+ * Called before child nodes are visited.
+ *
+ * @param Twig_NodeInterface $node The node to visit
+ * @param Twig_Environment $env The Twig environment instance
+ *
+ * @param Twig_NodeInterface The modified node
+ */
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env);
+ /**
+ * Called after child nodes are visited.
+ *
+ * @param Twig_NodeInterface $node The node to visit
+ * @param Twig_Environment $env The Twig environment instance
+ *
+ * @param Twig_NodeInterface The modified node
+ */
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env);
}
if (!is_null($this->extends)) {
// check that the body only contains block references and empty text nodes
- foreach ($body->getNodes() as $node)
+ foreach ($body as $node)
{
if (
- ($node instanceof Twig_Node_Text && !preg_match('/^\s*$/s', $node->getData()))
+ ($node instanceof Twig_Node_Text && !preg_match('/^\s*$/s', $node['data']))
||
(!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference)
) {
}
foreach ($this->blocks as $block) {
- $block->setParent($this->extends);
+ $block['parent'] = $this->extends;
}
}
- $node = new Twig_Node_Module($body, $this->extends, $this->blocks, $this->macros, $this->stream->getFilename());
+ $node = new Twig_Node_Module($body, $this->extends, new Twig_Node($this->blocks), new Twig_Node($this->macros), $this->stream->getFilename());
- $t = new Twig_NodeTraverser($this->env);
- foreach ($this->visitors as $visitor) {
- $node = $t->traverse($node, $visitor);
- }
+ $traverser = new Twig_NodeTraverser($this->env, $this->visitors);
- return $node;
+ return $traverser->traverse($node);
}
public function subparse($test, $drop_needle = false)
$this->stream->next();
}
- return new Twig_NodeList($rv, $lineno);
+ return new Twig_Node($rv, array(), $lineno);
}
if (!isset($this->handlers[$token->getValue()])) {
}
}
- return new Twig_NodeList($rv, $lineno);
+ return new Twig_Node($rv, array(), $lineno);
}
public function addHandler($name, $class)
return $this->env;
}
- protected function resolveMissingFilter($name)
- {
- throw new Twig_RuntimeError(sprintf('The filter "%s" does not exist', $name));
- }
-
protected function getContext($context, $item)
{
if (isset($context[$item])) {
} else {
$stream->expect(Twig_Token::NAME_TYPE, 'as');
- $body = new Twig_NodeList(array(
+ $body = new Twig_Node(array(
new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno),
));
}
{
public function parse(Twig_Token $token)
{
- $lineno = $token->getLine();
$filters = $this->parser->getExpressionParser()->parseFilterExpressionRaw();
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
- return new Twig_Node_Filter($filters, $body, $lineno, $this->getTag());
+ $name = '_tmp'.rand(10000, 99999);
+ $ref = new Twig_Node_BlockReference($name, $token->getLine(), $this->getTag());
+
+ $block = new Twig_Node_Block($name, $body, $token->getLine());
+ $this->parser->setBlock($name, $block);
+
+ $set = new Twig_Node_Set(true, new Twig_Node(array(new Twig_Node_Expression_AssignName($name, $token->getLine()))), new Twig_Node(array($ref)), $token->getLine(), $this->getTag());
+ $filter = new Twig_Node_Expression_Filter(new Twig_Node_Expression_Name($name, $token->getLine()), $filters, $token->getLine(), $this->getTag());
+ $filter = new Twig_Node_Print($filter, $token->getLine(), $this->getTag());
+
+ return new Twig_Node(array($set, $filter));
}
public function decideBlockEnd($token)
public function parse(Twig_Token $token)
{
$lineno = $token->getLine();
- list($isMultitarget, $item) = $this->parser->getExpressionParser()->parseAssignmentExpression();
+ $targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
$this->parser->getStream()->expect('in');
$seq = $this->parser->getExpressionParser()->parseExpression();
}
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
- return new Twig_Node_For($isMultitarget, $item, $seq, $body, $else, $withLoop, $lineno, $this->getTag());
+ if (count($targets) > 1) {
+ $keyTarget = $targets->{0};
+ $valueTarget = $targets->{1};
+ } else {
+ $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno);
+ $valueTarget = $targets->{0};
+ }
+
+ return new Twig_Node_For($keyTarget, $valueTarget, $seq, $body, $else, $withLoop, $lineno, $this->getTag());
}
public function decideForFork($token)
$expr = $this->parser->getExpressionParser()->parseExpression();
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideIfFork'));
- $tests = array(array($expr, $body));
+ $tests = array($expr, $body);
$else = null;
$end = false;
$expr = $this->parser->getExpressionParser()->parseExpression();
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideIfFork'));
- $tests[] = array($expr, $body);
+ $tests[] = $expr;
+ $tests[] = $body;
break;
case 'endif':
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
- return new Twig_Node_If($tests, $else, $lineno, $this->getTag());
+ return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag());
}
public function decideIfFork($token)
{
public function parse(Twig_Token $token)
{
- $macro = $this->parser->getStream()->expect(Twig_Token::STRING_TYPE)->getValue();
+ $macro = $this->parser->getExpressionParser()->parseExpression();
$this->parser->getStream()->expect('as');
- $var = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue();
+ $var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine());
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag());
{
$expr = $this->parser->getExpressionParser()->parseExpression();
- $sandboxed = false;
- if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'sandboxed')) {
- $this->parser->getStream()->next();
- $sandboxed = true;
- }
-
$variables = null;
if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'with')) {
$this->parser->getStream()->next();
+
$variables = $this->parser->getExpressionParser()->parseExpression();
}
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
- return new Twig_Node_Include($expr, $sandboxed, $variables, $token->getLine(), $this->getTag());
+ return new Twig_Node_Include($expr, $variables, $token->getLine(), $this->getTag());
}
public function getTag()
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2010 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+class Twig_TokenParser_Sandbox extends Twig_TokenParser
+{
+ public function parse(Twig_Token $token)
+ {
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+ $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
+
+ return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag());
+ }
+
+ public function decideBlockEnd($token)
+ {
+ return $token->test('endsandbox');
+ }
+
+ public function getTag()
+ {
+ return 'sandbox';
+ }
+}
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
- list($isMultitarget, $names) = $this->parser->getExpressionParser()->parseAssignmentExpression();
+ $names = $this->parser->getExpressionParser()->parseAssignmentExpression();
$capture = false;
if ($stream->test(Twig_Token::NAME_TYPE, 'as')) {
} else {
$capture = true;
- if ($isMultitarget) {
+ if (count($names) > 1) {
throw new Twig_SyntaxError("When using set with a block, you cannot have a multi-target.", $lineno);
}
throw new Twig_SyntaxError("When using set, you must have the same number of variables and assignements.", $lineno);
}
- return new Twig_Node_Set($isMultitarget, $capture, $names, $values, $lineno, $this->getTag());
+ return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag());
}
public function decideBlockEnd($token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
- $count = false;
+ $count = null;
if (!$stream->test(Twig_Token::BLOCK_END_TYPE)) {
$count = new Twig_Node_Expression_Name($stream->expect(Twig_Token::NAME_TYPE)->getValue(), $lineno);
}
$stream->expect(Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideForFork'));
- $plural = false;
+ $plural = null;
if ('plural' === $stream->next()->getValue()) {
$stream->expect(Twig_Token::BLOCK_END_TYPE);
$plural = $this->parser->subparse(array($this, 'decideForEnd'), true);
- if (false === $count) {
+ if (null === $count) {
throw new Twig_SyntaxError('When a plural is used, you must pass the count as an argument to the "trans" tag', $lineno);
}
}
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
- processIsolation="true"
+ processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="test/Twig/Tests/bootstrap.php"
$this->assertFalse(class_exists('FooBarFoo'), '->autoload() does not try to load classes that does not begin with Twig');
$autoloader = new Twig_Autoloader();
- $this->assertTrue($autoloader->autoload('Twig_Parser'), '->autoload() returns true if it is able to load a class');
- $this->assertFalse($autoloader->autoload('Foo'), '->autoload() returns false if it is not able to load a class');
+ $this->assertNull($autoloader->autoload('Foo'), '->autoload() returns false if it is not able to load a class');
}
}
$this->assertEquals('fooFOOfoo', $twig->loadTemplate('2_basic')->render(self::$params), 'Sandbox does nothing if disabled globally and sandboxed not used for the include');
self::$templates = array(
- '3_basic' => '{{ obj.foo }}{% include "3_included" sandboxed %}{{ obj.foo }}',
+ '3_basic' => '{{ obj.foo }}{% sandbox %}{% include "3_included" %}{% endsandbox %}{{ obj.foo }}',
'3_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
);
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_AutoEscapeTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_AutoEscape::__construct
+ */
+ public function testConstructor()
+ {
+ $body = new Twig_Node(array(new Twig_Node_Text('foo', 0)));
+ $node = new Twig_Node_AutoEscape(true, $body, 0);
+
+ $this->assertEquals($body, $node->body);
+ $this->assertEquals(true, $node['value']);
+ }
+
+ /**
+ * @covers Twig_Node_AutoEscape::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $body = new Twig_Node(array(new Twig_Node_Text('foo', 0)));
+ $node = new Twig_Node_AutoEscape(true, $body, 0);
+
+ return array(
+ array($node, 'echo "foo";'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_BlockReferenceTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_BlockReference::__construct
+ */
+ public function testConstructor()
+ {
+ $node = new Twig_Node_BlockReference('foo', 0);
+
+ $this->assertEquals('foo', $node['name']);
+ }
+
+ /**
+ * @covers Twig_Node_BlockReference::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ return array(
+ array(new Twig_Node_BlockReference('foo', 0), '$this->block_foo($context);'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_BlockTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Block::__construct
+ */
+ public function testConstructor()
+ {
+ $body = new Twig_Node_Text('foo', 0);
+ $node = new Twig_Node_Block('foo', $body, 0);
+
+ $this->assertEquals($body, $node->body);
+ $this->assertEquals('foo', $node['name']);
+ }
+
+ /**
+ * @covers Twig_Node_Block::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $body = new Twig_Node_Text('foo', 0);
+ $node = new Twig_Node_Block('foo', $body, 0);
+
+ return array(
+ array($node, <<<EOF
+public function block_foo(\$context)
+{
+ echo "foo";
+}
+EOF
+ ),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_DebugTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Debug::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Name('foo', 0);
+ $node = new Twig_Node_Debug($expr, 0);
+ $this->assertEquals($expr, $node->expr);
+
+ $node = new Twig_Node_Debug(null, 0);
+ $this->assertEquals(null, $node->expr);
+ }
+
+ /**
+ * @covers Twig_Node_Debug::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $tests[] = array(new Twig_Node_Debug(null, 0), <<<EOF
+if (\$this->env->isDebug()) {
+ var_export(\$context);
+}
+EOF
+ );
+
+ $expr = new Twig_Node_Expression_Name('foo', 0);
+ $node = new Twig_Node_Debug($expr, 0);
+
+ $tests[] = array($node, <<<EOF
+if (\$this->env->isDebug()) {
+ var_export(\$this->getContext(\$context, 'foo'));
+}
+EOF
+ );
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../TestCase.php';
+
+class Twig_Tests_Node_Expression_ArrayTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Array::__construct
+ */
+ public function testConstructor()
+ {
+ $elements = array('foo' => $foo = new Twig_Node_Expression_Constant('bar', 0));
+ $node = new Twig_Node_Expression_Array($elements, 0);
+
+ $this->assertEquals($foo, $node->foo);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Array::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $elements = array(
+ 'foo' => new Twig_Node_Expression_Constant('bar', 0),
+ 'bar' => new Twig_Node_Expression_Constant('foo', 0),
+ );
+ $node = new Twig_Node_Expression_Array($elements, 0);
+
+ return array(
+ array($node, 'array("foo" => "bar", "bar" => "foo")'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../TestCase.php';
+
+class Twig_Tests_Node_Expression_AssignNameTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_AssignName::__construct
+ */
+ public function testConstructor()
+ {
+ $node = new Twig_Node_Expression_AssignName('foo', 0);
+
+ $this->assertEquals('foo', $node['name']);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_AssignName::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $node = new Twig_Node_Expression_AssignName('foo', 0);
+
+ return array(
+ array($node, '$context[\'foo\']'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Binary_AddTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Binary_Add::__construct
+ */
+ public function testConstructor()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Add($left, $right, 0);
+
+ $this->assertEquals($left, $node->left);
+ $this->assertEquals($right, $node->right);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Binary_Add::compile
+ * @covers Twig_Node_Expression_Binary_Add::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Add($left, $right, 0);
+
+ return array(
+ array($node, '(1) + (2)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Binary_AndTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Binary_And::__construct
+ */
+ public function testConstructor()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_And($left, $right, 0);
+
+ $this->assertEquals($left, $node->left);
+ $this->assertEquals($right, $node->right);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Binary_And::compile
+ * @covers Twig_Node_Expression_Binary_And::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_And($left, $right, 0);
+
+ return array(
+ array($node, '(1) && (2)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Binary_ConcatTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Binary_Concat::__construct
+ */
+ public function testConstructor()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Concat($left, $right, 0);
+
+ $this->assertEquals($left, $node->left);
+ $this->assertEquals($right, $node->right);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Binary_Concat::compile
+ * @covers Twig_Node_Expression_Binary_Concat::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Concat($left, $right, 0);
+
+ return array(
+ array($node, '(1) . (2)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Binary_DivTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Binary_Div::__construct
+ */
+ public function testConstructor()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Div($left, $right, 0);
+
+ $this->assertEquals($left, $node->left);
+ $this->assertEquals($right, $node->right);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Binary_Div::compile
+ * @covers Twig_Node_Expression_Binary_Div::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Div($left, $right, 0);
+
+ return array(
+ array($node, '(1) / (2)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Binary_FloorDivTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Binary_FloorDiv::__construct
+ */
+ public function testConstructor()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 0);
+
+ $this->assertEquals($left, $node->left);
+ $this->assertEquals($right, $node->right);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Binary_FloorDiv::compile
+ * @covers Twig_Node_Expression_Binary_FloorDiv::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 0);
+
+ return array(
+ array($node, 'floor((1) / (2))'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Binary_ModTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Binary_Mod::__construct
+ */
+ public function testConstructor()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Mod($left, $right, 0);
+
+ $this->assertEquals($left, $node->left);
+ $this->assertEquals($right, $node->right);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Binary_Mod::compile
+ * @covers Twig_Node_Expression_Binary_Mod::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Mod($left, $right, 0);
+
+ return array(
+ array($node, '(1) % (2)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Binary_MulTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Binary_Mul::__construct
+ */
+ public function testConstructor()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Mul($left, $right, 0);
+
+ $this->assertEquals($left, $node->left);
+ $this->assertEquals($right, $node->right);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Binary_Mul::compile
+ * @covers Twig_Node_Expression_Binary_Mul::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Mul($left, $right, 0);
+
+ return array(
+ array($node, '(1) * (2)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Binary_OrTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Binary_Or::__construct
+ */
+ public function testConstructor()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Or($left, $right, 0);
+
+ $this->assertEquals($left, $node->left);
+ $this->assertEquals($right, $node->right);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Binary_Or::compile
+ * @covers Twig_Node_Expression_Binary_Or::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Or($left, $right, 0);
+
+ return array(
+ array($node, '(1) || (2)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Binary_SubTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Binary_Sub::__construct
+ */
+ public function testConstructor()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Sub($left, $right, 0);
+
+ $this->assertEquals($left, $node->left);
+ $this->assertEquals($right, $node->right);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Binary_Sub::compile
+ * @covers Twig_Node_Expression_Binary_Sub::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $left = new Twig_Node_Expression_Constant(1, 0);
+ $right = new Twig_Node_Expression_Constant(2, 0);
+ $node = new Twig_Node_Expression_Binary_Sub($left, $right, 0);
+
+ return array(
+ array($node, '(1) - (2)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../TestCase.php';
+
+class Twig_Tests_Node_Expression_CompareTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Compare::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Constant(1, 0);
+ $ops = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('>', 0),
+ new Twig_Node_Expression_Constant(2, 0),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Compare($expr, $ops, 0);
+
+ $this->assertEquals($expr, $node->expr);
+ $this->assertEquals($ops, $node->ops);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Compare::compile
+ * @covers Twig_Node_Expression_Compare::compileIn
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $expr = new Twig_Node_Expression_Constant(1, 0);
+ $ops = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('>', 0),
+ new Twig_Node_Expression_Constant(2, 0),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Compare($expr, $ops, 0);
+ $tests[] = array($node, '1 > 2');
+
+ $ops = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('>', 0),
+ new Twig_Node_Expression_Constant(2, 0),
+ new Twig_Node_Expression_Constant('<', 0),
+ new Twig_Node_Expression_Constant(4, 0),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Compare($expr, $ops, 0);
+ $tests[] = array($node, '1 > ($tmp1 = 2) && ($tmp1 < 4)');
+
+ $ops = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('in', 0),
+ new Twig_Node_Expression_Constant(2, 0),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Compare($expr, $ops, 0);
+ $tests[] = array($node, 'twig_in_filter(1, 2)');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../TestCase.php';
+
+class Twig_Tests_Node_Expression_ConditionalTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Conditional::__construct
+ */
+ public function testConstructor()
+ {
+ $expr1 = new Twig_Node_Expression_Constant(1, 0);
+ $expr2 = new Twig_Node_Expression_Constant(2, 0);
+ $expr3 = new Twig_Node_Expression_Constant(3, 0);
+ $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 0);
+
+ $this->assertEquals($expr1, $node->expr1);
+ $this->assertEquals($expr2, $node->expr2);
+ $this->assertEquals($expr3, $node->expr3);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Conditional::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $expr1 = new Twig_Node_Expression_Constant(1, 0);
+ $expr2 = new Twig_Node_Expression_Constant(2, 0);
+ $expr3 = new Twig_Node_Expression_Constant(3, 0);
+ $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 0);
+ $tests[] = array($node, '(1) ? (2) : (3)');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../TestCase.php';
+
+class Twig_Tests_Node_Expression_ConstantTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Constant::__construct
+ */
+ public function testConstructor()
+ {
+ $node = new Twig_Node_Expression_Constant('foo', 0);
+
+ $this->assertEquals('foo', $node['value']);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Constant::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $node = new Twig_Node_Expression_Constant('foo', 0);
+ $tests[] = array($node, '"foo"');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../TestCase.php';
+
+class Twig_Tests_Node_Expression_FilterTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Filter::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $filters = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('upper', 0),
+ new Twig_Node(),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Filter($expr, $filters, 0);
+
+ $this->assertEquals($expr, $node->node);
+ $this->assertEquals($filters, $node->filters);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Filter::hasFilter
+ */
+ public function testHasFilter()
+ {
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $filters = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('upper', 0),
+ new Twig_Node(),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Filter($expr, $filters, 0);
+
+ $this->assertTrue($node->hasFilter('upper'));
+ $this->assertFalse($node->hasFilter('lower'));
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Filter::prependFilter
+ */
+ public function testPrependFilter()
+ {
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $filters = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('upper', 0),
+ new Twig_Node(),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Filter($expr, $filters, 0);
+
+ $a = new Twig_Node_Expression_Constant('lower', 0);
+ $b = new Twig_Node_Expression_Constant('foobar', 0);
+ $node->prependFilter($a, $b);
+
+ $filters = new Twig_Node(array(
+ $a,
+ $b,
+ new Twig_Node_Expression_Constant('upper', 0),
+ new Twig_Node(),
+ ), array(), 0);
+
+ $this->assertEquals($filters, $node->filters);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Filter::appendFilter
+ */
+ public function testAppendFilter()
+ {
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $filters = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('upper', 0),
+ new Twig_Node(),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Filter($expr, $filters, 0);
+
+ $a = new Twig_Node_Expression_Constant('lower', 0);
+ $b = new Twig_Node_Expression_Constant('foobar', 0);
+ $node->appendFilter($a, $b);
+
+ $filters = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('upper', 0),
+ new Twig_Node(),
+ $a,
+ $b,
+ ), array(), 0);
+
+ $this->assertEquals($filters, $node->filters);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Filter::appendFilters
+ */
+ public function testAppendFilters()
+ {
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $filters = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('upper', 0),
+ new Twig_Node(),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Filter($expr, $filters, 0);
+
+ $others = new Twig_Node(array(
+ $a = new Twig_Node_Expression_Constant('lower', 0),
+ $b = new Twig_Node_Expression_Constant('foobar', 0),
+ ), array(), 0);
+ $node->appendFilters($others);
+
+ $filters = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('upper', 0),
+ new Twig_Node(),
+ $a,
+ $b,
+ ), array(), 0);
+
+ $this->assertEquals($filters, $node->filters);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Filter::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $filters = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('foobar', 0),
+ new Twig_Node(array(new Twig_Node_Expression_Constant('bar', 0), new Twig_Node_Expression_Constant('foobar', 0))),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Filter($expr, $filters, 0);
+
+ $tests[] = array($node, '$this->resolveMissingFilter("foobar", array("foo", "bar", "foobar"))');
+
+ try {
+ $node->compile($this->getCompiler());
+ $this->fail();
+ } catch (Exception $e) {
+ $this->assertEquals('Twig_SyntaxError', get_class($e));
+ }
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $filters = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('upper', 0),
+ new Twig_Node(),
+ new Twig_Node_Expression_Constant('lower', 0),
+ new Twig_Node(array(new Twig_Node_Expression_Constant('bar', 0), new Twig_Node_Expression_Constant('foobar', 0))),
+ ), array(), 0);
+ $node = new Twig_Node_Expression_Filter($expr, $filters, 0);
+
+ $tests[] = array($node, 'twig_lower_filter($this->getEnvironment(), twig_upper_filter($this->getEnvironment(), "foo"), "bar", "foobar")');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../TestCase.php';
+
+class Twig_Tests_Node_Expression_GetAttrTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_GetAttr::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Name('foo', 0);
+ $attr = new Twig_Node_Expression_Constant('bar', 0);
+ $args = new Twig_Node(array(
+ new Twig_Node_Expression_Name('foo', 0),
+ new Twig_Node_Expression_Constant('bar', 0),
+ ));
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 0, '[');
+
+ $this->assertEquals($expr, $node->node);
+ $this->assertEquals($attr, $node->attribute);
+ $this->assertEquals($args, $node->arguments);
+ $this->assertEquals('[', $node['token_value']);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_GetAttr::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $expr = new Twig_Node_Expression_Name('foo', 0);
+ $attr = new Twig_Node_Expression_Constant('bar', 0);
+ $args = new Twig_Node();
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 0);
+ $tests[] = array($node, '$this->getAttribute($this->getContext($context, \'foo\'), "bar", array())');
+
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 0, '[');
+ $tests[] = array($node, '$this->getAttribute($this->getContext($context, \'foo\'), "bar", array(), true)');
+
+ $args = new Twig_Node(array(
+ new Twig_Node_Expression_Name('foo', 0),
+ new Twig_Node_Expression_Constant('bar', 0),
+ ));
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 0);
+ $tests[] = array($node, '$this->getAttribute($this->getContext($context, \'foo\'), "bar", array($this->getContext($context, \'foo\'), "bar", ))');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../TestCase.php';
+
+class Twig_Tests_Node_Expression_NameTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Name::__construct
+ */
+ public function testConstructor()
+ {
+ $node = new Twig_Node_Expression_Name('foo', 0);
+
+ $this->assertEquals('foo', $node['name']);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Name::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $node = new Twig_Node_Expression_Name('foo', 0);
+
+ return array(
+ array($node, '$this->getContext($context, \'foo\')'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Unary_NegTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Unary_Neg::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Constant(1, 0);
+ $node = new Twig_Node_Expression_Unary_Neg($expr, 0);
+
+ $this->assertEquals($expr, $node->node);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Unary_Neg::compile
+ * @covers Twig_Node_Expression_Unary_Neg::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $node = new Twig_Node_Expression_Constant(1, 0);
+ $node = new Twig_Node_Expression_Unary_Neg($node, 0);
+
+ return array(
+ array($node, '(-1)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Unary_NotTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Unary_Not::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Constant(1, 0);
+ $node = new Twig_Node_Expression_Unary_Not($expr, 0);
+
+ $this->assertEquals($expr, $node->node);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Unary_Not::compile
+ * @covers Twig_Node_Expression_Unary_Not::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $node = new Twig_Node_Expression_Constant(1, 0);
+ $node = new Twig_Node_Expression_Unary_Not($node, 0);
+
+ return array(
+ array($node, '(!1)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/../../TestCase.php';
+
+class Twig_Tests_Node_Expression_Unary_PosTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Expression_Unary_Pos::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Constant(1, 0);
+ $node = new Twig_Node_Expression_Unary_Pos($expr, 0);
+
+ $this->assertEquals($expr, $node->node);
+ }
+
+ /**
+ * @covers Twig_Node_Expression_Unary_Pos::compile
+ * @covers Twig_Node_Expression_Unary_Pos::operator
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $node = new Twig_Node_Expression_Constant(1, 0);
+ $node = new Twig_Node_Expression_Unary_Pos($node, 0);
+
+ return array(
+ array($node, '(+1)'),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_ForTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_For::__construct
+ */
+ public function testConstructor()
+ {
+ $keyTarget = new Twig_Node_Expression_AssignName('key', 0);
+ $valueTarget = new Twig_Node_Expression_AssignName('item', 0);
+ $seq = new Twig_Node_Expression_Name('items', 0);
+ $body = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0);
+ $else = null;
+ $withLoop = false;
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $body, $else, $withLoop, 0);
+
+ $this->assertEquals($keyTarget, $node->key_target);
+ $this->assertEquals($valueTarget, $node->value_target);
+ $this->assertEquals($seq, $node->seq);
+ $this->assertEquals($body, $node->body);
+ $this->assertEquals(null, $node->else);
+
+ $this->assertEquals($withLoop, $node['with_loop']);
+
+ $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0);
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $body, $else, $withLoop, 0);
+ $this->assertEquals($else, $node->else);
+ }
+
+ /**
+ * @covers Twig_Node_For::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $keyTarget = new Twig_Node_Expression_AssignName('key', 0);
+ $valueTarget = new Twig_Node_Expression_AssignName('item', 0);
+ $seq = new Twig_Node_Expression_Name('items', 0);
+ $body = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0);
+ $else = null;
+ $withLoop = false;
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $body, $else, $withLoop, 0);
+
+ $tests[] = array($node, <<<EOF
+\$context['_parent'] = (array) \$context;
+\$context['_seq'] = twig_iterator_to_array(\$this->getContext(\$context, 'items'), true);
+foreach (\$context['_seq'] as \$context['key'] => \$context['item']) {
+ echo \$this->getContext(\$context, 'foo');
+}
+\$_parent = \$context['_parent'];
+unset(\$context['_seq'], \$context['_iterated'], \$context['key'], \$context['item'], \$context['_parent'], \$context['loop']);
+\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent));
+EOF
+ );
+
+ $keyTarget = new Twig_Node_Expression_AssignName('k', 0);
+ $valueTarget = new Twig_Node_Expression_AssignName('v', 0);
+ $seq = new Twig_Node_Expression_Name('values', 0);
+ $body = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0);
+ $else = null;
+ $withLoop = true;
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $body, $else, $withLoop, 0);
+
+ $tests[] = array($node, <<<EOF
+\$context['_parent'] = (array) \$context;
+\$context['_seq'] = twig_iterator_to_array(\$this->getContext(\$context, 'values'), true);
+\$length = count(\$context['_seq']);
+\$context['loop'] = array(
+ 'parent' => \$context['_parent'],
+ 'length' => \$length,
+ 'index0' => 0,
+ 'index' => 1,
+ 'revindex0' => \$length - 1,
+ 'revindex' => \$length,
+ 'first' => true,
+ 'last' => 1 === \$length,
+);
+foreach (\$context['_seq'] as \$context['k'] => \$context['v']) {
+ echo \$this->getContext(\$context, 'foo');
+ ++\$context['loop']['index0'];
+ ++\$context['loop']['index'];
+ --\$context['loop']['revindex0'];
+ --\$context['loop']['revindex'];
+ \$context['loop']['first'] = false;
+ \$context['loop']['last'] = 0 === \$context['loop']['revindex0'];
+}
+\$_parent = \$context['_parent'];
+unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
+\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent));
+EOF
+ );
+
+ $keyTarget = new Twig_Node_Expression_AssignName('k', 0);
+ $valueTarget = new Twig_Node_Expression_AssignName('v', 0);
+ $seq = new Twig_Node_Expression_Name('values', 0);
+ $body = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0);
+ $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0);
+ $withLoop = true;
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $body, $else, $withLoop, 0);
+
+ $tests[] = array($node, <<<EOF
+\$context['_parent'] = (array) \$context;
+\$context['_iterated'] = false;
+\$context['_seq'] = twig_iterator_to_array(\$this->getContext(\$context, 'values'), true);
+\$length = count(\$context['_seq']);
+\$context['loop'] = array(
+ 'parent' => \$context['_parent'],
+ 'length' => \$length,
+ 'index0' => 0,
+ 'index' => 1,
+ 'revindex0' => \$length - 1,
+ 'revindex' => \$length,
+ 'first' => true,
+ 'last' => 1 === \$length,
+);
+foreach (\$context['_seq'] as \$context['k'] => \$context['v']) {
+ \$context['_iterated'] = true;
+ echo \$this->getContext(\$context, 'foo');
+ ++\$context['loop']['index0'];
+ ++\$context['loop']['index'];
+ --\$context['loop']['revindex0'];
+ --\$context['loop']['revindex'];
+ \$context['loop']['first'] = false;
+ \$context['loop']['last'] = 0 === \$context['loop']['revindex0'];
+}
+if (!\$context['_iterated']) {
+ echo \$this->getContext(\$context, 'foo');
+}
+\$_parent = \$context['_parent'];
+unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
+\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent));
+EOF
+ );
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_IfTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_If::__construct
+ */
+ public function testConstructor()
+ {
+ $t = new Twig_Node(array(
+ new Twig_Node_Expression_Constant(true, 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0),
+ ), array(), 0);
+ $else = null;
+ $node = new Twig_Node_If($t, $else, 0);
+
+ $this->assertEquals($t, $node->tests);
+ $this->assertEquals(null, $node->else);
+
+ $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 0), 0);
+ $node = new Twig_Node_If($t, $else, 0);
+ $this->assertEquals($else, $node->else);
+ }
+
+ /**
+ * @covers Twig_Node_If::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $t = new Twig_Node(array(
+ new Twig_Node_Expression_Constant(true, 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0),
+ ), array(), 0);
+ $else = null;
+ $node = new Twig_Node_If($t, $else, 0);
+
+ $tests[] = array($node, <<<EOF
+if (true) {
+ echo \$this->getContext(\$context, 'foo');
+}
+EOF
+ );
+
+ $t = new Twig_Node(array(
+ new Twig_Node_Expression_Constant(true, 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0),
+ new Twig_Node_Expression_Constant(false, 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 0), 0),
+ ), array(), 0);
+ $else = null;
+ $node = new Twig_Node_If($t, $else, 0);
+
+ $tests[] = array($node, <<<EOF
+if (true) {
+ echo \$this->getContext(\$context, 'foo');
+} elseif (false) {
+ echo \$this->getContext(\$context, 'bar');
+}
+EOF
+ );
+
+ $t = new Twig_Node(array(
+ new Twig_Node_Expression_Constant(true, 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0),
+ ), array(), 0);
+ $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 0), 0);
+ $node = new Twig_Node_If($t, $else, 0);
+
+ $tests[] = array($node, <<<EOF
+if (true) {
+ echo \$this->getContext(\$context, 'foo');
+} else {
+ echo \$this->getContext(\$context, 'bar');
+}
+EOF
+ );
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_ImportTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Import::__construct
+ */
+ public function testConstructor()
+ {
+ $macro = new Twig_Node_Expression_Constant('foo.twig', 0);
+ $var = new Twig_Node_Expression_AssignName('macro', 0);
+ $node = new Twig_Node_Import($macro, $var, 0);
+
+ $this->assertEquals($macro, $node->expr);
+ $this->assertEquals($var, $node->var);
+ }
+
+ /**
+ * @covers Twig_Node_Import::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $macro = new Twig_Node_Expression_Constant('foo.twig', 0);
+ $var = new Twig_Node_Expression_AssignName('macro', 0);
+ $node = new Twig_Node_Import($macro, $var, 0);
+
+ $tests[] = array($node, '$context[\'macro\'] = $this->env->loadTemplate("foo.twig", true);');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_IncludeTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Include::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Constant('foo.twig', 0);
+ $node = new Twig_Node_Include($expr, null, 0);
+
+ $this->assertEquals(null, $node->variables);
+ $this->assertEquals($expr, $node->expr);
+
+ $vars = new Twig_Node_Expression_Array(array('foo' => new Twig_Node_Expression_Constant(true, 0)), 0);
+ $node = new Twig_Node_Include($expr, $vars, 0);
+ $this->assertEquals($vars, $node->variables);
+ }
+
+ /**
+ * @covers Twig_Node_Include::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $expr = new Twig_Node_Expression_Constant('foo.twig', 0);
+ $node = new Twig_Node_Include($expr, null, 0);
+ $tests[] = array($node, '$this->env->loadTemplate("foo.twig")->display($context);');
+
+ $expr = new Twig_Node_Expression_Constant('foo.twig', 0);
+ $vars = new Twig_Node_Expression_Array(array('foo' => new Twig_Node_Expression_Constant(true, 0)), 0);
+ $node = new Twig_Node_Include($expr, $vars, 0);
+ $tests[] = array($node, '$this->env->loadTemplate("foo.twig")->display(array("foo" => true));');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_MacroTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Macro::__construct
+ */
+ public function testConstructor()
+ {
+ $body = new Twig_Node_Text('foo', 0);
+ $arguments = new Twig_Node(array(new Twig_Node_Expression_Name('foo', 0)), array(), 0);
+ $node = new Twig_Node_Macro('foo', $body, $arguments, 0);
+
+ $this->assertEquals($body, $node->body);
+ $this->assertEquals($arguments, $node->arguments);
+ $this->assertEquals('foo', $node['name']);
+ }
+
+ /**
+ * @covers Twig_Node_Macro::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $body = new Twig_Node_Text('foo', 0);
+ $arguments = new Twig_Node(array(new Twig_Node_Expression_Name('foo', 0)), array(), 0);
+ $node = new Twig_Node_Macro('foo', $body, $arguments, 0);
+
+ return array(
+ array($node, <<<EOF
+public function getfoo(\$foo = null)
+{
+ \$context = array(
+ "foo" => \$foo,
+ );
+
+ echo "foo";
+}
+EOF
+ ),
+ );
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_ModuleTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Module::__construct
+ */
+ public function testConstructor()
+ {
+ $body = new Twig_Node_Text('foo', 0);
+ $extends = 'layout.twig';
+ $blocks = new Twig_Node();
+ $macros = new Twig_Node();
+ $filename = 'foo.twig';
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $filename);
+
+ $this->assertEquals($body, $node->body);
+ $this->assertEquals($blocks, $node->blocks);
+ $this->assertEquals($macros, $node->macros);
+ $this->assertEquals($filename, $node['filename']);
+ $this->assertEquals($extends, $node['extends']);
+ }
+
+ /**
+ * @covers Twig_Node_Module::compile
+ * @covers Twig_Node_Module::compileTemplate
+ * @covers Twig_Node_Module::compileMacros
+ * @covers Twig_Node_Module::compileClassHeader
+ * @covers Twig_Node_Module::compileDisplayHeader
+ * @covers Twig_Node_Module::compileDisplayBody
+ * @covers Twig_Node_Module::compileDisplayFooter
+ * @covers Twig_Node_Module::compileGetName
+ * @covers Twig_Node_Module::compileClassFooter
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $twig = new Twig_Environment(new Twig_Loader_String());
+
+ $tests = array();
+
+ $body = new Twig_Node_Text('foo', 0);
+ $extends = null;
+ $blocks = new Twig_Node();
+ $macros = new Twig_Node();
+ $filename = 'foo.twig';
+
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $filename);
+ $tests[] = array($node, <<<EOF
+<?php
+
+/* foo.twig */
+class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
+{
+ public function display(array \$context)
+ {
+ echo "foo";
+ }
+
+ public function getName()
+ {
+ return "foo.twig";
+ }
+
+}
+
+class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
+{
+}
+EOF
+ , $twig);
+
+ $import = new Twig_Node_Import(new Twig_Node_Expression_Constant('foo.twig', 0), new Twig_Node_Expression_AssignName('macro', 0), 0);
+
+ $body = new Twig_Node(array($import, new Twig_Node_Text('foo', 0)));
+ $extends = 'layout.twig';
+ $blocks = new Twig_Node();
+ $macros = new Twig_Node();
+ $filename = 'foo.twig';
+
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $filename);
+ $tests[] = array($node, <<<EOF
+<?php
+
+\$this->loadTemplate("layout.twig");
+
+/* foo.twig */
+class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends __TwigTemplate_d8fb9d03f55738ff78518e1bc2741faf
+{
+ public function display(array \$context)
+ {
+ \$context['macro'] = \$this->env->loadTemplate("foo.twig", true);
+
+ parent::display(\$context);
+ }
+
+ public function getName()
+ {
+ return "foo.twig";
+ }
+
+}
+
+class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
+{
+}
+EOF
+ , $twig);
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_ParentTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Parent::__construct
+ */
+ public function testConstructor()
+ {
+ $node = new Twig_Node_Parent('foo', 0);
+
+ $this->assertEquals('foo', $node['name']);
+ }
+
+ /**
+ * @covers Twig_Node_Parent::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+ $tests[] = array(new Twig_Node_Parent('foo', 0), 'parent::block_foo($context);');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_PrintTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Print::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $node = new Twig_Node_Print($expr, 0);
+
+ $this->assertEquals($expr, $node->expr);
+ }
+
+ /**
+ * @covers Twig_Node_Print::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+ $tests[] = array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 0), 0), 'echo "foo";');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_SandboxTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Sandbox::__construct
+ */
+ public function testConstructor()
+ {
+ $body = new Twig_Node_Text('foo', 0);
+ $node = new Twig_Node_Sandbox($body, 0);
+
+ $this->assertEquals($body, $node->body);
+ }
+
+ /**
+ * @covers Twig_Node_Sandbox::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $body = new Twig_Node_Text('foo', 0);
+ $node = new Twig_Node_Sandbox($body, 0);
+
+ $tests[] = array($node, <<<EOF
+\$sandbox = \$this->env->getExtension('sandbox');
+if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {
+ \$sandbox->enableSandbox();
+}
+echo "foo";
+if (!\$alreadySandboxed) {
+ \$sandbox->disableSandbox();
+}
+EOF
+ );
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_SandboxedModuleTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_SandboxedModule::__construct
+ */
+ public function testConstructor()
+ {
+ $body = new Twig_Node_Text('foo', 0);
+ $extends = 'layout.twig';
+ $blocks = new Twig_Node();
+ $macros = new Twig_Node();
+ $filename = 'foo.twig';
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $filename);
+ $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'));
+
+ $this->assertEquals($body, $node->body);
+ $this->assertEquals($blocks, $node->blocks);
+ $this->assertEquals($macros, $node->macros);
+ $this->assertEquals($filename, $node['filename']);
+ $this->assertEquals($extends, $node['extends']);
+ }
+
+ /**
+ * @covers Twig_Node_SandboxedModule::compile
+ * @covers Twig_Node_SandboxedModule::compileDisplayBody
+ * @covers Twig_Node_SandboxedModule::compileDisplayFooter
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $twig = new Twig_Environment(new Twig_Loader_String());
+
+ $tests = array();
+
+ $body = new Twig_Node_Text('foo', 0);
+ $extends = null;
+ $blocks = new Twig_Node();
+ $macros = new Twig_Node();
+ $filename = 'foo.twig';
+
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $filename);
+ $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'));
+
+ $tests[] = array($node, <<<EOF
+<?php
+
+/* foo.twig */
+class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
+{
+ public function display(array \$context)
+ {
+ \$this->checkSecurity();
+ echo "foo";
+ }
+
+ protected function checkSecurity() {
+ \$this->env->getExtension('sandbox')->checkSecurity(
+ array('upper'),
+ array('for')
+ );
+ }
+
+ public function getName()
+ {
+ return "foo.twig";
+ }
+
+}
+
+class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
+{
+}
+EOF
+ , $twig);
+
+ $body = new Twig_Node_Text('foo', 0);
+ $extends = 'layout.twig';
+ $blocks = new Twig_Node();
+ $macros = new Twig_Node();
+ $filename = 'foo.twig';
+
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $filename);
+ $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'));
+
+ $tests[] = array($node, <<<EOF
+<?php
+
+\$this->loadTemplate("layout.twig");
+
+/* foo.twig */
+class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends __TwigTemplate_d8fb9d03f55738ff78518e1bc2741faf
+{
+ public function display(array \$context)
+ {
+
+ parent::display(\$context);
+ }
+
+ protected function checkSecurity() {
+ \$this->env->getExtension('sandbox')->checkSecurity(
+ array('upper'),
+ array('for')
+ );
+
+ parent::checkSecurity();
+ }
+
+ public function getName()
+ {
+ return "foo.twig";
+ }
+
+}
+
+class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
+{
+}
+EOF
+ , $twig);
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_SandboxedPrintTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_SandboxedPrint::__construct
+ */
+ public function testConstructor()
+ {
+ $expr = new Twig_Node_Expression_Constant('foo', 0);
+ $node = new Twig_Node_Print($expr, 0);
+ $node = new Twig_Node_SandboxedPrint($node);
+
+ $this->assertEquals($expr, $node->expr);
+ }
+
+ /**
+ * @covers Twig_Node_SandboxedPrint::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $node = new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 0), 0);
+ $tests[] = array(new Twig_Node_SandboxedPrint($node), <<<EOF
+if (\$this->env->hasExtension('sandbox') && is_object("foo")) {
+ \$this->env->getExtension('sandbox')->checkMethodAllowed("foo", '__toString');
+}
+echo "foo";
+EOF
+ );
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_SetTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Set::__construct
+ */
+ public function testConstructor()
+ {
+ $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 0)), array(), 0);
+ $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 0)), array(), 0);
+ $node = new Twig_Node_Set(false, $names, $values, 0);
+
+ $this->assertEquals($names, $node->names);
+ $this->assertEquals($values, $node->values);
+ $this->assertEquals(false, $node['capture']);
+ }
+
+ /**
+ * @covers Twig_Node_Set::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 0)), array(), 0);
+ $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 0)), array(), 0);
+ $node = new Twig_Node_Set(false, $names, $values, 0);
+ $tests[] = array($node, '$context[\'foo\'] = "foo";');
+
+ $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 0)), array(), 0);
+ $values = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 0), 0)), array(), 0);
+ $node = new Twig_Node_Set(true, $names, $values, 0);
+ $tests[] = array($node, <<<EOF
+ob_start();
+echo "foo";
+\$context['foo'] = ob_get_clean();
+EOF
+ );
+
+ $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 0), new Twig_Node_Expression_AssignName('bar', 0)), array(), 0);
+ $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 0), new Twig_Node_Expression_Name('bar', 0)), array(), 0);
+ $node = new Twig_Node_Set(false, $names, $values, 0);
+ $tests[] = array($node, <<<EOF
+list(\$context['foo'], \$context['bar']) = array("foo", \$this->getContext(\$context, 'bar'));
+EOF
+ );
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+abstract class Twig_Tests_Node_TestCase extends PHPUnit_Framework_TestCase
+{
+ abstract public function getTests();
+
+ /**
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ $this->assertNodeCompilation($source, $node, $environment);
+ }
+
+ public function assertNodeCompilation($source, Twig_Node $node, Twig_Environment $environment = null)
+ {
+ $compiler = $this->getCompiler($environment);
+ $compiler->compile($node);
+
+ $this->assertEquals($source, trim($compiler->getSource()));
+ }
+
+ protected function getCompiler(Twig_Environment $environment = null)
+ {
+ return new Twig_Compiler(null === $environment ? $this->getEnvironment() : $environment);
+ }
+
+ protected function getEnvironment()
+ {
+ return new Twig_Environment();
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_TextTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Text::__construct
+ */
+ public function testConstructor()
+ {
+ $node = new Twig_Node_Text('foo', 0);
+
+ $this->assertEquals('foo', $node['data']);
+ }
+
+ /**
+ * @covers Twig_Node_Text::compile
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+ $tests[] = array(new Twig_Node_Text('foo', 0), 'echo "foo";');
+
+ return $tests;
+ }
+}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once dirname(__FILE__).'/TestCase.php';
+
+class Twig_Tests_Node_TransTest extends Twig_Tests_Node_TestCase
+{
+ /**
+ * @covers Twig_Node_Trans::__construct
+ */
+ public function testConstructor()
+ {
+ $count = new Twig_Node_Expression_Constant(12, 0);
+ $body = new Twig_Node(array(
+ new Twig_Node_Text('Hello', 0),
+ ), array(), 0);
+ $plural = new Twig_Node(array(
+ new Twig_Node_Text('Hey ', 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('name', 0), 0),
+ new Twig_Node_Text(', I have ', 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('count', 0), 0),
+ new Twig_Node_Text(' apples', 0),
+ ), array(), 0);
+ $node = new Twig_Node_Trans($count, $body, $plural, 0);
+
+ $this->assertEquals($body, $node->body);
+ $this->assertEquals($count, $node->count);
+ $this->assertEquals($plural, $node->plural);
+ }
+
+ /**
+ * @covers Twig_Node_Trans::compile
+ * @covers Twig_Node_Trans::compileString
+ * @dataProvider getTests
+ */
+ public function testCompile($node, $source, $environment = null)
+ {
+ parent::testCompile($node, $source, $environment);
+
+ $body = new Twig_Node(array(
+ new Twig_Node_Expression_Constant('Hello', 0),
+ ), array(), 0);
+ $node = new Twig_Node_Trans(null, $body, null, 0);
+
+ try {
+ $node->compile($this->getCompiler());
+ $this->fail();
+ } catch (Exception $e) {
+ $this->assertEquals('Twig_SyntaxError', get_class($e));
+ }
+ }
+
+ public function getTests()
+ {
+ $tests = array();
+
+ $body = new Twig_Node(array(
+ new Twig_Node_Text('Hello', 0),
+ ), array(), 0);
+ $node = new Twig_Node_Trans(null, $body, null, 0);
+ $tests[] = array($node, 'echo gettext("Hello");');
+
+ $body = new Twig_Node(array(
+ new Twig_Node_Text('J\'ai ', 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0),
+ new Twig_Node_Text(' pommes', 0),
+ ), array(), 0);
+ $node = new Twig_Node_Trans(null, $body, null, 0);
+ $tests[] = array($node, 'echo strtr(gettext("J\'ai %foo% pommes"), array("%foo%" => $this->getContext($context, \'foo\'), ));');
+
+ $count = new Twig_Node_Expression_Constant(12, 0);
+ $body = new Twig_Node(array(
+ new Twig_Node_Text('Hey ', 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('name', 0), 0),
+ new Twig_Node_Text(', I have one apple', 0),
+ ), array(), 0);
+ $plural = new Twig_Node(array(
+ new Twig_Node_Text('Hey ', 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('name', 0), 0),
+ new Twig_Node_Text(', I have ', 0),
+ new Twig_Node_Print(new Twig_Node_Expression_Name('count', 0), 0),
+ new Twig_Node_Text(' apples', 0),
+ ), array(), 0);
+ $node = new Twig_Node_Trans($count, $body, $plural, 0);
+ $tests[] = array($node, 'echo strtr(ngettext("Hey %name%, I have one apple", "Hey %name%, I have %count% apples", abs(12)), array("%name%" => $this->getContext($context, \'name\'), "%name%" => $this->getContext($context, \'name\'), "%count%" => abs(12), ));');
+
+ return $tests;
+ }
+}
class Twig_Tests_IntegrationTest extends PHPUnit_Framework_TestCase
{
- static protected $fixturesDir;
-
- public function setUp()
+ public function getTests()
{
- self::$fixturesDir = realpath(dirname(__FILE__).'/../../fixtures/');
- }
+ $fixturesDir = realpath(dirname(__FILE__).'/../../fixtures/');
+ $tests = array();
- public function testIntegration()
- {
- foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(self::$fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
+ foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if (!preg_match('/\.test$/', $file)) {
continue;
}
$test = file_get_contents($file->getRealpath());
if (!preg_match('/--TEST--\s*(.*?)\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) {
- throw new InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace(self::$fixturesDir.'/', '', $file)));
+ throw new InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file)));
}
$message = $match[1];
$templates[($match[1] ? $match[1] : 'index.twig')] = $match[2];
}
- $loader = new Twig_Loader_Array($templates);
- $twig = new Twig_Environment($loader, array('trim_blocks' => true, 'cache' => false));
- $twig->addExtension(new Twig_Extension_Escaper());
- $twig->addExtension(new TestExtension());
+ $tests[] = array(str_replace($fixturesDir.'/', '', $file), $test, $message, $templates);
+ }
- try {
- $template = $twig->loadTemplate('index.twig');
- } catch (Twig_SyntaxError $e) {
- $e->setFilename(str_replace(self::$fixturesDir.'/', '', $file));
+ return $tests;
+ }
- throw $e;
- } catch (Exception $e) {
- throw new Twig_Error($e->getMessage().' (in '.str_replace(self::$fixturesDir, '', $file).')');
- }
+ /**
+ * @dataProvider getTests
+ */
+ public function testIntegration($file, $test, $message, $templates)
+ {
+ $loader = new Twig_Loader_Array($templates);
+ $twig = new Twig_Environment($loader, array('trim_blocks' => true, 'cache' => false));
+ $twig->addExtension(new Twig_Extension_Escaper());
+ $twig->addExtension(new TestExtension());
+
+ try {
+ $template = $twig->loadTemplate('index.twig');
+ } catch (Twig_SyntaxError $e) {
+ $e->setFilename($file);
+
+ throw $e;
+ } catch (Exception $e) {
+ throw new Twig_Error($e->getMessage().' (in '.$file.')');
+ }
- preg_match_all('/--DATA--(.*?)--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $matches, PREG_SET_ORDER);
- foreach ($matches as $match) {
- $output = trim($template->render(eval($match[1].';')), "\n ");
- $expected = trim($match[2], "\n ");
+ preg_match_all('/--DATA--(.*?)--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $matches, PREG_SET_ORDER);
+ foreach ($matches as $match) {
+ $output = trim($template->render(eval($match[1].';')), "\n ");
+ $expected = trim($match[2], "\n ");
- $this->assertEquals($expected, $output, $message.' (in '.str_replace(self::$fixturesDir, '', $file).')');
- if ($output != $expected) {
- echo 'Compiled template that failed:';
+ $this->assertEquals($expected, $output, $message.' (in '.$file.')');
+ if ($output != $expected) {
+ echo 'Compiled template that failed:';
- foreach (array_keys($templates) as $name) {
- $source = $loader->getSource($name);
- echo $twig->compile($twig->parse($twig->tokenize($source, $name)));
- }
+ foreach (array_keys($templates) as $name) {
+ $source = $loader->getSource($name);
+ echo $twig->compile($twig->parse($twig->tokenize($source, $name)));
}
}
}
--TEST--
"filter" tags accept multiple chained filters
--TEMPLATE--
-{% filter lower|capitalize %}
+{% filter lower|title %}
{{ var }}
{% endfilter %}
--DATA--
--TEST--
"filter" tags can be nested at will
--TEMPLATE--
-{% filter capitalize %}
+{% filter lower|title %}
{{ var }}
{% filter upper %}
{{ var }}
return array('var' => 'var')
--EXPECT--
Var
- VAR
+ Var
Var