return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line);
default:
- if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
- $arguments = new Twig_Node_Expression_Array(array(), $line);
- foreach ($this->parseArguments() as $n) {
- $arguments->addElement($n);
- }
-
- $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
- $node->setAttribute('safe', true);
+ if (null !== $alias = $this->parser->getImportedSymbol('macro', $name)) {
+ $arguments = $this->createArrayFromArguments($this->parseArguments());
- return $node;
+ return new Twig_Node_Expression_MacroCall($alias['node'], $alias['name'], $arguments, $line);
}
$args = $this->parseArguments(true);
($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
) {
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
-
- if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
- $type = Twig_TemplateInterface::METHOD_CALL;
- foreach ($this->parseArguments() as $n) {
- $arguments->addElement($n);
- }
- }
} else {
throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
}
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
}
- $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
- $node->setAttribute('safe', true);
+ $arguments = $this->createArrayFromArguments($this->parseArguments());
- return $node;
+ return new Twig_Node_Expression_MacroCall($node, $arg->getAttribute('value'), $arguments, $lineno);
+ }
+
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
+ $type = Twig_TemplateInterface::METHOD_CALL;
+ $arguments = $this->createArrayFromArguments($this->parseArguments());
}
} else {
$type = Twig_TemplateInterface::ARRAY_CALL;
*
* @param Boolean $namedArguments Whether to allow named arguments or not
* @param Boolean $definition Whether we are parsing arguments for a function definition
+ *
+ * @return Twig_Node
*/
public function parseArguments($namedArguments = false, $definition = false)
{
}
}
- if ($definition) {
- if (null === $name) {
- $name = $value->getAttribute('name');
- $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
- }
- $args[$name] = $value;
+ if ($definition && null === $name) {
+ $name = $value->getAttribute('name');
+ $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
+ }
+
+ if (null === $name) {
+ $args[] = $value;
} else {
- if (null === $name) {
- $args[] = $value;
- } else {
- $args[$name] = $value;
- }
+ $args[$name] = $value;
}
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
return true;
}
+
+ private function createArrayFromArguments(Twig_Node $arguments, $line = null)
+ {
+ $line = null === $line ? $arguments->getLine() : $line;
+ $array = new Twig_Node_Expression_Array(array(), $line);
+ foreach ($arguments as $key => $value) {
+ $array->addElement($value, new Twig_Node_Expression_Constant($key, $value->getLine()));
+ }
+
+ return $array;
+ }
}
--- /dev/null
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2012 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Represents a macro call node.
+ *
+ * @author Martin Hasoň <martin.hason@gmail.com>
+ */
+class Twig_Node_Expression_MacroCall extends Twig_Node_Expression
+{
+ public function __construct(Twig_Node_Expression $template, $name, Twig_Node_Expression_Array $arguments, $lineno)
+ {
+ parent::__construct(array('template' => $template, 'arguments' => $arguments), array('name' => $name), $lineno);
+ }
+
+ public function compile(Twig_Compiler $compiler)
+ {
+ $compiler
+ ->raw('$this->callMacro(')
+ ->subcompile($this->getNode('template'))
+ ->raw(', ')
+ ->repr($this->getAttribute('name'))
+ ->raw(', ')
+ ->subcompile($this->getNode('arguments'))
+ ->raw(')')
+ ;
+ }
+}
{
public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
{
- parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
+ parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name, 'method' => 'get'.ucfirst($name)), $lineno, $tag);
}
/**
{
$compiler
->addDebugInfo($this)
- ->write(sprintf("public function get%s(", $this->getAttribute('name')))
+ ->write(sprintf("public function %s(", $this->getAttribute('method')))
;
$count = count($this->getNode('arguments'));
$compiler
->outdent()
+ ->write(");\n\n")
+ ;
+
+ // macro information
+ $compiler
+ ->write("\$this->macros = array(\n")
+ ->indent()
+ ;
+
+ foreach ($this->getNode('macros') as $name => $node) {
+ $compiler
+ ->addIndentation()->repr($name)->raw(" => array(\n")
+ ->indent()
+ ->write("'method' => ")->repr($node->getAttribute('method'))->raw(",\n")
+ ->outdent()
+ ->write("),\n")
+ ;
+ }
+ $compiler
+ ->outdent()
->write(");\n")
+ ;
+
+ $compiler
->outdent()
- ->write("}\n\n");
+ ->write("}\n\n")
;
}
} else {
$this->setSafe($node, array());
}
+ } elseif ($node instanceof Twig_Node_Expression_MacroCall) {
+ $this->setSafe($node, array('all'));
} elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) {
$name = $node->getNode('node')->getAttribute('name');
// attributes on template instances are safe
protected $env;
protected $blocks;
protected $traits;
+ protected $macros;
/**
* Constructor.
$this->env = $env;
$this->blocks = array();
$this->traits = array();
+ $this->macros = array();
}
/**
}
/**
+ * Calls macro in a template.
+ *
+ * @param Twig_Template $template The template
+ * @param string $macro The name of macro
+ * @param array $arguments The arguments of macro
+ *
+ * @return string The content of a macro
+ */
+ protected function callMacro(Twig_Template $template, $macro, array $arguments)
+ {
+ if (!isset($template->macros[$macro]['reflection'])) {
+ $template->macros[$macro]['reflection'] = new ReflectionMethod($template, $template->macros[$macro]['method']);
+ }
+
+ return $template->macros[$macro]['reflection']->invokeArgs($template, $arguments);
+ }
+
+ /**
* This method is only useful when testing Twig. Do not use it.
*/
public static function clearCache()
$node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag());
foreach ($targets as $name => $alias) {
- $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
+ $this->parser->addImportedSymbol('macro', $alias, $name, $node->getNode('var'));
}
return $node;
return array(
array($node, <<<EOF
// line 1
-public function getfoo(\$_foo = null, \$_bar = "Foo")
+public function getFoo(\$_foo = null, \$_bar = "Foo")
{
\$context = \$this->env->mergeGlobals(array(
"foo" => \$_foo,
\$this->blocks = array(
);
+
+ \$this->macros = array(
+ );
}
protected function doDisplay(array \$context, array \$blocks = array())
public function getDebugInfo()
{
- return array ( 19 => 1,);
+ return array ( 22 => 1,);
}
}
EOF
\$this->blocks = array(
);
+
+ \$this->macros = array(
+ );
}
protected function doGetParent(array \$context)
public function getDebugInfo()
{
- return array ( 24 => 1,);
+ return array ( 27 => 1,);
}
}
EOF
\$this->blocks = array(
);
+
+ \$this->macros = array(
+ );
}
protected function doDisplay(array \$context, array \$blocks = array())
public function getDebugInfo()
{
- return array ( 20 => 1,);
+ return array ( 23 => 1,);
}
}
EOF
\$this->blocks = array(
);
+
+ \$this->macros = array(
+ );
}
protected function doGetParent(array \$context)