Packages

  • Nette
    • Application
    • Caching
    • Collections
    • Config
    • Forms
    • IO
    • Loaders
    • Mail
    • Reflection
    • Security
    • Templates
    • Web
  • None
  • PHP

Classes

  • NBaseTemplate
  • NCachingHelper
  • NCurlyBracketsMacros
  • NLatteFilter
  • NLatteMacros
  • NSnippetHelper
  • NTemplate
  • NTemplateCacheStorage
  • NTemplateFilters
  • NTemplateHelpers

Interfaces

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