4 * This file is part of Twig.
6 * (c) 2012 Fabien Potencier
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
11 abstract class Twig_Node_Expression_Call
extends Twig_Node_Expression
13 protected function compileCallable(Twig_Compiler
$compiler)
15 $callable = $this->getAttribute('callable');
17 $closingParenthesis = false;
19 if (is_string($callable)) {
20 $compiler->raw($callable);
21 } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface
) {
22 $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
24 $type = ucfirst($this->getAttribute('type'));
25 $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
26 $closingParenthesis = true;
29 $compiler->raw($this->getAttribute('thing')->compile());
32 $this->compileArguments($compiler);
34 if ($closingParenthesis) {
39 protected function compileArguments(Twig_Compiler
$compiler)
45 if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
46 $compiler->raw('$this->env');
50 if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
54 $compiler->raw('$context');
58 if ($this->hasAttribute('arguments
')) {
59 foreach ($this->getAttribute('arguments
') as $argument) {
63 $compiler->string($argument);
68 if ($this->hasNode('node
')) {
72 $compiler->subcompile($this->getNode('node
'));
76 if ($this->hasNode('arguments
') && null !== $this->getNode('arguments
')) {
77 $callable = $this->hasAttribute('callable
') ? $this->getAttribute('callable
') : null;
79 $arguments = $this->getArguments($callable, $this->getNode('arguments
'));
81 foreach ($arguments as $node) {
85 $compiler->subcompile($node);
93 protected function getArguments($callable, $arguments)
95 $parameters = array();
97 foreach ($arguments as $name => $node) {
100 $name = $this->normalizeName($name);
102 throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments
for %s
"%s".', $this->getAttribute('type
'), $this->getAttribute('name
')));
105 $parameters[$name] = $node;
113 throw new LogicException(sprintf('Named arguments are not supported
for %s
"%s".', $this->getAttribute('type
'), $this->getAttribute('name
')));
116 // manage named arguments
117 if (is_array($callable)) {
118 $r = new ReflectionMethod($callable[0], $callable[1]);
119 } elseif (is_object($callable) && !$callable instanceof Closure) {
120 $r = new ReflectionObject($callable);
121 $r = $r->getMethod('__invoke
');
123 $r = new ReflectionFunction($callable);
126 $definition = $r->getParameters();
127 if ($this->hasNode('node
')) {
128 array_shift($definition);
130 if ($this->hasAttribute('needs_environment
') && $this->getAttribute('needs_environment
')) {
131 array_shift($definition);
133 if ($this->hasAttribute('needs_context
') && $this->getAttribute('needs_context
')) {
134 array_shift($definition);
136 if ($this->hasAttribute('arguments
') && null !== $this->getAttribute('arguments
')) {
137 foreach ($this->getAttribute('arguments
') as $argument) {
138 array_shift($definition);
142 $arguments = array();
144 foreach ($definition as $param) {
145 $name = $this->normalizeName($param->name);
147 if (array_key_exists($name, $parameters)) {
148 if (array_key_exists($pos, $parameters)) {
149 throw new Twig_Error_Syntax(sprintf('Argument
"%s" is defined twice
for %s
"%s".', $name, $this->getAttribute('type
'), $this->getAttribute('name
')));
152 $arguments[] = $parameters[$name];
153 unset($parameters[$name]);
154 } elseif (array_key_exists($pos, $parameters)) {
155 $arguments[] = $parameters[$pos];
156 unset($parameters[$pos]);
158 } elseif ($param->isDefaultValueAvailable()) {
159 $arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
160 } elseif ($param->isOptional()) {
163 throw new Twig_Error_Syntax(sprintf('Value
for argument
"%s" is required
for %s
"%s".', $name, $this->getAttribute('type
'), $this->getAttribute('name
')));
167 if (!empty($parameters)) {
168 throw new Twig_Error_Syntax(sprintf('Unknown argument%s
"%s" for %s
"%s".', count($parameters) > 1 ? 's
' : '' , implode('", "', array_keys($parameters)), $this->getAttribute('type
'), $this->getAttribute('name
')));
174 protected function normalizeName($name)
176 return strtolower(preg_replace(array('/([A
-Z
]+
)([A
-Z
][a
-z
])/', '/([a
-z\d
])([A
-Z
])/'), array('\\
1_\\
2', '\\
1_\\
2'), $name));