Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Utils
  • none
  • Tracy
    • Bridges
      • Nette

Classes

  • FilterInfo
  • Html
  • Template

Interfaces

  • IHtmlString
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Latte (https://latte.nette.org)
  5:  * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Latte\Runtime;
  9: 
 10: use Latte;
 11: use Latte\Engine;
 12: 
 13: 
 14: /**
 15:  * Template.
 16:  */
 17: class Template
 18: {
 19:     use Latte\Strict;
 20: 
 21:     /** @var Engine */
 22:     private $engine;
 23: 
 24:     /** @var string */
 25:     private $name;
 26: 
 27:     /** @var string  @internal */
 28:     protected $contentType = Engine::CONTENT_HTML;
 29: 
 30:     /** @var array  @internal */
 31:     protected $params = [];
 32: 
 33:     /** @var FilterExecutor */
 34:     protected $filters;
 35: 
 36:     /** @var array [name => method]  @internal */
 37:     protected $blocks = [];
 38: 
 39:     /** @var string|NULL|FALSE  @internal */
 40:     protected $parentName;
 41: 
 42:     /** @var Template|NULL  @internal */
 43:     private $referringTemplate;
 44: 
 45:     /** @var string|NULL  @internal */
 46:     private $referenceType;
 47: 
 48:     /** @var \stdClass global accumulators for intermediate results */
 49:     public $global;
 50: 
 51:     /** @var [name => [callbacks]]  @internal */
 52:     protected $blockQueue = [];
 53: 
 54:     /** @var [name => type]  @internal */
 55:     protected $blockTypes = [];
 56: 
 57: 
 58:     public function __construct(Engine $engine, array $params, FilterExecutor $filters, array $providers, $name)
 59:     {
 60:         $this->engine = $engine;
 61:         $this->params = $params;
 62:         $this->filters = $filters;
 63:         $this->name = $name;
 64:         $this->global = (object) $providers;
 65:         foreach ($this->blocks as $nm => $method) {
 66:             $this->blockQueue[$nm][] = [$this, $method];
 67:         }
 68:         $this->params['template'] = $this; // back compatibility
 69:     }
 70: 
 71: 
 72:     /**
 73:      * @return Engine
 74:      */
 75:     public function getEngine()
 76:     {
 77:         return $this->engine;
 78:     }
 79: 
 80: 
 81:     /**
 82:      * @return string
 83:      */
 84:     public function getName()
 85:     {
 86:         return $this->name;
 87:     }
 88: 
 89: 
 90:     /**
 91:      * Returns array of all parameters.
 92:      * @return array
 93:      */
 94:     public function getParameters()
 95:     {
 96:         return $this->params;
 97:     }
 98: 
 99: 
100:     /**
101:      * Returns parameter.
102:      * @return mixed
103:      */
104:     public function getParameter($name)
105:     {
106:         if (!array_key_exists($name, $this->params)) {
107:             trigger_error("The variable '$name' does not exist in template.", E_USER_NOTICE);
108:         }
109:         return $this->params[$name];
110:     }
111: 
112: 
113:     /**
114:      * @return string
115:      */
116:     public function getContentType()
117:     {
118:         return $this->contentType;
119:     }
120: 
121: 
122:     /**
123:      * @return string|NULL
124:      */
125:     public function getParentName()
126:     {
127:         return $this->parentName ?: NULL;
128:     }
129: 
130: 
131:     /**
132:      * @return Template|NULL
133:      */
134:     public function getReferringTemplate()
135:     {
136:         return $this->referringTemplate;
137:     }
138: 
139: 
140:     /**
141:      * @return string|NULL
142:      */
143:     public function getReferenceType()
144:     {
145:         return $this->referenceType;
146:     }
147: 
148: 
149:     /**
150:      * Renders template.
151:      * @return void
152:      * @internal
153:      */
154:     public function render()
155:     {
156:         $this->prepare();
157: 
158:         if ($this->parentName === NULL && isset($this->global->coreParentFinder)) {
159:             $this->parentName = call_user_func($this->global->coreParentFinder, $this);
160:         }
161:         if (isset($this->global->snippetBridge) && !isset($this->global->snippetDriver)) {
162:             $this->global->snippetDriver = new SnippetDriver($this->global->snippetBridge);
163:         }
164:         Filters::$xhtml = (bool) preg_match('#xml|xhtml#', $this->contentType);
165: 
166:         if ($this->referenceType === 'import') {
167:             if ($this->parentName) {
168:                 $this->createTemplate($this->parentName, [], 'import')->render();
169:             }
170:             return;
171: 
172:         } elseif ($this->parentName) { // extends
173:             ob_start(function () {});
174:             $params = $this->main();
175:             ob_end_clean();
176:             $this->createTemplate($this->parentName, $params, 'extends')->render();
177:             return;
178: 
179:         } elseif (!empty($this->params['_renderblock'])) { // single block rendering
180:             $tmp = $this;
181:             while (in_array($this->referenceType, ['extends', NULL], TRUE) && ($tmp = $tmp->referringTemplate));
182:             if (!$tmp) {
183:                 $this->renderBlock($this->params['_renderblock'], $this->params);
184:                 return;
185:             }
186:         }
187: 
188:         // old accumulators for back compatibility
189:         $this->params['_l'] = new \stdClass;
190:         $this->params['_g'] = $this->global;
191:         $this->params['_b'] = (object) ['blocks' => & $this->blockQueue, 'types' => & $this->blockTypes];
192:         if (isset($this->global->snippetDriver) && $this->global->snippetBridge->isSnippetMode()) {
193:             if ($this->global->snippetDriver->renderSnippets($this->blockQueue, $this->params)) {
194:                 return;
195:             }
196:         }
197: 
198:         $this->main();
199:     }
200: 
201: 
202:     /**
203:      * Renders template.
204:      * @return Template
205:      * @internal
206:      */
207:     protected function createTemplate($name, array $params, $referenceType)
208:     {
209:         $name = $this->engine->getLoader()->getReferredName($name, $this->name);
210:         $child = $this->engine->createTemplate($name, $params);
211:         $child->referringTemplate = $this;
212:         $child->referenceType = $referenceType;
213:         $child->global = $this->global;
214:         if (in_array($referenceType, ['extends', 'includeblock', 'import'])) {
215:             $this->blockQueue = array_merge_recursive($this->blockQueue, $child->blockQueue);
216:             foreach ($child->blockTypes as $nm => $type) {
217:                 $this->checkBlockContentType($type, $nm);
218:             }
219:             $child->blockQueue = & $this->blockQueue;
220:             $child->blockTypes = & $this->blockTypes;
221:         }
222:         return $child;
223:     }
224: 
225: 
226:     /**
227:      * @param  string|\Closure content-type name or modifier closure
228:      * @return void
229:      * @internal
230:      */
231:     protected function renderToContentType($mod)
232:     {
233:         if ($mod && $mod !== $this->contentType) {
234:             if ($filter = (is_string($mod) ? Filters::getConvertor($this->contentType, $mod) : $mod)) {
235:                 echo $filter($this->capture([$this, 'render']), $this->contentType);
236:                 return;
237:             }
238:             trigger_error("Including '$this->name' with content type " . strtoupper($this->contentType) . ' into incompatible type ' . strtoupper($mod) . '.', E_USER_WARNING);
239:         }
240:         $this->render();
241:     }
242: 
243: 
244:     /**
245:      * @return void
246:      * @internal
247:      */
248:     public function prepare()
249:     {
250:     }
251: 
252: 
253:     /********************* blocks ****************d*g**/
254: 
255: 
256:     /**
257:      * Renders block.
258:      * @param  string
259:      * @param  array
260:      * @param  string|\Closure content-type name or modifier closure
261:      * @return void
262:      * @internal
263:      */
264:     protected function renderBlock($name, array $params, $mod = NULL)
265:     {
266:         if (empty($this->blockQueue[$name])) {
267:             $hint = isset($this->blockQueue) && ($t = Latte\Helpers::getSuggestion(array_keys($this->blockQueue), $name)) ? ", did you mean '$t'?" : '.';
268:             throw new \RuntimeException("Cannot include undefined block '$name'$hint");
269:         }
270: 
271:         $block = reset($this->blockQueue[$name]);
272:         if ($mod && $mod !== ($blockType = $this->blockTypes[$name])) {
273:             if ($filter = (is_string($mod) ? Filters::getConvertor($blockType, $mod) : $mod)) {
274:                 echo $filter($this->capture(function () use ($block, $params) { $block($params); }), $blockType);
275:                 return;
276:             }
277:             trigger_error("Including block $name with content type " . strtoupper($blockType) . ' into incompatible type ' . strtoupper($mod) . '.', E_USER_WARNING);
278:         }
279:         $block($params);
280:     }
281: 
282: 
283:     /**
284:      * Renders parent block.
285:      * @return void
286:      * @internal
287:      */
288:     protected function renderBlockParent($name, array $params)
289:     {
290:         if (empty($this->blockQueue[$name]) || ($block = next($this->blockQueue[$name])) === FALSE) {
291:             throw new \RuntimeException("Cannot include undefined parent block '$name'.");
292:         }
293:         $block($params);
294:         prev($this->blockQueue[$name]);
295:     }
296: 
297: 
298:     /**
299:      * @return void
300:      * @internal
301:      */
302:     protected function checkBlockContentType($current, $name)
303:     {
304:         $expected = & $this->blockTypes[$name];
305:         if ($expected === NULL) {
306:             $expected = $current;
307:         } elseif ($expected !== $current) {
308:             trigger_error("Overridden block $name with content type " . strtoupper($current) . ' by incompatible type ' . strtoupper($expected) . '.', E_USER_WARNING);
309:         }
310:     }
311: 
312: 
313:     /**
314:      * Captures output to string.
315:      * @return string
316:      * @internal
317:      */
318:     public function capture(callable $function)
319:     {
320:         ob_start(function () {});
321:         try {
322:             $this->global->coreCaptured = TRUE;
323:             $function();
324:         } catch (\Throwable $e) {
325:         } catch (\Exception $e) {
326:         }
327:         $this->global->coreCaptured = FALSE;
328:         if (isset($e)) {
329:             ob_end_clean();
330:             throw $e;
331:         }
332:         return ob_get_clean();
333:     }
334: 
335: 
336:     /** @deprecated */
337:     public function setParameters(array $params)
338:     {
339:         trigger_error(__METHOD__ . ' is deprecated.', E_USER_DEPRECATED);
340:         $this->params = $params;
341:         return $this;
342:     }
343: 
344: 
345:     /********************* deprecated ****************d*g**/
346: 
347: 
348:     /** @deprecated */
349:     public function __call($name, $args)
350:     {
351:         trigger_error("Invoking filters via \$template->$name(\$vars) is deprecated, use (\$vars|$name)", E_USER_DEPRECATED);
352:         return call_user_func_array($this->filters->$name, $args);
353:     }
354: 
355: 
356:     /** @deprecated */
357:     public function __set($name, $value)
358:     {
359:         trigger_error("Access to parameters via \$template->$name is deprecated", E_USER_DEPRECATED);
360:         $this->params[$name] = $value;
361:     }
362: 
363: 
364:     /** @deprecated */
365:     public function &__get($name)
366:     {
367:         trigger_error("Access to parameters via \$template->$name is deprecated, use \$this->getParameter('$name')", E_USER_DEPRECATED);
368:         if (!array_key_exists($name, $this->params)) {
369:             trigger_error("The variable '$name' does not exist in template.");
370:         }
371:         return $this->params[$name];
372:     }
373: 
374: 
375:     /** @deprecated */
376:     public function __isset($name)
377:     {
378:         trigger_error("Access to parameters via \$template->$name is deprecated, use isset(\$this->getParameters()['$name'])", E_USER_DEPRECATED);
379:         return isset($this->params[$name]);
380:     }
381: 
382: 
383:     /** @deprecated */
384:     public function __unset($name)
385:     {
386:         trigger_error("Access to parameters via \$template->$name is deprecated.", E_USER_DEPRECATED);
387:         unset($this->params[$name]);
388:     }
389: 
390: }
391: 
Nette 2.4-20161109 API API documentation generated by ApiGen 2.8.0