Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • 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 (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Templating;
  9: 
 10: use Nette,
 11:     Nette\Caching;
 12: 
 13: 
 14: /**
 15:  * Template.
 16:  *
 17:  * @author     David Grudl
 18:  */
 19: class Template extends Nette\Object implements ITemplate
 20: {
 21:     /** @var array of function(Template $sender); Occurs before a template is compiled - implement to customize the filters */
 22:     public $onPrepareFilters = array();
 23: 
 24:     /** @var string */
 25:     private $source;
 26: 
 27:     /** @var array */
 28:     private $params = array();
 29: 
 30:     /** @var array compile-time filters */
 31:     private $filters = array();
 32: 
 33:     /** @var array run-time helpers */
 34:     private $helpers = array();
 35: 
 36:     /** @var array */
 37:     private $helperLoaders = array();
 38: 
 39:     /** @var Nette\Caching\IStorage */
 40:     private $cacheStorage;
 41: 
 42: 
 43:     /**
 44:      * Sets template source code.
 45:      * @param  string
 46:      * @return self
 47:      */
 48:     public function setSource($source)
 49:     {
 50:         $this->source = $source;
 51:         return $this;
 52:     }
 53: 
 54: 
 55:     /**
 56:      * Returns template source code.
 57:      * @return source
 58:      */
 59:     public function getSource()
 60:     {
 61:         return $this->source;
 62:     }
 63: 
 64: 
 65:     /********************* rendering ****************d*g**/
 66: 
 67: 
 68:     /**
 69:      * Renders template to output.
 70:      * @return void
 71:      */
 72:     public function render()
 73:     {
 74:         $cache = new Caching\Cache($storage = $this->getCacheStorage(), 'Nette.Template');
 75:         $cached = $compiled = $cache->load($this->source);
 76: 
 77:         if ($compiled === NULL) {
 78:             $compiled = $this->compile();
 79:             $cache->save($this->source, $compiled, array(Caching\Cache::CONSTS => 'Nette\Framework::REVISION'));
 80:             $cached = $cache->load($this->source);
 81:         }
 82: 
 83:         if ($cached !== NULL && $storage instanceof Caching\Storages\PhpFileStorage) {
 84:             Nette\Utils\LimitedScope::load($cached['file'], $this->getParameters());
 85:         } else {
 86:             Nette\Utils\LimitedScope::evaluate($compiled, $this->getParameters());
 87:         }
 88:     }
 89: 
 90: 
 91:     /**
 92:      * Renders template to file.
 93:      * @param  string
 94:      * @return void
 95:      */
 96:     public function save($file)
 97:     {
 98:         if (file_put_contents($file, $this->__toString(TRUE)) === FALSE) {
 99:             throw new Nette\IOException("Unable to save file '$file'.");
100:         }
101:     }
102: 
103: 
104:     /**
105:      * Renders template to string.
106:      * @param  can throw exceptions? (hidden parameter)
107:      * @return string
108:      */
109:     public function __toString()
110:     {
111:         ob_start();
112:         try {
113:             $this->render();
114:             return ob_get_clean();
115: 
116:         } catch (\Exception $e) {
117:             ob_end_clean();
118:             if (func_num_args()) {
119:                 throw $e;
120:             }
121:             trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
122:         }
123:     }
124: 
125: 
126:     /**
127:      * Applies filters on template content.
128:      * @return string
129:      */
130:     public function compile()
131:     {
132:         if (!$this->filters) {
133:             $this->onPrepareFilters($this);
134:         }
135: 
136:         $code = $this->getSource();
137:         foreach ($this->filters as $filter) {
138:             $code = self::extractPhp($code, $blocks);
139:             $code = $filter($code);
140:             $code = strtr($code, $blocks); // put PHP code back
141:         }
142: 
143:         return Helpers::optimizePhp($code);
144:     }
145: 
146: 
147:     /********************* template filters & helpers ****************d*g**/
148: 
149: 
150:     /**
151:      * Registers callback as template compile-time filter.
152:      * @param  callable
153:      * @return self
154:      */
155:     public function registerFilter($callback)
156:     {
157:         $callback = new Nette\Callback($callback);
158:         if (in_array($callback, $this->filters, TRUE)) {
159:             throw new Nette\InvalidStateException("Filter '$callback' was registered twice.");
160:         }
161:         $this->filters[] = $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)] = new Nette\Callback($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:         $this->helperLoaders[] = new Nette\Callback($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 = $loader($lname);
233:                 if ($helper) {
234:                     $this->registerHelper($lname, $helper);
235:                     return $this->helpers[$lname]->invokeArgs($args);
236:                 }
237:             }
238:             return parent::__call($name, $args);
239:         }
240: 
241:         return $this->helpers[$lname]->invokeArgs($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:     /** @deprecated */
298:     function setParams(array $params)
299:     {
300:         trigger_error(__METHOD__ . '() is deprecated; use setParameters() instead.', E_USER_WARNING);
301:         return $this->setParameters($params);
302:     }
303: 
304: 
305:     /** @deprecated */
306:     function getParams()
307:     {
308:         trigger_error(__METHOD__ . '() is deprecated; use getParameters() instead.', E_USER_WARNING);
309:         return $this->getParameters();
310:     }
311: 
312: 
313:     /**
314:      * Sets a template parameter. Do not call directly.
315:      * @return void
316:      */
317:     public function __set($name, $value)
318:     {
319:         $this->params[$name] = $value;
320:     }
321: 
322: 
323:     /**
324:      * Returns a template parameter. Do not call directly.
325:      * @return mixed  value
326:      */
327:     public function &__get($name)
328:     {
329:         if (!array_key_exists($name, $this->params)) {
330:             trigger_error("The variable '$name' does not exist in template.", E_USER_NOTICE);
331:         }
332: 
333:         return $this->params[$name];
334:     }
335: 
336: 
337:     /**
338:      * Determines whether parameter is defined. Do not call directly.
339:      * @return bool
340:      */
341:     public function __isset($name)
342:     {
343:         return isset($this->params[$name]);
344:     }
345: 
346: 
347:     /**
348:      * Removes a template parameter. Do not call directly.
349:      * @param  string    name
350:      * @return void
351:      */
352:     public function __unset($name)
353:     {
354:         unset($this->params[$name]);
355:     }
356: 
357: 
358:     /********************* caching ****************d*g**/
359: 
360: 
361:     /**
362:      * Set cache storage.
363:      * @return self
364:      */
365:     public function setCacheStorage(Caching\IStorage $storage)
366:     {
367:         $this->cacheStorage = $storage;
368:         return $this;
369:     }
370: 
371: 
372:     /**
373:      * @return Nette\Caching\IStorage
374:      */
375:     public function getCacheStorage()
376:     {
377:         if ($this->cacheStorage === NULL) {
378:             return new Caching\Storages\DevNullStorage;
379:         }
380:         return $this->cacheStorage;
381:     }
382: 
383: 
384:     /********************* tools ****************d*g**/
385: 
386: 
387:     /**
388:      * Extracts all blocks of PHP code.
389:      * @param  string
390:      * @param  array
391:      * @return string
392:      */
393:     private static function extractPhp($source, & $blocks)
394:     {
395:         $res = '';
396:         $blocks = array();
397:         $tokens = token_get_all($source);
398:         foreach ($tokens as $n => $token) {
399:             if (is_array($token)) {
400:                 if ($token[0] === T_INLINE_HTML) {
401:                     $res .= $token[1];
402:                     continue;
403: 
404:                 } elseif ($token[0] === T_CLOSE_TAG) {
405:                     if ($php !== $res) { // not <?xml
406:                         $res .= str_repeat("\n", substr_count($php, "\n"));
407:                     }
408:                     $res .= $token[1];
409:                     continue;
410: 
411:                 } elseif ($token[0] === T_OPEN_TAG && $token[1] === '<?' && isset($tokens[$n+1][1]) && $tokens[$n+1][1] === 'xml') {
412:                     $php = & $res;
413:                     $token[1] = '<<?php ?>?';
414: 
415:                 } elseif ($token[0] === T_OPEN_TAG || $token[0] === T_OPEN_TAG_WITH_ECHO) {
416:                     $res .= $id = "<?php \x01@php:p" . count($blocks) . "@\x02";
417:                     $php = & $blocks[$id];
418:                 }
419:                 $php .= $token[1];
420: 
421:             } else {
422:                 $php .= $token;
423:             }
424:         }
425:         return $res;
426:     }
427: 
428: }
429: 
Nette 2.0 API documentation generated by ApiGen 2.8.0