if (empty($realChildren)) { return sprintf($this->prepare(self::PARENT_NO_CONTEXT, $level), var_export($id, true)); } return sprintf( $this->prepare(self::PARENT, $level), var_export($id, true), $this->walk($realChildren, $level + 1) ); } /** * Helper method for filtering out non-block-arg tokens. * * @param array $node * * @return bool True if $node is a block arg token */ private static function onlyBlockArgs(array $node) { return $node[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_BLOCK_ARG; } const VARIABLE = ' $value = $this->resolveValue($context->%s(%s), $context);%s $buffer .= %s%s; '; /** * Generate Mustache Template variable interpolation PHP source. * * @param string $id Variable name * @param string[] $filters Array of filters * @param bool $escape Escape the variable value for output? * @param int $level * * @return string Generated variable interpolation PHP source */ private function variable($id, $filters, $escape, $level) { $method = $this->getFindMethod($id); $id = ($method !== 'last') ? var_export($id, true) : ''; $filters = $this->getFilters($filters, $level); $value = $escape ? $this->getEscape() : '$value'; return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $filters, $this->flushIndent(), $value); } const FILTER = ' $filter = $context->%s(%s); if (!(%s)) { throw new Mustache_Exception_UnknownFilterException(%s); } $value = call_user_func($filter, $value);%s '; /** * Generate Mustache Template variable filtering PHP source. * * @param string[] $filters Array of filters * @param int $level * * @return string Generated filter PHP source */ private function getFilters(array $filters, $level) { if (empty($filters)) { return ''; } $name = array_shift($filters); $method = $this->getFindMethod($name); $filter = ($method !== 'last') ? var_export($name, true) : ''; $callable = $this->getCallable('$filter'); $msg = var_export($name, true); return sprintf($this->prepare(self::FILTER, $level), $method, $filter, $callable, $msg, $this->getFilters($filters, $level)); } const LINE = '$buffer .= "\n";'; const TEXT = '$buffer .= %s%s;'; /** * Generate Mustache Template output Buffer call PHP source. * * @param string $text * @param int $level * * @return string Generated output Buffer call PHP source */ private function text($text, $level) { $indentNextLine = (substr($text, -1) === "\n"); $code = sprintf($this->prepare(self::TEXT, $level), $this->flushIndent(), var_export($text, true)); $this->indentNextLine = $indentNextLine; return $code; } /** * Prepare PHP source code snippet for output. * * @param string $text * @param int $bonus Additional indent level (default: 0) * @param bool $prependNewline Prepend a newline to the snippet? (default: true) * @param bool $appendNewline Append a newline to the snippet? (default: false) * * @return string PHP source code snippet */ private function prepare($text, $bonus = 0, $prependNewline = true, $appendNewline = false) { $text = ($prependNewline ? "\n" : '') . trim($text); if ($prependNewline) { $bonus++; } if ($appendNewline) { $text .= "\n"; } return preg_replace("/\n( {8})?/", "\n" . str_repeat(' ', $bonus * 4), $text); } const DEFAULT_ESCAPE = 'htmlspecialchars(%s, %s, %s)'; const CUSTOM_ESCAPE = 'call_user_func($this->mustache->getEscape(), %s)'; /** * Get the current escaper. * * @param string $value (default: '$value') * * @return string Either a custom callback, or an inline call to `htmlspecialchars` */ private function getEscape($value = '$value') { if ($this->customEscape) { return sprintf(self::CUSTOM_ESCAPE, $value); } return sprintf(self::DEFAULT_ESCAPE, $value, var_export($this->entityFlags, true), var_export($this->charset, true)); } /** * Select the appropriate Context `find` method for a given $id. * * The return value will be one of `find`, `findDot`, `findAnchoredDot` or `last`. * * @see Mustache_Context::find * @see Mustache_Context::findDot * @see Mustache_Context::last * * @param string $id Variable name * * @return string `find` method name */ private function getFindMethod($id) { if ($id === '.') { return 'last