protected function compileString(\Twig_NodeInterface $body, \Twig_Node_Expression_Array $vars) { if ($body instanceof \Twig_Node_Expression_Constant) { $msg = $body->getAttribute('value'); } elseif ($body instanceof \Twig_Node_Text) { $msg = $body->getAttribute('data'); } else { return array($body, $vars); } preg_match_all('/(?<!%)%([^%]+)%/', $msg, $matches); if (version_compare(\Twig_Environment::VERSION, '1.5', '>=')) { foreach ($matches[1] as $var) { $key = new \Twig_Node_Expression_Constant('%' . $var . '%', $body->getLine()); if (!$vars->hasElement($key)) { $vars->addElement(new \Twig_Node_Expression_Name($var, $body->getLine()), $key); } } } else { $current = array(); foreach ($vars as $name => $var) { $current[$name] = true; } foreach ($matches[1] as $var) { if (!isset($current['%' . $var . '%'])) { $vars->setNode('%' . $var . '%', new \Twig_Node_Expression_Name($var, $body->getLine())); } } } return array(new \Twig_Node_Expression_Constant(str_replace('%%', '%', trim($msg)), $body->getLine()), $vars); }
public function parse(\Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $resources = new \Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); do { $resources->addElement($this->parser->getExpressionParser()->parseExpression()); } while (!$stream->test(\Twig_Token::BLOCK_END_TYPE)); $stream->expect(\Twig_Token::BLOCK_END_TYPE); return new GitThemeNode($resources, $lineno, $this->getTag()); }
/** * @param ArrayNode $node * @return array */ protected function nodeToArray(ArrayNode $node) { $array = array(); foreach ($node->getKeyValuePairs() as $pair) { if (!$pair['key'] instanceof ConstantNode) { continue; } $array[$pair['key']->getAttribute('value')] = $pair['value']; } return $array; }
public function valueNode() { // date value (either a DateTime object, or null) $valueNode = parent::valueNode(); // format('Y-m-d') method call on date object $args = new \Twig_Node_Expression_Array([], $this->lineno); $args->addElement(new \Twig_Node_Expression_Constant('j M, Y', $this->lineno)); $formatNode = new \Twig_Node_Expression_MethodCall($valueNode, 'format', $args, $this->lineno); // conditional to check for a null value $conditionalNode = new \Twig_Node_Expression_Conditional($valueNode, $formatNode, $valueNode, $this->lineno); return $conditionalNode; }
protected function convertToViewArguments(\Twig_Node_Expression_Array $array) { $arguments = array(); foreach (array_chunk($array->getIterator()->getArrayCopy(), 2) as $pair) { if (count($pair) == 2) { $key = $pair[0]->getAttribute('value'); $value = $pair[1]->getAttribute('value'); // @todo support for multiple types $arguments[$key] = $value; } } return $arguments; }
/** * @param string $msg * @param \Twig_Node_Expression_Array $vars * @param int $lineno * @return \Twig_Node_Expression_Array */ protected function escapeContextVariables($msg, $vars, $lineno) { preg_match_all('/(?<!%)%([^%]+)%/', $msg, $matches); foreach ($matches[1] as $var) { $key = new \Twig_Node_Expression_Constant('%' . $var . '%', $lineno); if (!$vars->hasElement($key)) { $node = new \Twig_Node_Expression_Name($var, $lineno); $node = $this->escapeNodeIfNecessary($node, $lineno); $vars->addElement($node, $key); } } return $vars; }
public function getTests() { $tests = array(); $expr = new Twig_Node_Expression_Name('foo', 1); $attr = new Twig_Node_Expression_Constant('bar', 1); $args = new Twig_Node_Expression_Array(array(), 1); $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ANY_CALL, 1); $tests[] = array($node, sprintf('%s%s, "bar", [])', $this->getAttributeGetter(), $this->getVariableGetter('foo', 1))); $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ARRAY_CALL, 1); $tests[] = array($node, sprintf('%s%s, "bar", [], "array")', $this->getAttributeGetter(), $this->getVariableGetter('foo', 1))); $args = new Twig_Node_Expression_Array(array(), 1); $args->addElement(new Twig_Node_Expression_Name('foo', 1)); $args->addElement(new Twig_Node_Expression_Constant('bar', 1)); $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::METHOD_CALL, 1); $tests[] = array($node, sprintf('%s%s, "bar", [0 => %s, 1 => "bar"], "method")', $this->getAttributeGetter(), $this->getVariableGetter('foo', 1), $this->getVariableGetter('foo'))); return $tests; }
/** * {@inheritdoc} */ public function parse(\Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $datagrid = $this->parser->getExpressionParser()->parseExpression(); if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'with')) { $this->parser->getStream()->next(); $resources = $this->parser->getExpressionParser()->parseExpression(); } else { $resources = new \Twig_Node_Expression_Array([], $stream->getCurrent()->getLine()); do { $resources->addElement($this->parser->getExpressionParser()->parseExpression()); } while (!$stream->test(\Twig_Token::BLOCK_END_TYPE)); } $stream->expect(\Twig_Token::BLOCK_END_TYPE); return new DatagridThemeNode($datagrid, $resources, $lineno, $this->getTag()); }
/** * @param \Twig_NodeInterface $node * @param \Twig_Environment $env * @return \Twig_NodeInterface */ public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env) { if (!$this->enabled) { return $node; } if ($node instanceof \Twig_Node_Expression_Filter && 'desc' === $node->getNode('filter')->getAttribute('value')) { $transNode = $node->getNode('node'); while ($transNode instanceof \Twig_Node_Expression_Filter && 'trans' !== $transNode->getNode('filter')->getAttribute('value') && 'transchoice' !== $transNode->getNode('filter')->getAttribute('value')) { $transNode = $transNode->getNode('node'); } if (!$transNode instanceof \Twig_Node_Expression_Filter) { throw new RuntimeException(sprintf('The "desc" filter must be applied after a "trans", or "transchoice" filter.')); } $wrappingNode = $node->getNode('node'); $testNode = clone $wrappingNode; $defaultNode = $node->getNode('arguments')->getNode(0); // if the |transchoice filter is used, delegate the call to the TranslationExtension // so that we can catch a possible exception when the default translation has not yet // been extracted if ('transchoice' === $transNode->getNode('filter')->getAttribute('value')) { $transchoiceArguments = new \Twig_Node_Expression_Array(array(), $transNode->getLine()); $transchoiceArguments->addElement($wrappingNode->getNode('node')); $transchoiceArguments->addElement($defaultNode); foreach ($wrappingNode->getNode('arguments') as $arg) { $transchoiceArguments->addElement($arg); } $transchoiceNode = new \Twig_Node_Expression_MethodCall(new \Twig_Node_Expression_ExtensionReference('jms_translation', $transNode->getLine()), 'transchoiceWithDefault', $transchoiceArguments, $transNode->getLine()); $node->setNode('node', $transchoiceNode); return $node; } // if the |trans filter has replacements parameters // (e.g. |trans({'%foo%': 'bar'})) if ($wrappingNode->getNode('arguments')->hasNode(0)) { $lineno = $wrappingNode->getLine(); // remove the replacements from the test node $testNode->setNode('arguments', clone $testNode->getNode('arguments')); $testNode->getNode('arguments')->setNode(0, new \Twig_Node_Expression_Array(array(), $lineno)); // wrap the default node in a |replace filter $defaultNode = new \Twig_Node_Expression_Filter(clone $node->getNode('arguments')->getNode(0), new \Twig_Node_Expression_Constant('replace', $lineno), new \Twig_Node(array(clone $wrappingNode->getNode('arguments')->getNode(0))), $lineno); } $condition = new \Twig_Node_Expression_Conditional(new \Twig_Node_Expression_Binary_Equal($testNode, $transNode->getNode('node'), $wrappingNode->getLine()), $defaultNode, clone $wrappingNode, $wrappingNode->getLine()); $node->setNode('node', $condition); } return $node; }
protected function compileString(\Twig_NodeInterface $body, \Twig_Node_Expression_Array $vars) { if ($body instanceof \Twig_Node_Expression_Constant) { $msg = $body->getAttribute('value'); } elseif ($body instanceof \Twig_Node_Text) { $msg = $body->getAttribute('data'); } else { return array($body, $vars); } preg_match_all('/(?<!%)%([^%]+)%/', $msg, $matches); foreach ($matches[1] as $var) { $key = new \Twig_Node_Expression_Constant('%' . $var . '%', $body->getLine()); if (!$vars->hasElement($key)) { $vars->addElement(new \Twig_Node_Expression_Name($var, $body->getLine()), $key); } } return array(new \Twig_Node_Expression_Constant(str_replace('%%', '%', trim($msg)), $body->getLine()), $vars); }
/** * @param \Twig_Token $token * @return array */ protected function parseArguments(\Twig_Token $token) { $stream = $this->parser->getStream(); $location = null; if ($stream->nextIf(\Twig_Token::OPERATOR_TYPE, 'in')) { $location = $this->parser->getExpressionParser()->parseExpression(); } else { $lineno = $token->getLine(); $location = new \Twig_Node_Expression_Constant('head', $lineno); } if ($stream->nextIf(\Twig_Token::NAME_TYPE, 'with')) { $variables = $this->parser->getExpressionParser()->parseExpression(); } else { $lineno = $token->getLine(); $variables = new \Twig_Node_Expression_Array([], $lineno); $variables->setAttribute('priority', 0); } $stream->expect(\Twig_Token::BLOCK_END_TYPE); return [$location, $variables]; }
protected function compileString(\Twig_NodeInterface $body, \Twig_Node_Expression_Array $vars) { if ($body instanceof \Twig_Node_Expression_Constant) { $msg = $body->getAttribute('value'); } elseif ($body instanceof \Twig_Node_Text) { $msg = $body->getAttribute('data'); } else { return array($body, $vars); } $current = array(); foreach ($vars as $name => $var) { $current[$name] = true; } preg_match_all('/\\%([^\\%]+)\\%/', $msg, $matches); foreach ($matches[1] as $var) { if (!isset($current['%' . $var . '%'])) { $vars->setNode('%' . $var . '%', new \Twig_Node_Expression_Name($var, $body->getLine())); } } return array(new \Twig_Node_Expression_Constant(trim($msg), $body->getLine()), $vars); }
public function parse(\Twig_Token $token) { $lineno = $token->getLine(); $arguments = new \Twig_Node_Expression_Array(array(), $lineno); $wherearguments = null; // name - the new variable with the results $name = $this->parser->getStream()->expect(\Twig_Token::NAME_TYPE)->getValue(); $this->parser->getStream()->expect(\Twig_Token::OPERATOR_TYPE, '='); // contenttype, or simple expression to content. $contenttype = $this->parser->getExpressionParser()->parseExpression(); $counter = 0; do { // where parameter if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'where')) { $this->parser->getStream()->next(); $wherearguments = $this->parser->getExpressionParser()->parseExpression(); } // limit parameter if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'limit')) { $this->parser->getStream()->next(); $limit = $this->parser->getExpressionParser()->parseExpression(); $arguments->addElement($limit, new \Twig_Node_Expression_Constant('limit', $lineno)); } // order / orderby parameter if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'order') || $this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'orderby')) { $this->parser->getStream()->next(); $order = $this->parser->getExpressionParser()->parseExpression(); $arguments->addElement($order, new \Twig_Node_Expression_Constant('order', $lineno)); } // paging / allowpaging parameter if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'paging') || $this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'allowpaging')) { $this->parser->getStream()->next(); $arguments->addElement(new \Twig_Node_Expression_Constant(true, $lineno), new \Twig_Node_Expression_Constant('paging', $lineno)); } // printquery parameter if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'printquery')) { $this->parser->getStream()->next(); $arguments->addElement(new \Twig_Node_Expression_Constant(true, $lineno), new \Twig_Node_Expression_Constant('printquery', $lineno)); } // returnsingle parameter if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'returnsingle')) { $this->parser->getStream()->next(); $arguments->addElement(new \Twig_Node_Expression_Constant(true, $lineno), new \Twig_Node_Expression_Constant('returnsingle', $lineno)); } // nohydrate parameter if ($this->parser->getStream()->test(\Twig_Token::NAME_TYPE, 'nohydrate')) { $this->parser->getStream()->next(); $arguments->addElement(new \Twig_Node_Expression_Constant(false, $lineno), new \Twig_Node_Expression_Constant('hydrate', $lineno)); } // Make sure we don't get stuck in a loop, if a token can't be parsed. $counter++; } while (!$this->parser->getStream()->test(\Twig_Token::BLOCK_END_TYPE) && $counter < 10); $this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE); return new SetcontentNode($name, $contenttype, $arguments, $wherearguments, $lineno, $this->getTag()); }
protected function compileString(\Twig_NodeInterface $body, \Twig_Node_Expression_Array $vars, $ignoreStrictCheck = false) { if ($body instanceof \Twig_Node_Expression_Constant) { $msg = $body->getAttribute('value'); } elseif ($body instanceof \Twig_Node_Text) { $msg = $body->getAttribute('data'); } else { return array($body, $vars); } preg_match_all('/(?<!%)%([^%]+)%/', $msg, $matches); foreach ($matches[1] as $var) { $key = new \Twig_Node_Expression_Constant('%' . $var . '%', $body->getLine()); if (!$vars->hasElement($key)) { if ('count' === $var && null !== $this->getNode('count')) { $vars->addElement($this->getNode('count'), $key); } else { $varExpr = new \Twig_Node_Expression_Name($var, $body->getLine()); $varExpr->setAttribute('ignore_strict_check', $ignoreStrictCheck); $vars->addElement($varExpr, $key); } } } return array(new \Twig_Node_Expression_Constant(str_replace('%%', '%', trim($msg)), $body->getLine()), $vars); }
public function parseSubscriptExpression($node) { $stream = $this->parser->getStream(); $token = $stream->next(); $lineno = $token->getLine(); $arguments = new Twig_Node_Expression_Array(array(), $lineno); $type = Twig_Template::ANY_CALL; if ($token->getValue() == '.') { $token = $stream->next(); if ($token->getType() == Twig_Token::NAME_TYPE || $token->getType() == Twig_Token::NUMBER_TYPE || $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()); } if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { if (!$arg instanceof Twig_Node_Expression_Constant) { 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); return $node; } } else { $type = Twig_Template::ARRAY_CALL; // slice? $slice = false; if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { $slice = true; $arg = new Twig_Node_Expression_Constant(0, $token->getLine()); } else { $arg = $this->parseExpression(); } if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { $slice = true; } if ($slice) { if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { $length = new Twig_Node_Expression_Constant(null, $token->getLine()); } else { $length = $this->parseExpression(); } $class = $this->getFilterNodeClass('slice', $token->getLine()); $arguments = new Twig_Node(array($arg, $length)); $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); return $filter; } $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); } return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno); }
public function parseSubscriptExpression($node) { $stream = $this->parser->getStream(); $token = $stream->next(); $lineno = $token->getLine(); $arguments = new Twig_Node_Expression_Array(array(), $lineno); $type = Twig_TemplateInterface::ANY_CALL; if ($token->getValue() == '.') { $token = $stream->next(); if ($token->getType() == Twig_Token::NAME_TYPE || $token->getType() == Twig_Token::NUMBER_TYPE || $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); } } else { $type = Twig_TemplateInterface::ARRAY_CALL; $arg = $this->parseExpression(); // slice? if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { $stream->next(); if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { $length = new Twig_Node_Expression_Constant(null, $token->getLine()); } else { $length = $this->parseExpression(); } $class = $this->getFilterNodeClass('slice'); $arguments = new Twig_Node(array($arg, $length)); $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); return $filter; } $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); } return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno); }
protected function getArguments($callable, $arguments) { $callType = $this->getAttribute('type'); $callName = $this->getAttribute('name'); $parameters = array(); $named = false; foreach ($arguments as $name => $node) { if (!is_int($name)) { $named = true; $name = $this->normalizeName($name); } elseif ($named) { throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName)); } $parameters[$name] = $node; } $isVariadic = $this->hasAttribute('is_variadic') && $this->getAttribute('is_variadic'); if (!$named && !$isVariadic) { return $parameters; } if (!$callable) { if ($named) { $message = sprintf('Named arguments are not supported for %s "%s".', $callType, $callName); } else { $message = sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName); } throw new LogicException($message); } // manage named arguments if (is_array($callable)) { $r = new ReflectionMethod($callable[0], $callable[1]); } elseif (is_object($callable) && !$callable instanceof Closure) { $r = new ReflectionObject($callable); $r = $r->getMethod('__invoke'); } elseif (is_string($callable) && false !== strpos($callable, '::')) { $r = new ReflectionMethod($callable); } else { $r = new ReflectionFunction($callable); } $definition = $r->getParameters(); if ($this->hasNode('node')) { array_shift($definition); } if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { array_shift($definition); } if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { array_shift($definition); } if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) { foreach ($this->getAttribute('arguments') as $argument) { array_shift($definition); } } if ($isVariadic) { $argument = end($definition); if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && array() === $argument->getDefaultValue()) { array_pop($definition); } else { $callableName = $r->name; if ($r->getDeclaringClass()) { $callableName = $r->getDeclaringClass()->name . '::' . $callableName; } throw new LogicException(sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = array()".', $callableName, $callType, $callName)); } } $arguments = array(); $names = array(); $missingArguments = array(); $optionalArguments = array(); $pos = 0; foreach ($definition as $param) { $names[] = $name = $this->normalizeName($param->name); if (array_key_exists($name, $parameters)) { if (array_key_exists($pos, $parameters)) { throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName)); } if (!empty($missingArguments)) { throw new Twig_Error_Syntax(sprintf('Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".', $name, $callType, $callName, implode(', ', $names), count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments))); } $arguments = array_merge($arguments, $optionalArguments); $arguments[] = $parameters[$name]; unset($parameters[$name]); $optionalArguments = array(); } elseif (array_key_exists($pos, $parameters)) { $arguments = array_merge($arguments, $optionalArguments); $arguments[] = $parameters[$pos]; unset($parameters[$pos]); $optionalArguments = array(); ++$pos; } elseif ($param->isDefaultValueAvailable()) { $optionalArguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1); } elseif ($param->isOptional()) { if (empty($parameters)) { break; } else { $missingArguments[] = $name; } } else { throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $callType, $callName)); } } if ($isVariadic) { $arbitraryArguments = new Twig_Node_Expression_Array(array(), -1); foreach ($parameters as $key => $value) { if (is_int($key)) { $arbitraryArguments->addElement($value); } else { $arbitraryArguments->addElement($value, new Twig_Node_Expression_Constant($key, -1)); } unset($parameters[$key]); } if ($arbitraryArguments->count()) { $arguments = array_merge($arguments, $optionalArguments); $arguments[] = $arbitraryArguments; } } if (!empty($parameters)) { $unknownParameter = null; foreach ($parameters as $parameter) { if ($parameter instanceof Twig_Node) { $unknownParameter = $parameter; break; } } throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s(%s)".', count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $callType, $callName, implode(', ', $names)), $unknownParameter ? $unknownParameter->getLine() : -1); } return $arguments; }
public function compile(\Twig_Compiler $compiler) { $compiler->addDebugInfo($this); $compiler->raw('$this->env->getRuntime(\'' . TwigRenderer::class . '\')->searchAndRenderBlock('); preg_match('/_([^_]+)$/', $this->getAttribute('name'), $matches); // Use the suffix to determine which properties must be extracted, from the view. // Allow the label to be overwritten? $label = null; $arguments = iterator_to_array($this->getNode('arguments')); $blockNameSuffix = $matches[1]; // The suffix is extracted from the function name, but calling the // function `rollerworks_datagrid_container` is rather redundant. // Else the block would be named `datagrid_datagrid`... if ('datagrid' === $blockNameSuffix) { $blockNameSuffix = 'container'; } if (isset($arguments[0])) { $compiler->subcompile($arguments[0]); $compiler->raw(', \'' . $blockNameSuffix . '\''); if (isset($arguments[1])) { if ('header' === $blockNameSuffix) { // The "label" function expects the label in the second and // the variables in the third argument $label = $arguments[1]; $variables = isset($arguments[2]) ? $arguments[2] : null; $lineno = $label->getLine(); if ($label instanceof \Twig_Node_Expression_Constant) { // If the label argument is given as a constant, we can either // strip it away if it is empty, or integrate it into the array // of variables at compile time. $labelIsExpression = false; // Only insert the label into the array if it is not empty if (!twig_test_empty($label->getAttribute('value'))) { $originalVariables = $variables; $variables = new \Twig_Node_Expression_Array([], $lineno); $labelKey = new \Twig_Node_Expression_Constant('label', $lineno); if (null !== $originalVariables) { foreach ($originalVariables->getKeyValuePairs() as $pair) { // Don't copy the original label attribute over if it exists if ((string) $labelKey !== (string) $pair['key']) { $variables->addElement($pair['value'], $pair['key']); } } } // Insert the label argument into the array $variables->addElement($label, $labelKey); } } else { // The label argument is not a constant, but some kind of // expression. This expression needs to be evaluated at runtime. // Depending on the result (whether it is null or not), the // label in the arguments should take precedence over the label // in the attributes or not. $labelIsExpression = true; } } else { // All other functions than "label" expect the variables // in the second argument $label = null; $variables = $arguments[1]; $labelIsExpression = false; } if (null !== $variables || $labelIsExpression) { $compiler->raw(', '); if (null !== $variables) { $compiler->subcompile($variables); } if ($labelIsExpression) { if (null !== $variables) { $compiler->raw(' + '); } // Check at runtime whether the label is empty. // If not, add it to the array at runtime. $compiler->raw('(twig_test_empty($_label_ = '); $compiler->subcompile($label); $compiler->raw(') ? [] : ["label" => $_label_])'); } } } } $compiler->raw(')'); }
protected function getArguments($callable, $arguments) { $callType = $this->getAttribute('type'); $callName = $this->getAttribute('name'); $parameters = array(); $named = false; foreach ($arguments as $name => $node) { if (!is_int($name)) { $named = true; $name = $this->normalizeName($name); } elseif ($named) { throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName)); } $parameters[$name] = $node; } $isVariadic = $this->hasAttribute('is_variadic') && $this->getAttribute('is_variadic'); if (!$named && !$isVariadic) { return $parameters; } if (!$callable) { if ($named) { $message = sprintf('Named arguments are not supported for %s "%s".', $callType, $callName); } else { $message = sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName); } throw new LogicException($message); } $callableParameters = $this->getCallableParameters($callable, $isVariadic); $arguments = array(); $names = array(); $missingArguments = array(); $optionalArguments = array(); $pos = 0; foreach ($callableParameters as $callableParameter) { $names[] = $name = $this->normalizeName($callableParameter->name); if (array_key_exists($name, $parameters)) { if (array_key_exists($pos, $parameters)) { throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName)); } if (!empty($missingArguments)) { throw new Twig_Error_Syntax(sprintf('Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".', $name, $callType, $callName, implode(', ', $names), count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments))); } $arguments = array_merge($arguments, $optionalArguments); $arguments[] = $parameters[$name]; unset($parameters[$name]); $optionalArguments = array(); } elseif (array_key_exists($pos, $parameters)) { $arguments = array_merge($arguments, $optionalArguments); $arguments[] = $parameters[$pos]; unset($parameters[$pos]); $optionalArguments = array(); ++$pos; } elseif ($callableParameter->isDefaultValueAvailable()) { $optionalArguments[] = new Twig_Node_Expression_Constant($callableParameter->getDefaultValue(), -1); } elseif ($callableParameter->isOptional()) { if (empty($parameters)) { break; } else { $missingArguments[] = $name; } } else { throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $callType, $callName)); } } if ($isVariadic) { $arbitraryArguments = new Twig_Node_Expression_Array(array(), -1); foreach ($parameters as $key => $value) { if (is_int($key)) { $arbitraryArguments->addElement($value); } else { $arbitraryArguments->addElement($value, new Twig_Node_Expression_Constant($key, -1)); } unset($parameters[$key]); } if ($arbitraryArguments->count()) { $arguments = array_merge($arguments, $optionalArguments); $arguments[] = $arbitraryArguments; } } if (!empty($parameters)) { $unknownParameter = null; foreach ($parameters as $parameter) { if ($parameter instanceof Twig_Node) { $unknownParameter = $parameter; break; } } throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s(%s)".', count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $callType, $callName, implode(', ', $names)), $unknownParameter ? $unknownParameter->getTemplateLine() : -1); } return $arguments; }
public function compile(\Twig_Compiler $compiler) { $compiler->addDebugInfo($this); $compiler->raw('$this->env->getExtension(\'table\')->renderer->searchAndRenderBlock('); preg_match('/_([^_]+)$/', $this->getAttribute('name'), $matches); $label = null; $arguments = iterator_to_array($this->getNode('arguments')); $blockNameSuffix = $matches[1]; if (isset($arguments[0])) { $compiler->subcompile($arguments[0]); $compiler->raw(', \'' . $blockNameSuffix . '\''); if (isset($arguments[1])) { if ('label' === $blockNameSuffix) { // The "label" function expects the label in the second and // the variables in the third argument $label = $arguments[1]; $variables = isset($arguments[2]) ? $arguments[2] : null; $lineno = $label->getLine(); if ($label instanceof \Twig_Node_Expression_Constant) { // If the label argument is given as a constant, we can either // strip it away if it is empty, or integrate it into the array // of variables at compile time. $labelIsExpression = false; // Only insert the label into the array if it is not empty if (!twig_test_empty($label->getAttribute('value'))) { $originalVariables = $variables; $variables = new \Twig_Node_Expression_Array(array(), $lineno); $labelKey = new \Twig_Node_Expression_Constant('label', $lineno); if (null !== $originalVariables) { foreach ($originalVariables->getKeyValuePairs() as $pair) { // Don't copy the original label attribute over if it exists if ((string) $labelKey !== (string) $pair['key']) { $variables->addElement($pair['value'], $pair['key']); } } } // Insert the label argument into the array $variables->addElement($label, $labelKey); } } else { // The label argument is not a constant, but some kind of // expression. This expression needs to be evaluated at runtime. // Depending on the result (whether it is null or not), the // label in the arguments should take precedence over the label // in the attributes or not. $labelIsExpression = true; } } else { // All other functions than "label" expect the variables // in the second argument $label = null; $variables = $arguments[1]; $labelIsExpression = false; } if (null !== $variables || $labelIsExpression) { $compiler->raw(', '); if (null !== $variables) { $compiler->subcompile($variables); } if ($labelIsExpression) { if (null !== $variables) { $compiler->raw(' + '); } // Check at runtime whether the label is empty. // If not, add it to the array at runtime. $compiler->raw('(twig_test_empty($_label_ = '); $compiler->subcompile($label); $compiler->raw(') ? array() : array("label" => $_label_))'); } } } } $compiler->raw(")"); }
/** * @covers Twig_Node_Expression_Array::__construct */ public function testConstructor() { $elements = array(new Twig_Node_Expression_Constant('foo', 1), $foo = new Twig_Node_Expression_Constant('bar', 1)); $node = new Twig_Node_Expression_Array($elements, 1); $this->assertEquals($foo, $node->getNode(1)); }
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; }
public function parseSubscriptExpression($node) { $stream = $this->parser->getStream(); $token = $stream->next(); $lineno = $token->getLine(); $arguments = new Twig_Node_Expression_Array(array(), $lineno); $type = Twig_Template::ANY_CALL; if ($token->getValue() == '.') { $token = $stream->next(); if ($token->getType() == Twig_Token::NAME_TYPE || $token->getType() == Twig_Token::NUMBER_TYPE || $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_Template::METHOD_CALL; foreach ($this->parseArguments() as $n) { $arguments->addElement($n); } } } else { throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename()); } if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { if (!$arg instanceof Twig_Node_Expression_Constant) { throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename()); } $name = $arg->getAttribute('value'); $node = new Twig_Node_Expression_MethodCall($node, 'macro_' . $name, $arguments, $lineno); $node->setAttribute('safe', true); return $node; } if ($node instanceof Twig_Node_Expression_Name && null !== ($symbol = $this->parser->getImportedSymbol('types', $node->getAttribute('name'))) && false === $this->parser->getEnvironment()->hasExtension('sandbox')) { $class = $symbol['name']; if (0 === strcasecmp($class, 'array')) { $type = Twig_Template::ARRAY_CALL; return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno); } if (!class_exists($class)) { throw new Twig_Error_Syntax(sprintf('Class "%s" set for %s was not found.', $class, $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename()); } $name = $arg->getAttribute('value'); if (Twig_Template::METHOD_CALL !== $type) { $vars = get_class_vars($class); if (isset($vars[$name])) { if ($this->parser->getEnvironment()->hasExtension('sandbox')) { $this->parser->getEnvironment()->getExtension('sandbox')->checkPropertyAllowed($class, $name); } return new Twig_Node_Expression_GetProperty($node, $name, $lineno); } } $methods = array_change_key_case(array_flip(get_class_methods($class))); $lcItem = strtolower($name); if (isset($methods[$lcItem])) { $method = (string) $name; } elseif (isset($methods['get' . $lcItem])) { $method = 'get' . $name; } elseif (isset($methods['is' . $lcItem])) { $method = 'is' . $name; } elseif (isset($methods['__call'])) { $method = (string) $name; } if (isset($method)) { return new Twig_Node_Expression_MethodCall($node, $method, $arguments, $lineno); } } } else { $type = Twig_Template::ARRAY_CALL; // slice? $slice = false; if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { $slice = true; $arg = new Twig_Node_Expression_Constant(0, $token->getLine()); } else { $arg = $this->parseExpression(); } if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { $slice = true; } if ($slice) { if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { $length = new Twig_Node_Expression_Constant(null, $token->getLine()); } else { $length = $this->parseExpression(); } $class = $this->getFilterNodeClass('slice', $token->getLine()); $arguments = new Twig_Node(array($arg, $length)); $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); return $filter; } $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); } return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno); }
public function parseHashExpression() { $stream = $this->parser->getStream(); $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected'); $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); $first = true; while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { if (!$first) { $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma'); // trailing ,? if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { break; } } $first = false; // a hash key can be: // // * a number -- 12 // * a string -- 'a' // * a name, which is equivalent to a string -- a // * an expression, which must be enclosed in parentheses -- (1 + 2) if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || ($token = $stream->nextIf(Twig_Token::NUMBER_TYPE))) { $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { $key = $this->parseExpression(); } else { $current = $stream->getCurrent(); throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $this->parser->getFilename()); } $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); $value = $this->parseExpression(); $node->addElement($value, $key); } $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed'); return $node; }
/** * @param ArrayNode $node * @return array */ private function collectConstantValues(ArrayNode $node) { $values = array(); foreach ($node->getKeyValuePairs() as $pair) { if (!$pair['key'] instanceof ConstantNode) { continue; } $value = null; if ($pair['value'] instanceof ConstantNode) { $value = $pair['value']->getAttribute('value'); } elseif ($pair['value'] instanceof ArrayNode) { $value = $this->collectConstantValues($pair['value']); } $values[$pair['key']->getAttribute('value')] = $value; } return $values; }