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
  • PHP

Classes

  • FileTemplate
  • Helpers
  • Template

Interfaces

  • IFileTemplate
  • ITemplate

Exceptions

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