Packages

  • 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
  • Template
  • TemplateHelpers

Interfaces

  • IFileTemplate
  • ITemplate

Exceptions

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