Overview

Namespaces

  • Budovy
  • Kdyby
    • BootstrapFormRenderer
      • DI
      • Latte
  • 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
  • Nextras
    • Datagrid
  • None
  • PHP
  • Tester
    • CodeCoverage
    • Runner
      • Output
  • Vodacek
    • Forms
      • Controls
  • WebLoader
    • Filter
    • Nette

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:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Templating;
  9: 
 10: use Nette,
 11:     Nette\Caching,
 12:     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  bool  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 (\Exception $e) {
118:             ob_end_clean();
119:             if (func_get_args() && func_get_arg(0)) {
120:                 throw $e;
121:             } else {
122:                 trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
123:             }
124:         }
125:     }
126: 
127: 
128:     /**
129:      * Applies filters on template content.
130:      * @return string
131:      */
132:     public function compile()
133:     {
134:         if (!$this->filters) {
135:             $this->onPrepareFilters($this);
136:         }
137: 
138:         $code = $this->getSource();
139:         foreach ($this->filters as $filter) {
140:             $code = self::extractPhp($code, $blocks);
141:             $code = call_user_func($filter, $code);
142:             $code = strtr($code, $blocks); // put PHP code back
143:         }
144: 
145:         return Helpers::optimizePhp($code);
146:     }
147: 
148: 
149:     /********************* template filters & helpers ****************d*g**/
150: 
151: 
152:     /**
153:      * Registers callback as template compile-time filter.
154:      * @param  callable
155:      * @return self
156:      */
157:     public function registerFilter($callback)
158:     {
159:         $this->filters[] = Callback::check($callback);
160:         return $this;
161:     }
162: 
163: 
164:     /**
165:      * Returns all registered compile-time filters.
166:      * @return array
167:      */
168:     public function getFilters()
169:     {
170:         return $this->filters;
171:     }
172: 
173: 
174:     /**
175:      * Registers callback as template run-time helper.
176:      * @param  string
177:      * @param  callable
178:      * @return self
179:      */
180:     public function registerHelper($name, $callback)
181:     {
182:         $this->helpers[strtolower($name)] = $callback;
183:         return $this;
184:     }
185: 
186: 
187:     /**
188:      * Registers callback as template run-time helpers loader.
189:      * @param  callable
190:      * @return self
191:      */
192:     public function registerHelperLoader($callback)
193:     {
194:         array_unshift($this->helperLoaders, $callback);
195:         return $this;
196:     }
197: 
198: 
199:     /**
200:      * Returns all registered run-time helpers.
201:      * @return array
202:      */
203:     public function getHelpers()
204:     {
205:         return $this->helpers;
206:     }
207: 
208: 
209:     /**
210:      * Returns all registered template run-time helper loaders.
211:      * @return array
212:      */
213:     public function getHelperLoaders()
214:     {
215:         return $this->helperLoaders;
216:     }
217: 
218: 
219:     /**
220:      * Call a template run-time helper. Do not call directly.
221:      * @param  string  helper name
222:      * @param  array   arguments
223:      * @return mixed
224:      */
225:     public function __call($name, $args)
226:     {
227:         $lname = strtolower($name);
228:         if (!isset($this->helpers[$lname])) {
229:             foreach ($this->helperLoaders as $loader) {
230:                 $helper = Callback::invoke($loader, $lname);
231:                 if ($helper) {
232:                     $this->registerHelper($lname, $helper);
233:                     return Callback::invokeArgs($this->helpers[$lname], $args);
234:                 }
235:             }
236:             return parent::__call($name, $args);
237:         }
238: 
239:         return Callback::invokeArgs($this->helpers[$lname], $args);
240:     }
241: 
242: 
243:     /**
244:      * Sets translate adapter.
245:      * @return self
246:      */
247:     public function setTranslator(Nette\Localization\ITranslator $translator = NULL)
248:     {
249:         $this->registerHelper('translate', $translator === NULL ? NULL : array($translator, 'translate'));
250:         return $this;
251:     }
252: 
253: 
254:     /********************* template parameters ****************d*g**/
255: 
256: 
257:     /**
258:      * Adds new template parameter.
259:      * @return self
260:      */
261:     public function add($name, $value)
262:     {
263:         if (array_key_exists($name, $this->params)) {
264:             throw new Nette\InvalidStateException("The variable '$name' already exists.");
265:         }
266: 
267:         $this->params[$name] = $value;
268:         return $this;
269:     }
270: 
271: 
272:     /**
273:      * Sets all parameters.
274:      * @param  array
275:      * @return self
276:      */
277:     public function setParameters(array $params)
278:     {
279:         $this->params = $params + $this->params;
280:         return $this;
281:     }
282: 
283: 
284:     /**
285:      * Returns array of all parameters.
286:      * @return array
287:      */
288:     public function getParameters()
289:     {
290:         $this->params['template'] = $this;
291:         return $this->params;
292:     }
293: 
294: 
295:     /**
296:      * Sets a template parameter. Do not call directly.
297:      * @return void
298:      */
299:     public function __set($name, $value)
300:     {
301:         $this->params[$name] = $value;
302:     }
303: 
304: 
305:     /**
306:      * Returns a template parameter. Do not call directly.
307:      * @return mixed  value
308:      */
309:     public function &__get($name)
310:     {
311:         if (!array_key_exists($name, $this->params)) {
312:             trigger_error("The variable '$name' does not exist in template.", E_USER_NOTICE);
313:         }
314: 
315:         return $this->params[$name];
316:     }
317: 
318: 
319:     /**
320:      * Determines whether parameter is defined. Do not call directly.
321:      * @return bool
322:      */
323:     public function __isset($name)
324:     {
325:         return isset($this->params[$name]);
326:     }
327: 
328: 
329:     /**
330:      * Removes a template parameter. Do not call directly.
331:      * @param  string    name
332:      * @return void
333:      */
334:     public function __unset($name)
335:     {
336:         unset($this->params[$name]);
337:     }
338: 
339: 
340:     /********************* caching ****************d*g**/
341: 
342: 
343:     /**
344:      * Set cache storage.
345:      * @return self
346:      */
347:     public function setCacheStorage(Caching\IStorage $storage)
348:     {
349:         $this->cacheStorage = $storage;
350:         return $this;
351:     }
352: 
353: 
354:     /**
355:      * @return Nette\Caching\IStorage
356:      */
357:     public function getCacheStorage()
358:     {
359:         if ($this->cacheStorage === NULL) {
360:             return new Caching\Storages\DevNullStorage;
361:         }
362:         return $this->cacheStorage;
363:     }
364: 
365: 
366:     /********************* tools ****************d*g**/
367: 
368: 
369:     /**
370:      * Extracts all blocks of PHP code.
371:      * @param  string
372:      * @param  array
373:      * @return string
374:      */
375:     private static function extractPhp($source, & $blocks)
376:     {
377:         $res = '';
378:         $blocks = array();
379:         $tokens = token_get_all($source);
380:         foreach ($tokens as $n => $token) {
381:             if (is_array($token)) {
382:                 if ($token[0] === T_INLINE_HTML) {
383:                     $res .= $token[1];
384:                     continue;
385: 
386:                 } elseif ($token[0] === T_CLOSE_TAG) {
387:                     if ($php !== $res) { // not <?xml
388:                         $res .= str_repeat("\n", substr_count($php, "\n"));
389:                     }
390:                     $res .= $token[1];
391:                     continue;
392: 
393:                 } elseif ($token[0] === T_OPEN_TAG && $token[1] === '<?' && isset($tokens[$n+1][1]) && $tokens[$n+1][1] === 'xml') {
394:                     $php = & $res;
395:                     $token[1] = '<<?php ?>?';
396: 
397:                 } elseif ($token[0] === T_OPEN_TAG || $token[0] === T_OPEN_TAG_WITH_ECHO) {
398:                     $res .= $id = "<?php \x01@php:p" . count($blocks) . "@\x02";
399:                     $php = & $blocks[$id];
400:                 }
401:                 $php .= $token[1];
402: 
403:             } else {
404:                 $php .= $token;
405:             }
406:         }
407:         return $res;
408:     }
409: 
410: }
411: 
API documentation generated by ApiGen 2.8.0