Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Diagnostics
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
      • Diagnostics
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • PhpGenerator
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
  • NetteModule
  • none

Classes

  • FileTemplate
  • Helpers
  • Template

Interfaces

  • IFileTemplate
  • ITemplate

Exceptions

  • FilterException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Templating;
  9: 
 10: use Nette;
 11: use Nette\Caching;
 12: use Nette\Utils\Callback;
 13: 
 14: 
 15: /**
 16:  * Template.
 17:  *
 18:  * @author     David Grudl
 19:  */
 20: class Template extends Nette\Object implements ITemplate
 21: {
 22:     /** @var array of function (Template $sender); Occurs before a template is compiled - implement to customize the filters */
 23:     public $onPrepareFilters = array();
 24: 
 25:     /** @var string */
 26:     private $source;
 27: 
 28:     /** @var array */
 29:     private $params = array();
 30: 
 31:     /** @var array compile-time filters */
 32:     private $filters = array();
 33: 
 34:     /** @var array run-time helpers */
 35:     private $helpers = array();
 36: 
 37:     /** @var array */
 38:     private $helperLoaders = array();
 39: 
 40:     /** @var Nette\Caching\IStorage */
 41:     private $cacheStorage;
 42: 
 43: 
 44:     /**
 45:      * Sets template source code.
 46:      * @param  string
 47:      * @return self
 48:      */
 49:     public function setSource($source)
 50:     {
 51:         $this->source = $source;
 52:         return $this;
 53:     }
 54: 
 55: 
 56:     /**
 57:      * Returns template source code.
 58:      * @return source
 59:      */
 60:     public function getSource()
 61:     {
 62:         return $this->source;
 63:     }
 64: 
 65: 
 66:     /********************* rendering ****************d*g**/
 67: 
 68: 
 69:     /**
 70:      * Renders template to output.
 71:      * @return void
 72:      */
 73:     public function render()
 74:     {
 75:         $cache = new Caching\Cache($storage = $this->getCacheStorage(), 'Nette.Template');
 76:         $cached = $compiled = $cache->load($this->source);
 77: 
 78:         if ($compiled === NULL) {
 79:             $compiled = $this->compile();
 80:             $cache->save($this->source, $compiled, array(Caching\Cache::CONSTS => 'Nette\Framework::REVISION'));
 81:             $cached = $cache->load($this->source);
 82:         }
 83: 
 84:         if ($cached !== NULL && $storage instanceof Caching\Storages\PhpFileStorage) {
 85:             Nette\Utils\LimitedScope::load($cached['file'], $this->getParameters());
 86:         } else {
 87:             Nette\Utils\LimitedScope::evaluate($compiled, $this->getParameters());
 88:         }
 89:     }
 90: 
 91: 
 92:     /**
 93:      * Renders template to file.
 94:      * @param  string
 95:      * @return void
 96:      */
 97:     public function save($file)
 98:     {
 99:         if (file_put_contents($file, $this->__toString(TRUE)) === FALSE) {
100:             throw new Nette\IOException("Unable to save file '$file'.");
101:         }
102:     }
103: 
104: 
105:     /**
106:      * Renders template to string.
107:      * @param  can throw exceptions? (hidden parameter)
108:      * @return string
109:      */
110:     public function __toString()
111:     {
112:         ob_start();
113:         try {
114:             $this->render();
115:             return ob_get_clean();
116: 
117:         } catch (\Throwable $e) {
118:         } catch (\Exception $e) {
119:         }
120:         if (isset($e)) {
121:             ob_end_clean();
122:             if (func_num_args()) {
123:                 throw $e;
124:             }
125:             trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
126:         }
127:     }
128: 
129: 
130:     /**
131:      * Applies filters on template content.
132:      * @return string
133:      */
134:     public function compile()
135:     {
136:         if (!$this->filters) {
137:             $this->onPrepareFilters($this);
138:         }
139: 
140:         $code = $this->getSource();
141:         foreach ($this->filters as $filter) {
142:             $code = self::extractPhp($code, $blocks);
143:             $code = call_user_func($filter, $code);
144:             $code = strtr($code, $blocks); // put PHP code back
145:         }
146: 
147:         return Helpers::optimizePhp($code);
148:     }
149: 
150: 
151:     /********************* template filters & helpers ****************d*g**/
152: 
153: 
154:     /**
155:      * Registers callback as template compile-time filter.
156:      * @param  callable
157:      * @return self
158:      */
159:     public function registerFilter($callback)
160:     {
161:         $this->filters[] = Callback::check($callback);
162:         return $this;
163:     }
164: 
165: 
166:     /**
167:      * Returns all registered compile-time filters.
168:      * @return array
169:      */
170:     public function getFilters()
171:     {
172:         return $this->filters;
173:     }
174: 
175: 
176:     /**
177:      * Registers callback as template run-time helper.
178:      * @param  string
179:      * @param  callable
180:      * @return self
181:      */
182:     public function registerHelper($name, $callback)
183:     {
184:         $this->helpers[strtolower($name)] = $callback;
185:         return $this;
186:     }
187: 
188: 
189:     /**
190:      * Registers callback as template run-time helpers loader.
191:      * @param  callable
192:      * @return self
193:      */
194:     public function registerHelperLoader($callback)
195:     {
196:         array_unshift($this->helperLoaders, $callback);
197:         return $this;
198:     }
199: 
200: 
201:     /**
202:      * Returns all registered run-time helpers.
203:      * @return array
204:      */
205:     public function getHelpers()
206:     {
207:         return $this->helpers;
208:     }
209: 
210: 
211:     /**
212:      * Returns all registered template run-time helper loaders.
213:      * @return array
214:      */
215:     public function getHelperLoaders()
216:     {
217:         return $this->helperLoaders;
218:     }
219: 
220: 
221:     /**
222:      * Call a template run-time helper. Do not call directly.
223:      * @param  string  helper name
224:      * @param  array   arguments
225:      * @return mixed
226:      */
227:     public function __call($name, $args)
228:     {
229:         $lname = strtolower($name);
230:         if (!isset($this->helpers[$lname])) {
231:             foreach ($this->helperLoaders as $loader) {
232:                 $helper = Callback::invoke($loader, $lname);
233:                 if ($helper) {
234:                     $this->registerHelper($lname, $helper);
235:                     return Callback::invokeArgs($this->helpers[$lname], $args);
236:                 }
237:             }
238:             return parent::__call($name, $args);
239:         }
240: 
241:         return Callback::invokeArgs($this->helpers[$lname], $args);
242:     }
243: 
244: 
245:     /**
246:      * Sets translate adapter.
247:      * @return self
248:      */
249:     public function setTranslator(Nette\Localization\ITranslator $translator = NULL)
250:     {
251:         $this->registerHelper('translate', $translator === NULL ? NULL : array($translator, 'translate'));
252:         return $this;
253:     }
254: 
255: 
256:     /********************* template parameters ****************d*g**/
257: 
258: 
259:     /**
260:      * Adds new template parameter.
261:      * @return self
262:      */
263:     public function add($name, $value)
264:     {
265:         if (array_key_exists($name, $this->params)) {
266:             throw new Nette\InvalidStateException("The variable '$name' already exists.");
267:         }
268: 
269:         $this->params[$name] = $value;
270:         return $this;
271:     }
272: 
273: 
274:     /**
275:      * Sets all parameters.
276:      * @param  array
277:      * @return self
278:      */
279:     public function setParameters(array $params)
280:     {
281:         $this->params = $params + $this->params;
282:         return $this;
283:     }
284: 
285: 
286:     /**
287:      * Returns array of all parameters.
288:      * @return array
289:      */
290:     public function getParameters()
291:     {
292:         $this->params['template'] = $this;
293:         return $this->params;
294:     }
295: 
296: 
297:     /**
298:      * Sets a template parameter. Do not call directly.
299:      * @return void
300:      */
301:     public function __set($name, $value)
302:     {
303:         $this->params[$name] = $value;
304:     }
305: 
306: 
307:     /**
308:      * Returns a template parameter. Do not call directly.
309:      * @return mixed  value
310:      */
311:     public function &__get($name)
312:     {
313:         if (!array_key_exists($name, $this->params)) {
314:             trigger_error("The variable '$name' does not exist in template.", E_USER_NOTICE);
315:         }
316: 
317:         return $this->params[$name];
318:     }
319: 
320: 
321:     /**
322:      * Determines whether parameter is defined. Do not call directly.
323:      * @return bool
324:      */
325:     public function __isset($name)
326:     {
327:         return isset($this->params[$name]);
328:     }
329: 
330: 
331:     /**
332:      * Removes a template parameter. Do not call directly.
333:      * @param  string    name
334:      * @return void
335:      */
336:     public function __unset($name)
337:     {
338:         unset($this->params[$name]);
339:     }
340: 
341: 
342:     /********************* caching ****************d*g**/
343: 
344: 
345:     /**
346:      * Set cache storage.
347:      * @return self
348:      */
349:     public function setCacheStorage(Caching\IStorage $storage)
350:     {
351:         $this->cacheStorage = $storage;
352:         return $this;
353:     }
354: 
355: 
356:     /**
357:      * @return Nette\Caching\IStorage
358:      */
359:     public function getCacheStorage()
360:     {
361:         if ($this->cacheStorage === NULL) {
362:             return new Caching\Storages\DevNullStorage;
363:         }
364:         return $this->cacheStorage;
365:     }
366: 
367: 
368:     /********************* tools ****************d*g**/
369: 
370: 
371:     /**
372:      * Extracts all blocks of PHP code.
373:      * @param  string
374:      * @param  array
375:      * @return string
376:      */
377:     private static function extractPhp($source, & $blocks)
378:     {
379:         $res = '';
380:         $blocks = array();
381:         $tokens = token_get_all($source);
382:         foreach ($tokens as $n => $token) {
383:             if (is_array($token)) {
384:                 if ($token[0] === T_INLINE_HTML) {
385:                     $res .= $token[1];
386:                     continue;
387: 
388:                 } elseif ($token[0] === T_CLOSE_TAG) {
389:                     if ($php !== $res) { // not <?xml
390:                         $res .= str_repeat("\n", substr_count($php, "\n"));
391:                     }
392:                     $res .= $token[1];
393:                     continue;
394: 
395:                 } elseif ($token[0] === T_OPEN_TAG && $token[1] === '<?' && isset($tokens[$n+1][1]) && $tokens[$n+1][1] === 'xml') {
396:                     $php = & $res;
397:                     $token[1] = '<<?php ?>?';
398: 
399:                 } elseif ($token[0] === T_OPEN_TAG || $token[0] === T_OPEN_TAG_WITH_ECHO) {
400:                     $res .= $id = "<?php \x01@php:p" . count($blocks) . "@\x02";
401:                     $php = & $blocks[$id];
402:                 }
403:                 $php .= $token[1];
404: 
405:             } else {
406:                 $php .= $token;
407:             }
408:         }
409:         return $res;
410:     }
411: 
412: }
413: 
Nette 2.1 API documentation generated by ApiGen 2.8.0