$token = $this->parser->getStream()->next();
$lineno = $token->getLine();
$arguments = new Twig_Node();
+ $type = Twig_Node_Expression_GetAttr::TYPE_ANY;
if ($token->getValue() == '.') {
$token = $this->parser->getStream()->next();
if ($token->getType() == Twig_Token::NAME_TYPE || $token->getType() == Twig_Token::NUMBER_TYPE) {
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
+ if ($this->parser->getStream()->test(Twig_Token::OPERATOR_TYPE, '(')) {
+ $type = Twig_Node_Expression_GetAttr::TYPE_METHOD;
+ }
+
$arguments = $this->parseArguments();
} else {
throw new Twig_SyntaxError('Expected name or number', $lineno);
}
} else {
+ $type = Twig_Node_Expression_GetAttr::TYPE_ARRAY;
+
$arg = $this->parseExpression();
$this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, ']');
}
- return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $lineno, $token->getValue());
+ return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $lineno, $type);
}
public function parseFilterExpression($node)
*/
class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
{
- public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_NodeInterface $arguments, $lineno, $token_value = null)
+ const TYPE_ANY = 'any';
+ const TYPE_ARRAY = 'array';
+ const TYPE_METHOD = 'method';
+
+ public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_NodeInterface $arguments, $lineno, $type = self::TYPE_ANY)
{
- parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('token_value' => $token_value), $lineno);
+ parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type), $lineno);
}
public function compile($compiler)
;
}
- $compiler->raw(')');
-
- // Don't look for functions if they're using foo[bar]
- if ('[' == $this['token_value']) {
- $compiler->raw(', true');
- }
-
- $compiler->raw(')');
+ $compiler
+ ->raw('), ')
+ ->repr($this['type'])
+ ->raw(')');
}
}
throw new InvalidArgumentException(sprintf('Item "%s" from context does not exist.', $item));
}
- protected function getAttribute($object, $item, array $arguments = array(), $arrayOnly = false)
+ protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_Node_Expression_GetAttr::TYPE_ANY)
{
- $item = (string) $item;
+ // array
+ if (Twig_Node_Expression_GetAttr::TYPE_METHOD !== $type) {
+ if ((is_array($object) || is_object($object) && $object instanceof ArrayAccess) && isset($object[$item])) {
+ return $object[$item];
+ }
+
+ if (Twig_Node_Expression_GetAttr::TYPE_ARRAY === $type) {
+ if (!$this->env->isStrictVariables()) {
+ return null;
+ }
- if ((is_array($object) || is_object($object) && $object instanceof ArrayAccess) && isset($object[$item])) {
- return $object[$item];
+ throw new InvalidArgumentException(sprintf('Key "%s" for array "%s" does not exist.', $item, $object));
+ }
}
- if ($arrayOnly || !is_object($object)) {
+ if (!is_object($object)) {
if (!$this->env->isStrictVariables()) {
return null;
}
- throw new InvalidArgumentException(sprintf('Key "%s" for array "%s" does not exist.', $item, $object));
+ throw new InvalidArgumentException(sprintf('Item "%s" for "%s" does not exist.', $item, $object));
}
- if (isset($object->$item)) {
- if ($this->env->hasExtension('sandbox')) {
- $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
- }
+ // object property
+ if (Twig_Node_Expression_GetAttr::TYPE_METHOD !== $type) {
+ if (isset($object->$item)) {
+ if ($this->env->hasExtension('sandbox')) {
+ $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
+ }
- return $object->$item;
+ return $object->$item;
+ }
}
+ // object method
$class = get_class($object);
if (!isset($this->cache[$class])) {
new Twig_Node_Expression_Name('foo', 0),
new Twig_Node_Expression_Constant('bar', 0),
));
- $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 0, '[');
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 0, Twig_Node_Expression_GetAttr::TYPE_ARRAY);
$this->assertEquals($expr, $node->node);
$this->assertEquals($attr, $node->attribute);
$this->assertEquals($args, $node->arguments);
- $this->assertEquals('[', $node['token_value']);
+ $this->assertEquals(Twig_Node_Expression_GetAttr::TYPE_ARRAY, $node['type']);
}
/**
$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())');
+ $tests[] = array($node, '$this->getAttribute($this->getContext($context, \'foo\'), "bar", array(), "any")');
+
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 0, Twig_Node_Expression_GetAttr::TYPE_ARRAY);
+ $tests[] = array($node, '$this->getAttribute($this->getContext($context, \'foo\'), "bar", array(), "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", ))');
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, 0, Twig_Node_Expression_GetAttr::TYPE_METHOD);
+ $tests[] = array($node, '$this->getAttribute($this->getContext($context, \'foo\'), "bar", array($this->getContext($context, \'foo\'), "bar", ), "method")');
return $tests;
}