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