mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-16 04:16:28 +00:00
refactored node transformers to node visitors
git-svn-id: http://svn.twig-project.org/trunk@201 93ef8e89-cb99-4229-a87c-7fa0fa45744b
This commit is contained in:
@@ -12,6 +12,11 @@ environment constant by the "needs_environment" option:
|
||||
'even' => new Twig_Filter_Function('twig_is_even_filter'),
|
||||
'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)),
|
||||
|
||||
If you have used the undocumented NodeTransformer classes, you will need to
|
||||
upgrade to the new interface (please not that the interface is not yet stable).
|
||||
|
||||
* refactored node transformers to node visitors
|
||||
* fixed automatic-escaping for blocks
|
||||
* added a way to specify variables to pass to an included template
|
||||
* changed the automatic-escaping rules to be more sensible and more configurable in custom filters (the documentation lists all the rules)
|
||||
* improved the filter system to allow object methods to be used as filters
|
||||
|
||||
@@ -25,7 +25,7 @@ class Twig_Environment
|
||||
protected $baseTemplateClass;
|
||||
protected $extensions;
|
||||
protected $parsers;
|
||||
protected $transformers;
|
||||
protected $visitors;
|
||||
protected $filters;
|
||||
protected $runtimeInitialized;
|
||||
protected $loadedTemplates;
|
||||
@@ -353,18 +353,18 @@ class Twig_Environment
|
||||
return $this->parsers;
|
||||
}
|
||||
|
||||
public function getNodeTransformers()
|
||||
public function getNodeVisitors()
|
||||
{
|
||||
if (null === $this->transformers)
|
||||
if (null === $this->visitors)
|
||||
{
|
||||
$this->transformers = array();
|
||||
$this->visitors = array();
|
||||
foreach ($this->getExtensions() as $extension)
|
||||
{
|
||||
$this->transformers = array_merge($this->transformers, $extension->getNodeTransformers());
|
||||
$this->visitors = array_merge($this->visitors, $extension->getNodeVisitors());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->transformers;
|
||||
return $this->visitors;
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
|
||||
@@ -30,11 +30,11 @@ abstract class Twig_Extension implements Twig_ExtensionInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node transformer instances to add to the existing list.
|
||||
* Returns the node visitor instances to add to the existing list.
|
||||
*
|
||||
* @return array An array of Twig_NodeTransformer instances
|
||||
* @return array An array of Twig_NodeVisitorInterface instances
|
||||
*/
|
||||
public function getNodeTransformers()
|
||||
public function getNodeVisitors()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
@@ -43,13 +43,15 @@ class Twig_Extension_Core extends Twig_Extension
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node transformer instances to add to the existing list.
|
||||
* Returns the node visitor instances to add to the existing list.
|
||||
*
|
||||
* @return array An array of Twig_NodeTransformer instances
|
||||
* @return array An array of Twig_NodeVisitorInterface instances
|
||||
*/
|
||||
public function getNodeTransformers()
|
||||
public function getNodeVisitors()
|
||||
{
|
||||
return array(new Twig_NodeTransformer_Filter());
|
||||
return array(
|
||||
new Twig_NodeVisitor_Filter(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,13 +37,13 @@ class Twig_Extension_Escaper extends Twig_Extension
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node transformer instances to add to the existing list.
|
||||
* Returns the node visitor instances to add to the existing list.
|
||||
*
|
||||
* @return array An array of Twig_NodeTransformer instances
|
||||
* @return array An array of Twig_NodeVisitorInterface instances
|
||||
*/
|
||||
public function getNodeTransformers()
|
||||
public function getNodeVisitors()
|
||||
{
|
||||
return array(new Twig_NodeTransformer_Escaper());
|
||||
return array(new Twig_NodeVisitor_Escaper());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ class Twig_Extension_Escaper extends Twig_Extension
|
||||
}
|
||||
}
|
||||
|
||||
// tells the escaper node transformer that the string is safe
|
||||
// tells the escaper node visitor that the string is safe
|
||||
function twig_safe_filter($string)
|
||||
{
|
||||
return $string;
|
||||
|
||||
@@ -21,13 +21,13 @@ class Twig_Extension_Sandbox extends Twig_Extension
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node transformer instances to add to the existing list.
|
||||
* Returns the node visitor instances to add to the existing list.
|
||||
*
|
||||
* @return array An array of Twig_NodeTransformer instances
|
||||
* @return array An array of Twig_NodeVisitorInterface instances
|
||||
*/
|
||||
public function getNodeTransformers()
|
||||
public function getNodeVisitors()
|
||||
{
|
||||
return array(new Twig_NodeTransformer_Sandbox());
|
||||
return array(new Twig_NodeVisitor_Sandbox());
|
||||
}
|
||||
|
||||
public function enableSandbox()
|
||||
|
||||
@@ -33,11 +33,11 @@ interface Twig_ExtensionInterface
|
||||
public function getTokenParsers();
|
||||
|
||||
/**
|
||||
* Returns the node transformer instances to add to the existing list.
|
||||
* Returns the node visitor instances to add to the existing list.
|
||||
*
|
||||
* @return array An array of Twig_NodeTransformer instances
|
||||
* @return array An array of Twig_NodeVisitorInterface instances
|
||||
*/
|
||||
public function getNodeTransformers();
|
||||
public function getNodeVisitors();
|
||||
|
||||
/**
|
||||
* Returns a list of filters to add to the existing list.
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<?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.
|
||||
*/
|
||||
abstract class Twig_NodeTransformer
|
||||
{
|
||||
protected $env;
|
||||
|
||||
public function setEnvironment(Twig_Environment $env)
|
||||
{
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
abstract public function visit(Twig_Node $node);
|
||||
|
||||
protected function visitDeep(Twig_Node $node)
|
||||
{
|
||||
if (!$node instanceof Twig_NodeListInterface)
|
||||
{
|
||||
return $node;
|
||||
}
|
||||
|
||||
$newNodes = array();
|
||||
foreach ($nodes = $node->getNodes() as $k => $n)
|
||||
{
|
||||
if (null !== $n = $this->visit($n))
|
||||
{
|
||||
$newNodes[$k] = $n;
|
||||
}
|
||||
}
|
||||
|
||||
$node->setNodes($newNodes);
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?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_NodeTransformer_Chain extends Twig_NodeTransformer
|
||||
{
|
||||
protected $transformers;
|
||||
|
||||
public function __construct(array $transformers)
|
||||
{
|
||||
$this->transformers = $transformers;
|
||||
}
|
||||
|
||||
public function setEnvironment(Twig_Environment $env)
|
||||
{
|
||||
parent::setEnvironment($env);
|
||||
|
||||
foreach ($this->transformers as $transformer)
|
||||
{
|
||||
$transformer->setEnvironment($env);
|
||||
}
|
||||
}
|
||||
|
||||
public function visit(Twig_Node $node)
|
||||
{
|
||||
foreach ($this->transformers as $transformer)
|
||||
{
|
||||
$node = $transformer->visit($node);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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_NodeTraverser
|
||||
{
|
||||
protected $env;
|
||||
|
||||
public function __construct(Twig_Environment $env)
|
||||
{
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
public function traverse(Twig_Node $node, Twig_NodeVisitorInterface $visitor)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
$node->setNodes($newNodes);
|
||||
}
|
||||
|
||||
return $visitor->leaveNode($node, $this->env);
|
||||
}
|
||||
}
|
||||
@@ -8,39 +8,44 @@
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
class Twig_NodeTransformer_Escaper extends Twig_NodeTransformer
|
||||
class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
|
||||
{
|
||||
protected $statusStack = array();
|
||||
protected $blocks = array();
|
||||
|
||||
public function visit(Twig_Node $node)
|
||||
public function enterNode(Twig_Node $node, Twig_Environment $env)
|
||||
{
|
||||
// autoescape?
|
||||
if ($node instanceof Twig_Node_AutoEscape)
|
||||
{
|
||||
$this->statusStack[] = $node->getValue();
|
||||
|
||||
$node = $this->visitDeep($node);
|
||||
|
||||
array_pop($this->statusStack);
|
||||
|
||||
// remove the node
|
||||
return $node;
|
||||
}
|
||||
|
||||
if (!$node instanceof Twig_Node_Print)
|
||||
elseif ($node instanceof Twig_Node_Print && true === $this->needEscaping($env))
|
||||
{
|
||||
return $this->visitDeep($node);
|
||||
return $this->escapeNode($node, $env);
|
||||
}
|
||||
|
||||
if (false === $this->needEscaping())
|
||||
elseif ($node instanceof Twig_Node_Block)
|
||||
{
|
||||
return $node;
|
||||
$this->statusStack[] = isset($this->blocks[$node->getName()]) ? $this->blocks[$node->getName()] : $this->needEscaping($env);
|
||||
}
|
||||
|
||||
return $this->escapeNode($node);
|
||||
return $node;
|
||||
}
|
||||
|
||||
protected function escapeNode($node)
|
||||
public function leaveNode(Twig_Node $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);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
protected function escapeNode(Twig_Node $node, Twig_Environment $env)
|
||||
{
|
||||
$expression = $node instanceof Twig_Node_Print ? $node->getExpression() : $node;
|
||||
|
||||
@@ -54,7 +59,7 @@ class Twig_NodeTransformer_Escaper extends Twig_NodeTransformer
|
||||
}
|
||||
|
||||
// don't escape if there is already an "escaper" in the filter chain
|
||||
$filterMap = $this->env->getFilters();
|
||||
$filterMap = $env->getFilters();
|
||||
foreach ($expression->getFilters() as $filter)
|
||||
{
|
||||
if (isset($filterMap[$filter[0]]) && $filterMap[$filter[0]]->isEscaper())
|
||||
@@ -78,7 +83,7 @@ class Twig_NodeTransformer_Escaper extends Twig_NodeTransformer
|
||||
{
|
||||
foreach ($filter[1] as $j => $argument)
|
||||
{
|
||||
$filters[$i][1][$j] = $this->escapeNode($argument);
|
||||
$filters[$i][1][$j] = $this->escapeNode($argument, $env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +105,7 @@ class Twig_NodeTransformer_Escaper extends Twig_NodeTransformer
|
||||
}
|
||||
}
|
||||
|
||||
protected function needEscaping()
|
||||
protected function needEscaping(Twig_Environment $env)
|
||||
{
|
||||
if (count($this->statusStack))
|
||||
{
|
||||
@@ -108,7 +113,7 @@ class Twig_NodeTransformer_Escaper extends Twig_NodeTransformer
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->env->hasExtension('escaper') ? $this->env->getExtension('escaper')->isGlobal() : false;
|
||||
return $env->hasExtension('escaper') ? $env->getExtension('escaper')->isGlobal() : false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,29 +8,36 @@
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
class Twig_NodeTransformer_Filter extends Twig_NodeTransformer
|
||||
class Twig_NodeVisitor_Filter implements Twig_NodeVisitorInterface
|
||||
{
|
||||
protected $statusStack = array();
|
||||
|
||||
public function visit(Twig_Node $node)
|
||||
public function enterNode(Twig_Node $node, Twig_Environment $env)
|
||||
{
|
||||
// filter?
|
||||
if ($node instanceof Twig_Node_Filter)
|
||||
{
|
||||
$this->statusStack[] = $node->getFilters();
|
||||
|
||||
$node = $this->visitDeep($node);
|
||||
|
||||
array_pop($this->statusStack);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
if (!$node instanceof Twig_Node_Print && !$node instanceof Twig_Node_Text)
|
||||
elseif ($node instanceof Twig_Node_Print || $node instanceof Twig_Node_Text)
|
||||
{
|
||||
return $this->visitDeep($node);
|
||||
return $this->applyFilters($node);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function leaveNode(Twig_Node $node, Twig_Environment $env)
|
||||
{
|
||||
if ($node instanceof Twig_Node_Filter)
|
||||
{
|
||||
array_pop($this->statusStack);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
protected function applyFilters(Twig_Node $node)
|
||||
{
|
||||
if (false === $filters = $this->getCurrentFilters())
|
||||
{
|
||||
return $node;
|
||||
@@ -8,13 +8,13 @@
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
class Twig_NodeTransformer_Sandbox extends Twig_NodeTransformer
|
||||
class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
|
||||
{
|
||||
protected $inAModule = false;
|
||||
protected $tags;
|
||||
protected $filters;
|
||||
|
||||
public function visit(Twig_Node $node)
|
||||
public function enterNode(Twig_Node $node, Twig_Environment $env)
|
||||
{
|
||||
if ($node instanceof Twig_Node_Module)
|
||||
{
|
||||
@@ -22,36 +22,37 @@ class Twig_NodeTransformer_Sandbox extends Twig_NodeTransformer
|
||||
$this->tags = array();
|
||||
$this->filters = array();
|
||||
|
||||
$node = $this->visitDeep($node);
|
||||
|
||||
$node->setUsedFilters(array_keys($this->filters));
|
||||
$node->setUsedTags(array_keys($this->tags));
|
||||
$this->inAModule = false;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
if (!$this->inAModule)
|
||||
elseif ($this->inAModule)
|
||||
{
|
||||
return $node;
|
||||
}
|
||||
|
||||
// look for tags
|
||||
if ($node->getTag())
|
||||
{
|
||||
$this->tags[$node->getTag()] = true;
|
||||
}
|
||||
|
||||
// look for filters
|
||||
if ($node instanceof Twig_Node_Expression_Filter)
|
||||
{
|
||||
foreach ($node->getFilters() as $filter)
|
||||
// look for tags
|
||||
if ($node->getTag())
|
||||
{
|
||||
$this->filters[$filter[0]] = true;
|
||||
$this->tags[$node->getTag()] = true;
|
||||
}
|
||||
|
||||
// look for filters
|
||||
if ($node instanceof Twig_Node_Expression_Filter)
|
||||
{
|
||||
foreach ($node->getFilters() as $filter)
|
||||
{
|
||||
$this->filters[$filter[0]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->visitDeep($node);
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function leaveNode(Twig_Node $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 $node;
|
||||
}
|
||||
+11
-9
@@ -14,7 +14,7 @@ class Twig_Parser
|
||||
protected $stream;
|
||||
protected $extends;
|
||||
protected $handlers;
|
||||
protected $transformers;
|
||||
protected $visitors;
|
||||
protected $expressionParser;
|
||||
protected $blocks;
|
||||
protected $currentBlock;
|
||||
@@ -31,7 +31,7 @@ class Twig_Parser
|
||||
$this->env = $env;
|
||||
|
||||
$this->handlers = array();
|
||||
$this->transformers = array();
|
||||
$this->visitors = array();
|
||||
|
||||
// tag handlers
|
||||
foreach ($this->env->getTokenParsers() as $handler)
|
||||
@@ -41,8 +41,8 @@ class Twig_Parser
|
||||
$this->handlers[$handler->getTag()] = $handler;
|
||||
}
|
||||
|
||||
// node transformers
|
||||
$this->transformers = $env->getNodeTransformers();
|
||||
// node visitors
|
||||
$this->visitors = $env->getNodeVisitors();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,9 +89,11 @@ class Twig_Parser
|
||||
|
||||
$node = new Twig_Node_Module($body, $this->extends, $this->blocks, $this->macros, $this->stream->getFilename());
|
||||
|
||||
$transformer = new Twig_NodeTransformer_Chain($this->transformers);
|
||||
$transformer->setEnvironment($this->env);
|
||||
$node = $transformer->visit($node);
|
||||
$t = new Twig_NodeTraverser($this->env);
|
||||
foreach ($this->visitors as $visitor)
|
||||
{
|
||||
$node = $t->traverse($node, $visitor);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
@@ -163,9 +165,9 @@ class Twig_Parser
|
||||
$this->handlers[$name] = $class;
|
||||
}
|
||||
|
||||
public function addTransformer(Twig_NodeTransformer $transformer)
|
||||
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
|
||||
{
|
||||
$this->transformers[] = $transformer;
|
||||
$this->visitors[] = $visitor;
|
||||
}
|
||||
|
||||
public function getCurrentBlock()
|
||||
|
||||
Reference in New Issue
Block a user