Example #1
0
 /**
  * Access to undeclared property.
  * @throws LogicException
  */
 public function __set($name, $value)
 {
     $rc = new \ReflectionClass($this);
     $items = array_diff($rc->getProperties(\ReflectionProperty::IS_PUBLIC), $rc->getProperties(\ReflectionProperty::IS_STATIC));
     $hint = ($t = Helpers::getSuggestion($items, $name)) ? ", did you mean \${$t}?" : '.';
     throw new LogicException("Attempt to write to undeclared property {$rc->getName()}::\${$name}{$hint}");
 }
 /**
  * Calls block.
  * @return void
  */
 public static function callBlock(\stdClass $context, $name, array $params)
 {
     if (empty($context->blocks[$name])) {
         $hint = isset($context->blocks) && ($t = Latte\Helpers::getSuggestion(array_keys($context->blocks), $name)) ? ", did you mean '{$t}'?" : '.';
         throw new RuntimeException("Cannot include undefined block '{$name}'{$hint}");
     }
     $block = reset($context->blocks[$name]);
     $block($context, $params);
 }
Example #3
0
 public function addMacro($name, $begin, $end = NULL, $attr = NULL, $flags = NULL)
 {
     if (!$begin && !$end && !$attr) {
         throw new \InvalidArgumentException("At least one argument must be specified for macro '{$name}'.");
     }
     foreach ([$begin, $end, $attr] as $arg) {
         if ($arg && !is_string($arg)) {
             Latte\Helpers::checkCallback($arg);
         }
     }
     $this->macros[$name] = [$begin, $end, $attr];
     $this->compiler->addMacro($name, $this, $flags);
     return $this;
 }
Example #4
0
 /**
  * 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);
 }
Example #5
0
 /**
  * Renders block.
  * @param  string
  * @param  array
  * @param  string|\Closure content-type name or modifier closure
  * @return void
  * @internal
  */
 protected function renderBlock($name, array $params, $mod = NULL)
 {
     if (empty($this->blockQueue[$name])) {
         $hint = isset($this->blockQueue) && ($t = Latte\Helpers::getSuggestion(array_keys($this->blockQueue), $name)) ? ", did you mean '{$t}'?" : '.';
         throw new \RuntimeException("Cannot include undefined block '{$name}'{$hint}");
     }
     $block = reset($this->blockQueue[$name]);
     if ($mod && $mod !== ($blockType = $this->blockTypes[$name])) {
         if ($filter = is_string($mod) ? Filters::getConvertor($blockType, $mod) : $mod) {
             echo $filter($this->capture(function () use($block, $params) {
                 $block($params);
             }), $blockType);
             return;
         }
         trigger_error("Including block {$name} with content type " . strtoupper($blockType) . ' into incompatible type ' . strtoupper($mod) . '.', E_USER_WARNING);
     }
     $block($params);
 }
Example #6
0
 /**
  * {use class MacroSet}
  */
 public function macroUse(MacroNode $node, PhpWriter $writer)
 {
     if ($node->modifiers) {
         trigger_error("Modifiers are not allowed in {{$node->name}}", E_USER_WARNING);
     }
     call_user_func(Latte\Helpers::checkCallback(array($node->tokenizer->fetchWord(), 'install')), $this->getCompiler())->initialize();
 }
Example #7
0
 /**
  * {use class MacroSet}
  */
 public function macroUse(MacroNode $node, PhpWriter $writer)
 {
     if ($node->modifiers) {
         throw new CompileException("Modifiers are not allowed in {{$node->name}}");
     }
     call_user_func(Latte\Helpers::checkCallback([$node->tokenizer->fetchWord(), 'install']), $this->getCompiler())->initialize();
 }
Example #8
0
 public static function optimizePhp($source, $lineLength = 80)
 {
     return Latte\Helpers::optimizePhp($source, $lineLength);
 }
Example #9
0
 /**
  * {use class MacroSet}
  */
 public function macroUse(MacroNode $node, PhpWriter $writer)
 {
     call_user_func(Latte\Helpers::checkCallback(array($node->tokenizer->fetchWord(), 'install')), $this->getCompiler())->initialize();
 }
Example #10
0
 /**
  * {foreach ...}
  */
 public function macroEndForeach(MacroNode $node, PhpWriter $writer)
 {
     $noCheck = Helpers::removeFilter($node->modifiers, 'nocheck');
     $noIterator = Helpers::removeFilter($node->modifiers, 'noiterator');
     if ($node->modifiers) {
         throw new CompileException('Only modifiers |noiterator and |nocheck are allowed here.');
     }
     $node->openingCode = '<?php $iterations = 0; ';
     $args = $writer->formatArgs();
     if (!$noCheck) {
         preg_match('#.+\\s+as\\s*\\$(\\w+)(?:\\s*=>\\s*\\$(\\w+))?#i', $args, $m);
         for ($i = 1; $i < count($m); $i++) {
             $this->overwrittenVars[$m[$i]][] = $node->startLine;
         }
     }
     if (!$noIterator && preg_match('#\\W(\\$iterator|include|require|get_defined_vars)\\W#', $this->getCompiler()->expandTokens($node->content))) {
         $node->openingCode .= 'foreach ($iterator = $this->global->its[] = new LR\\CachingIterator(' . preg_replace('#(.*)\\s+as\\s+#i', '$1) as ', $args, 1) . ') { ?>';
         $node->closingCode = '<?php $iterations++; } array_pop($this->global->its); $iterator = end($this->global->its); ?>';
     } else {
         $node->openingCode .= 'foreach (' . $args . ') { ?>';
         $node->closingCode = '<?php $iterations++; } ?>';
     }
 }
Example #11
0
 private function prepareFilter($name)
 {
     if (!isset($this->_static[$name][1])) {
         $callback = Helpers::checkCallback($this->_static[$name][0]);
         if (is_string($callback) && strpos($callback, '::')) {
             $callback = explode('::', $callback);
         } elseif (is_object($callback)) {
             $callback = [$callback, '__invoke'];
         }
         $ref = is_array($callback) ? new \ReflectionMethod($callback[0], $callback[1]) : new \ReflectionFunction($callback);
         $this->_static[$name][1] = ($tmp = $ref->getParameters()) && $tmp[0]->getClass() && $tmp[0]->getClass()->getName() === 'Latte\\Runtime\\FilterInfo';
     }
     return $this->_static[$name];
 }
Example #12
0
 /**
  * {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);
     }
 }