Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Utils
  • none
  • Tracy
    • Bridges
      • Nette

Classes

  • Compiler
  • Engine
  • HtmlNode
  • MacroNode
  • MacroTokens
  • Parser
  • PhpWriter
  • Token

Interfaces

  • ILoader
  • IMacro

Traits

  • Strict

Exceptions

  • CompileException
  • RegexpException
  • RuntimeException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Latte (https://latte.nette.org)
  5:  * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Latte;
  9: 
 10: 
 11: /**
 12:  * Templating engine Latte.
 13:  */
 14: class Engine
 15: {
 16:     use Strict;
 17: 
 18:     const VERSION = '2.4.2';
 19: 
 20:     /** Content types */
 21:     const CONTENT_HTML = 'html',
 22:         CONTENT_XHTML = 'xhtml',
 23:         CONTENT_XML = 'xml',
 24:         CONTENT_JS = 'js',
 25:         CONTENT_CSS = 'css',
 26:         CONTENT_ICAL = 'ical',
 27:         CONTENT_TEXT = 'text';
 28: 
 29:     /** @var callable[] */
 30:     public $onCompile = [];
 31: 
 32:     /** @var Parser */
 33:     private $parser;
 34: 
 35:     /** @var Compiler */
 36:     private $compiler;
 37: 
 38:     /** @var ILoader */
 39:     private $loader;
 40: 
 41:     /** @var Runtime\FilterExecutor */
 42:     private $filters;
 43: 
 44:     /** @var array */
 45:     private $providers = [];
 46: 
 47:     /** @var string */
 48:     private $contentType = self::CONTENT_HTML;
 49: 
 50:     /** @var string */
 51:     private $tempDirectory;
 52: 
 53:     /** @var bool */
 54:     private $autoRefresh = TRUE;
 55: 
 56: 
 57: 
 58:     public function __construct()
 59:     {
 60:         $this->filters = new Runtime\FilterExecutor;
 61:     }
 62: 
 63: 
 64:     /**
 65:      * Renders template to output.
 66:      * @return void
 67:      */
 68:     public function render($name, array $params = [], $block = NULL)
 69:     {
 70:         $this->createTemplate($name, $params + ['_renderblock' => $block])
 71:             ->render();
 72:     }
 73: 
 74: 
 75:     /**
 76:      * Renders template to string.
 77:      * @return string
 78:      */
 79:     public function renderToString($name, array $params = [], $block = NULL)
 80:     {
 81:         $template = $this->createTemplate($name, $params + ['_renderblock' => $block]);
 82:         return $template->capture([$template, 'render']);
 83:     }
 84: 
 85: 
 86:     /**
 87:      * Creates template object.
 88:      * @return Runtime\Template
 89:      */
 90:     public function createTemplate($name, array $params = [])
 91:     {
 92:         $class = $this->getTemplateClass($name);
 93:         if (!class_exists($class, FALSE)) {
 94:             $this->loadTemplate($name);
 95:         }
 96:         return new $class($this, $params, $this->filters, $this->providers, $name);
 97:     }
 98: 
 99: 
100:     /**
101:      * Compiles template to PHP code.
102:      * @return string
103:      */
104:     public function compile($name)
105:     {
106:         foreach ($this->onCompile ?: [] as $cb) {
107:             call_user_func(Helpers::checkCallback($cb), $this);
108:         }
109:         $this->onCompile = [];
110: 
111:         $source = $this->getLoader()->getContent($name);
112: 
113:         try {
114:             $tokens = $this->getParser()->setContentType($this->contentType)
115:                 ->parse($source);
116: 
117:             $code = $this->getCompiler()->setContentType($this->contentType)
118:                 ->compile($tokens, $this->getTemplateClass($name));
119: 
120:         } catch (\Exception $e) {
121:             if (!$e instanceof CompileException) {
122:                 $e = new CompileException("Thrown exception '{$e->getMessage()}'", NULL, $e);
123:             }
124:             $line = isset($tokens) ? $this->getCompiler()->getLine() : $this->getParser()->getLine();
125:             throw $e->setSource($source, $line, $name);
126:         }
127: 
128:         if (!preg_match('#\n|\?#', $name)) {
129:             $code = "<?php\n// source: $name\n?>" . $code;
130:         }
131:         $code = PhpHelpers::reformatCode($code);
132:         return $code;
133:     }
134: 
135: 
136:     /**
137:      * Compiles template to cache.
138:      * @param  string
139:      * @return void
140:      * @throws \LogicException
141:      */
142:     public function warmupCache($name)
143:     {
144:         if (!$this->tempDirectory) {
145:             throw new \LogicException('Path to temporary directory is not set.');
146:         }
147: 
148:         $class = $this->getTemplateClass($name);
149:         if (!class_exists($class, FALSE)) {
150:             $this->loadTemplate($name);
151:         }
152:     }
153: 
154: 
155:     /**
156:      * @return void
157:      */
158:     private function loadTemplate($name)
159:     {
160:         if (!$this->tempDirectory) {
161:             $code = $this->compile($name);
162:             if (@eval('?>' . $code) === FALSE) { // @ is escalated to exception
163:                 throw (new CompileException('Error in template: ' . error_get_last()['message']))
164:                     ->setSource($code, error_get_last()['line'], "$name (compiled)");
165:             }
166:             return;
167:         }
168: 
169:         $file = $this->getCacheFile($name);
170: 
171:         if (!$this->isExpired($file, $name) && (@include $file) !== FALSE) { // @ - file may not exist
172:             return;
173:         }
174: 
175:         if (!is_dir($this->tempDirectory)) {
176:             @mkdir($this->tempDirectory); // @ - directory may already exist
177:         }
178: 
179:         $handle = fopen("$file.lock", 'c+');
180:         if (!$handle || !flock($handle, LOCK_EX)) {
181:             throw new \RuntimeException("Unable to acquire exclusive lock '$file.lock'.");
182:         }
183: 
184:         if (!is_file($file) || $this->isExpired($file, $name)) {
185:             $code = $this->compile($name);
186:             if (file_put_contents("$file.tmp", $code) !== strlen($code) || !rename("$file.tmp", $file)) {
187:                 @unlink("$file.tmp"); // @ - file may not exist
188:                 throw new \RuntimeException("Unable to create '$file'.");
189:             } elseif (function_exists('opcache_invalidate')) {
190:                 @opcache_invalidate($file, TRUE); // @ can be restricted
191:             }
192:         }
193: 
194:         if ((include $file) === FALSE) {
195:             throw new \RuntimeException("Unable to load '$file'.");
196:         }
197: 
198:         flock($handle, LOCK_UN);
199:         fclose($handle);
200:         @unlink("$file.lock"); // @ file may become locked on Windows
201:     }
202: 
203: 
204:     /**
205:      * @param  string
206:      * @param  string
207:      * @return bool
208:      */
209:     private function isExpired($file, $name)
210:     {
211:         return $this->autoRefresh && $this->getLoader()->isExpired($name, (int) @filemtime($file)); // @ - file may not exist
212:     }
213: 
214: 
215:     /**
216:      * @return string
217:      */
218:     public function getCacheFile($name)
219:     {
220:         $hash = substr($this->getTemplateClass($name), 8);
221:         $base = preg_match('#([/\\\\][\w@.-]{3,35}){1,3}\z#', $name, $m)
222:             ? preg_replace('#[^\w@.-]+#', '-', substr($m[0], 1)) . '--'
223:             : '';
224:         return "$this->tempDirectory/$base$hash.php";
225:     }
226: 
227: 
228:     /**
229:      * @return string
230:      */
231:     public function getTemplateClass($name)
232:     {
233:         $key = $this->getLoader()->getUniqueId($name) . "\00" . self::VERSION;
234:         return 'Template' . substr(md5($key), 0, 10);
235:     }
236: 
237: 
238:     /**
239:      * Registers run-time filter.
240:      * @param  string|NULL
241:      * @param  callable
242:      * @return self
243:      */
244:     public function addFilter($name, $callback)
245:     {
246:         $this->filters->add($name, $callback);
247:         return $this;
248:     }
249: 
250: 
251:     /**
252:      * Returns all run-time filters.
253:      * @return string[]
254:      */
255:     public function getFilters()
256:     {
257:         return $this->filters->getAll();
258:     }
259: 
260: 
261:     /**
262:      * Call a run-time filter.
263:      * @param  string  filter name
264:      * @param  array   arguments
265:      * @return mixed
266:      */
267:     public function invokeFilter($name, array $args)
268:     {
269:         return call_user_func_array($this->filters->$name, $args);
270:     }
271: 
272: 
273:     /**
274:      * Adds new macro.
275:      * @return self
276:      */
277:     public function addMacro($name, IMacro $macro)
278:     {
279:         $this->getCompiler()->addMacro($name, $macro);
280:         return $this;
281:     }
282: 
283: 
284:     /**
285:      * Adds new provider.
286:      * @return self
287:      */
288:     public function addProvider($name, $value)
289:     {
290:         $this->providers[$name] = $value;
291:         return $this;
292:     }
293: 
294: 
295:     /**
296:      * Returns all providers.
297:      * @return array
298:      */
299:     public function getProviders()
300:     {
301:         return $this->providers;
302:     }
303: 
304: 
305:     /**
306:      * @return self
307:      */
308:     public function setContentType($type)
309:     {
310:         $this->contentType = $type;
311:         return $this;
312:     }
313: 
314: 
315:     /**
316:      * Sets path to temporary directory.
317:      * @return self
318:      */
319:     public function setTempDirectory($path)
320:     {
321:         $this->tempDirectory = $path;
322:         return $this;
323:     }
324: 
325: 
326:     /**
327:      * Sets auto-refresh mode.
328:      * @return self
329:      */
330:     public function setAutoRefresh($on = TRUE)
331:     {
332:         $this->autoRefresh = (bool) $on;
333:         return $this;
334:     }
335: 
336: 
337:     /**
338:      * @return Parser
339:      */
340:     public function getParser()
341:     {
342:         if (!$this->parser) {
343:             $this->parser = new Parser;
344:         }
345:         return $this->parser;
346:     }
347: 
348: 
349:     /**
350:      * @return Compiler
351:      */
352:     public function getCompiler()
353:     {
354:         if (!$this->compiler) {
355:             $this->compiler = new Compiler;
356:             Macros\CoreMacros::install($this->compiler);
357:             Macros\BlockMacros::install($this->compiler);
358:         }
359:         return $this->compiler;
360:     }
361: 
362: 
363:     /**
364:      * @return self
365:      */
366:     public function setLoader(ILoader $loader)
367:     {
368:         $this->loader = $loader;
369:         return $this;
370:     }
371: 
372: 
373:     /**
374:      * @return ILoader
375:      */
376:     public function getLoader()
377:     {
378:         if (!$this->loader) {
379:             $this->loader = new Loaders\FileLoader;
380:         }
381:         return $this->loader;
382:     }
383: 
384: }
385: 
Nette 2.4-20161109 API API documentation generated by ApiGen 2.8.0