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

Classes

Interfaces

Exceptions

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