/** * Returns template source code. * @return string */ public function getContent($file) { $file = $this->baseDir . $file; if ($this->baseDir && !Latte\Helpers::startsWith($this->normalizePath($file), $this->baseDir)) { throw new \RuntimeException("Template '{$file}' is not within the allowed path '{$this->baseDir}'."); } elseif (!is_file($file)) { throw new \RuntimeException("Missing template file '{$file}'."); } elseif ($this->isExpired($file, time())) { if (@touch($file) === FALSE) { trigger_error("File's modification time is in the future. Cannot update it: " . error_get_last()['message'], E_USER_WARNING); } } return file_get_contents($file); }
/** * {capture $variable} */ public function macroCapture(MacroNode $node, PhpWriter $writer) { $variable = $node->tokenizer->fetchWord(); if (!Helpers::startsWith($variable, '$')) { throw new CompileException("Invalid capture block variable '{$variable}'"); } $this->checkExtraArgs($node); $node->data->variable = $variable; return 'ob_start(function () {})'; }
/** * {block [name]} * {snippet [name [,]] [tag]} * {snippetArea [name]} * {define name} */ public function macroBlock(MacroNode $node, PhpWriter $writer) { $name = $node->tokenizer->fetchWord(); if ($node->name === 'block' && $name === FALSE) { // anonymous block return $node->modifiers === '' ? '' : 'ob_start(function () {})'; } $node->data->name = $name = ltrim($name, '#'); if ($name == NULL) { if ($node->name === 'define') { throw new CompileException('Missing block name.'); } } elseif (strpos($name, '$') !== FALSE) { // dynamic block/snippet if ($node->name === 'snippet') { for ($parent = $node->parentNode; $parent && !($parent->name === 'snippet' || $parent->name === 'snippetArea'); $parent = $parent->parentNode) { } if (!$parent) { throw new CompileException('Dynamic snippets are allowed only inside static snippet/snippetArea.'); } $parent->data->dynamic = TRUE; $node->data->leave = TRUE; $node->closingCode = "<?php \$this->global->snippetDriver->leave(); ?>"; $enterCode = '$this->global->snippetDriver->enter(' . $writer->formatWord($name) . ', "' . SnippetDriver::TYPE_DYNAMIC . '");'; if ($node->prefix) { $node->attrCode = $writer->write("<?php echo ' id=\"' . htmlSpecialChars(\$this->global->snippetDriver->getHtmlId({$writer->formatWord($name)})) . '\"' ?>"); return $writer->write($enterCode); } $tag = trim($node->tokenizer->fetchWord(), '<>'); if ($tag) { trigger_error('HTML tag specified in {snippet} is deprecated, use n:snippet.', E_USER_DEPRECATED); } $tag = $tag ? $tag : 'div'; $node->closingCode .= "\n</{$tag}>"; $this->checkExtraArgs($node); return $writer->write("?>\n<{$tag} id=\"<?php echo htmlSpecialChars(\$this->global->snippetDriver->getHtmlId({$writer->formatWord($name)})) ?>\"><?php " . $enterCode); } else { $node->data->leave = TRUE; $node->data->func = $this->generateMethodName($name); $fname = $writer->formatWord($name); $node->closingCode = '<?php ' . ($node->name === 'define' ? '' : "\$this->renderBlock({$fname}, get_defined_vars());") . ' ?>'; $blockType = var_export(implode($node->context), TRUE); $this->checkExtraArgs($node); return "\$this->checkBlockContentType({$blockType}, {$fname});" . "\$this->blockQueue[{$fname}][] = [\$this, '{$node->data->func}'];"; } } // static snippet/snippetArea if ($node->name === 'snippet' || $node->name === 'snippetArea') { if ($node->prefix && isset($node->htmlNode->attrs['id'])) { throw new CompileException('Cannot combine HTML attribute id with n:snippet.'); } $node->data->name = $name = '_' . $name; } if (isset($this->namedBlocks[$name])) { throw new CompileException("Cannot redeclare static {$node->name} '{$name}'"); } $extendsCheck = $this->namedBlocks ? '' : 'if ($this->getParentName()) return get_defined_vars();'; $this->namedBlocks[$name] = TRUE; if (Helpers::removeFilter($node->modifiers, 'escape')) { trigger_error('Macro ' . $node->getNotation() . ' provides auto-escaping, remove |escape.'); } if (Helpers::startsWith($node->context[1], Latte\Compiler::CONTEXT_HTML_ATTRIBUTE)) { $node->context[1] = ''; $node->modifiers .= '|escape'; } elseif ($node->modifiers) { $node->modifiers .= '|escape'; } $this->blockTypes[$name] = implode($node->context); $include = '$this->renderBlock(%var, ' . ($node->name === 'snippet' || $node->name === 'snippetArea' ? '$this->params' : 'get_defined_vars()') . ($node->modifiers ? ', function ($s, $type) { $_fi = new LR\\FilterInfo($type); return %modifyContent($s); }' : '') . ')'; if ($node->name === 'snippet') { if ($node->prefix) { if (isset($node->htmlNode->macroAttrs['foreach'])) { trigger_error('Combination of n:snippet with n:foreach is invalid, use n:inner-foreach.', E_USER_WARNING); } $node->attrCode = $writer->write('<?php echo \' id="\' . htmlSpecialChars($this->global->snippetDriver->getHtmlId(%var)) . \'"\' ?>', (string) substr($name, 1)); return $writer->write($include, $name); } $tag = trim($node->tokenizer->fetchWord(), '<>'); if ($tag) { trigger_error('HTML tag specified in {snippet} is deprecated, use n:snippet.', E_USER_DEPRECATED); } $tag = $tag ? $tag : 'div'; $this->checkExtraArgs($node); return $writer->write("?>\n<{$tag} id=\"<?php echo htmlSpecialChars(\$this->global->snippetDriver->getHtmlId(%var)) ?>\"><?php {$include} ?>\n</{$tag}><?php ", (string) substr($name, 1), $name); } elseif ($node->name === 'define') { $tokens = $node->tokenizer; $args = []; while ($tokens->isNext()) { $args[] = $tokens->expectNextValue($tokens::T_VARIABLE); if ($tokens->isNext()) { $tokens->expectNextValue(','); } } if ($args) { $node->data->args = 'list(' . implode(', ', $args) . ') = $_args + [' . str_repeat('NULL, ', count($args)) . '];'; } return $extendsCheck; } else { // block, snippetArea $this->checkExtraArgs($node); return $writer->write($extendsCheck . $include, $name); } }