Namespaces

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

Classes

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

Interfaces

  • ILoader
  • IMacro

Exceptions

  • CompileException
  • RegexpException
  • RuntimeException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  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:  * @author     David Grudl
 15:  */
 16: class Engine extends Object
 17: {
 18:     const VERSION = '2.2.9';
 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_URL = 'url',
 27:         CONTENT_ICAL = 'ical',
 28:         CONTENT_TEXT = 'text';
 29: 
 30:     /** @var callable[] */
 31:     public $onCompile = array();
 32: 
 33:     /** @var Parser */
 34:     private $parser;
 35: 
 36:     /** @var Compiler */
 37:     private $compiler;
 38: 
 39:     /** @var ILoader */
 40:     private $loader;
 41: 
 42:     /** @var string */
 43:     private $contentType = self::CONTENT_HTML;
 44: 
 45:     /** @var string */
 46:     private $tempDirectory;
 47: 
 48:     /** @var bool */
 49:     private $autoRefresh = TRUE;
 50: 
 51:     /** @var array run-time filters */
 52:     private $filters = array(
 53:         NULL => array(), // dynamic
 54:         'bytes' => 'Latte\Runtime\Filters::bytes',
 55:         'capitalize' => 'Latte\Runtime\Filters::capitalize',
 56:         'datastream' => 'Latte\Runtime\Filters::dataStream',
 57:         'date' => 'Latte\Runtime\Filters::date',
 58:         'escapecss' => 'Latte\Runtime\Filters::escapeCss',
 59:         'escapehtml' => 'Latte\Runtime\Filters::escapeHtml',
 60:         'escapehtmlcomment' => 'Latte\Runtime\Filters::escapeHtmlComment',
 61:         'escapeical' => 'Latte\Runtime\Filters::escapeICal',
 62:         'escapejs' => 'Latte\Runtime\Filters::escapeJs',
 63:         'escapeurl' => 'rawurlencode',
 64:         'escapexml' => 'Latte\Runtime\Filters::escapeXML',
 65:         'firstupper' => 'Latte\Runtime\Filters::firstUpper',
 66:         'implode' => 'implode',
 67:         'indent' => 'Latte\Runtime\Filters::indent',
 68:         'lower' => 'Latte\Runtime\Filters::lower',
 69:         'nl2br' => 'Latte\Runtime\Filters::nl2br',
 70:         'number' => 'number_format',
 71:         'repeat' => 'str_repeat',
 72:         'replace' => 'Latte\Runtime\Filters::replace',
 73:         'replacere' => 'Latte\Runtime\Filters::replaceRe',
 74:         'safeurl' => 'Latte\Runtime\Filters::safeUrl',
 75:         'strip' => 'Latte\Runtime\Filters::strip',
 76:         'striptags' => 'strip_tags',
 77:         'substr' => 'Latte\Runtime\Filters::substring',
 78:         'trim' => 'Latte\Runtime\Filters::trim',
 79:         'truncate' => 'Latte\Runtime\Filters::truncate',
 80:         'upper' => 'Latte\Runtime\Filters::upper',
 81:     );
 82: 
 83:     /** @var string */
 84:     private $baseTemplateClass = 'Latte\Template';
 85: 
 86: 
 87:     /**
 88:      * Renders template to output.
 89:      * @return void
 90:      */
 91:     public function render($name, array $params = array())
 92:     {
 93:         $template = new $this->baseTemplateClass($params, $this, $name);
 94:         $this->loadCacheFile($name, $template->getParameters());
 95:     }
 96: 
 97: 
 98:     /**
 99:      * Renders template to string.
100:      * @return string
101:      */
102:     public function renderToString($name, array $params = array())
103:     {
104:         ob_start();
105:         try {
106:             $this->render($name, $params);
107:         } catch (\Throwable $e) {
108:             ob_end_clean();
109:             throw $e;
110:         } catch (\Exception $e) {
111:             ob_end_clean();
112:             throw $e;
113:         }
114:         return ob_get_clean();
115:     }
116: 
117: 
118:     /**
119:      * Compiles template to PHP code.
120:      * @return string
121:      */
122:     public function compile($name)
123:     {
124:         foreach ($this->onCompile ?: array() as $cb) {
125:             call_user_func(Helpers::checkCallback($cb), $this);
126:         }
127:         $this->onCompile = array();
128: 
129:         $source = $this->getLoader()->getContent($name);
130:         try {
131:             $tokens = $this->getParser()->setContentType($this->contentType)
132:                 ->parse($source);
133:             $code = $this->getCompiler()->setContentType($this->contentType)
134:                 ->compile($tokens);
135: 
136:             if (!preg_match('#\n|\?#', $name)) {
137:                 $code = "<?php\n// source: $name\n?>" . $code;
138:             }
139: 
140:         } catch (\Exception $e) {
141:             $e = $e instanceof CompileException ? $e : new CompileException("Thrown exception '{$e->getMessage()}'", NULL, $e);
142:             throw $e->setSource($source, $this->getCompiler()->getLine(), $name);
143:         }
144:         $code = Helpers::optimizePhp($code);
145:         return $code;
146:     }
147: 
148: 
149:     /**
150:      * @return void
151:      */
152:     private function loadCacheFile($name, $params)
153:     {
154:         if (!$this->tempDirectory) {
155:             return call_user_func(function () {
156:                 foreach (func_get_arg(1) as $__k => $__v) {
157:                     $$__k = $__v;
158:                 }
159:                 unset($__k, $__v);
160:                 eval('?>' . func_get_arg(0));
161:             }, $this->compile($name), $params);
162:         }
163: 
164:         $file = $this->getCacheFile($name);
165:         $handle = fopen($file, 'c+');
166:         if (!$handle) {
167:             throw new \RuntimeException("Unable to open or create file '$file'.");
168:         }
169:         flock($handle, LOCK_SH);
170:         $stat = fstat($handle);
171:         if (!$stat['size'] || ($this->autoRefresh && $this->getLoader()->isExpired($name, $stat['mtime']))) {
172:             ftruncate($handle, 0);
173:             flock($handle, LOCK_EX);
174:             $stat = fstat($handle);
175:             if (!$stat['size']) {
176:                 $code = $this->compile($name);
177:                 if (fwrite($handle, $code, strlen($code)) !== strlen($code)) {
178:                     ftruncate($handle, 0);
179:                     throw new \RuntimeException("Unable to write file '$file'.");
180:                 }
181:             }
182:             flock($handle, LOCK_SH); // holds the lock
183:         }
184: 
185:         call_user_func(function () {
186:             foreach (func_get_arg(1) as $__k => $__v) {
187:                 $$__k = $__v;
188:             }
189:             unset($__k, $__v);
190:             include func_get_arg(0);
191:         }, $file, $params);
192:     }
193: 
194: 
195:     /**
196:      * @return string
197:      */
198:     public function getCacheFile($name)
199:     {
200:         if (!$this->tempDirectory) {
201:             throw new \RuntimeException('Set path to temporary directory using setTempDirectory().');
202:         } elseif (!is_dir($this->tempDirectory)) {
203:             @mkdir($this->tempDirectory); // High concurrency
204:             if (!is_dir($this->tempDirectory)) {
205:                 throw new \RuntimeException("Temporary directory cannot be created. Check access rights");
206:             }
207:         }
208:         $file = md5($name);
209:         if (preg_match('#\b\w.{10,50}$#', $name, $m)) {
210:             $file = trim(preg_replace('#\W+#', '-', $m[0]), '-') . '-' . $file;
211:         }
212:         return $this->tempDirectory . '/' . $file . '.php';
213:     }
214: 
215: 
216:     /**
217:      * Registers run-time filter.
218:      * @param  string|NULL
219:      * @param  callable
220:      * @return self
221:      */
222:     public function addFilter($name, $callback)
223:     {
224:         if ($name == NULL) { // intentionally ==
225:             array_unshift($this->filters[NULL], $callback);
226:         } else {
227:             $this->filters[strtolower($name)] = $callback;
228:         }
229:         return $this;
230:     }
231: 
232: 
233:     /**
234:      * Returns all run-time filters.
235:      * @return callable[]
236:      */
237:     public function getFilters()
238:     {
239:         return $this->filters;
240:     }
241: 
242: 
243:     /**
244:      * Call a run-time filter.
245:      * @param  string  filter name
246:      * @param  array   arguments
247:      * @return mixed
248:      */
249:     public function invokeFilter($name, array $args)
250:     {
251:         $lname = strtolower($name);
252:         if (!isset($this->filters[$lname])) {
253:             $args2 = $args;
254:             array_unshift($args2, $lname);
255:             foreach ($this->filters[NULL] as $filter) {
256:                 $res = call_user_func_array(Helpers::checkCallback($filter), $args2);
257:                 if ($res !== NULL) {
258:                     return $res;
259:                 } elseif (isset($this->filters[$lname])) {
260:                     return call_user_func_array(Helpers::checkCallback($this->filters[$lname]), $args);
261:                 }
262:             }
263:             throw new \LogicException("Filter '$name' is not defined.");
264:         }
265:         return call_user_func_array(Helpers::checkCallback($this->filters[$lname]), $args);
266:     }
267: 
268: 
269:     /**
270:      * Adds new macro.
271:      * @return self
272:      */
273:     public function addMacro($name, IMacro $macro)
274:     {
275:         $this->getCompiler()->addMacro($name, $macro);
276:         return $this;
277:     }
278: 
279: 
280:     /**
281:      * @return self
282:      */
283:     public function setContentType($type)
284:     {
285:         $this->contentType = $type;
286:         return $this;
287:     }
288: 
289: 
290:     /**
291:      * Sets path to temporary directory.
292:      * @return self
293:      */
294:     public function setTempDirectory($path)
295:     {
296:         $this->tempDirectory = $path;
297:         return $this;
298:     }
299: 
300: 
301:     /**
302:      * Sets auto-refresh mode.
303:      * @return self
304:      */
305:     public function setAutoRefresh($on = TRUE)
306:     {
307:         $this->autoRefresh = (bool) $on;
308:         return $this;
309:     }
310: 
311: 
312:     /**
313:      * @return Parser
314:      */
315:     public function getParser()
316:     {
317:         if (!$this->parser) {
318:             $this->parser = new Parser;
319:         }
320:         return $this->parser;
321:     }
322: 
323: 
324:     /**
325:      * @return Compiler
326:      */
327:     public function getCompiler()
328:     {
329:         if (!$this->compiler) {
330:             $this->compiler = new Compiler;
331:             Macros\CoreMacros::install($this->compiler);
332:             Macros\BlockMacros::install($this->compiler);
333:         }
334:         return $this->compiler;
335:     }
336: 
337: 
338:     /**
339:      * @return self
340:      */
341:     public function setLoader(ILoader $loader)
342:     {
343:         $this->loader = $loader;
344:         return $this;
345:     }
346: 
347: 
348:     /**
349:      * @return ILoader
350:      */
351:     public function getLoader()
352:     {
353:         if (!$this->loader) {
354:             $this->loader = new Loaders\FileLoader;
355:         }
356:         return $this->loader;
357:     }
358: 
359: }
360: 
Nette 2.2 API documentation generated by ApiGen 2.8.0