Namespaces

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

Classes

  • BaseTemplate
  • CachingHelper
  • CurlyBracketsMacros
  • LatteFilter
  • LatteMacros
  • SnippetHelper
  • Template
  • TemplateCacheStorage
  • TemplateFilters
  • TemplateHelpers

Interfaces

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