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
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • CachingIterator
  • FilterExecutor
  • FilterInfo
  • Filters
  • Html
  • SnippetDriver
  • Template

Interfaces

  • IHtmlString
  • ISnippetBridge
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  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 \stdClass global accumulators for intermediate results */
 22:     public $global;
 23: 
 24:     /** @var string  @internal */
 25:     protected $contentType = Engine::CONTENT_HTML;
 26: 
 27:     /** @var array  @internal */
 28:     protected $params = [];
 29: 
 30:     /** @var FilterExecutor */
 31:     protected $filters;
 32: 
 33:     /** @var array [name => method]  @internal */
 34:     protected $blocks = [];
 35: 
 36:     /** @var string|null|false  @internal */
 37:     protected $parentName;
 38: 
 39:     /** @var [name => [callbacks]]  @internal */
 40:     protected $blockQueue = [];
 41: 
 42:     /** @var [name => type]  @internal */
 43:     protected $blockTypes = [];
 44: 
 45:     /** @var Engine */
 46:     private $engine;
 47: 
 48:     /** @var string */
 49:     private $name;
 50: 
 51:     /** @var Template|null  @internal */
 52:     private $referringTemplate;
 53: 
 54:     /** @var string|null  @internal */
 55:     private $referenceType;
 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'], true)) {
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 instanceof \Closure) {
234:             echo $mod($this->capture([$this, 'render']), $this->contentType);
235:         } elseif ($mod && $mod !== $this->contentType) {
236:             if ($filter = Filters::getConvertor($this->contentType, $mod)) {
237:                 echo $filter($this->capture([$this, 'render']));
238:             } else {
239:                 trigger_error("Including '$this->name' with content type " . strtoupper($this->contentType) . ' into incompatible type ' . strtoupper($mod) . '.', E_USER_WARNING);
240:             }
241:         } else {
242:             $this->render();
243:         }
244:     }
245: 
246: 
247:     /**
248:      * @return void
249:      * @internal
250:      */
251:     public function prepare()
252:     {
253:     }
254: 
255: 
256:     /********************* blocks ****************d*g**/
257: 
258: 
259:     /**
260:      * Renders block.
261:      * @param  string
262:      * @param  array
263:      * @param  string|\Closure content-type name or modifier closure
264:      * @return void
265:      * @internal
266:      */
267:     protected function renderBlock($name, array $params, $mod = null)
268:     {
269:         if (empty($this->blockQueue[$name])) {
270:             $hint = isset($this->blockQueue) && ($t = Latte\Helpers::getSuggestion(array_keys($this->blockQueue), $name)) ? ", did you mean '$t'?" : '.';
271:             throw new \RuntimeException("Cannot include undefined block '$name'$hint");
272:         }
273: 
274:         $block = reset($this->blockQueue[$name]);
275:         if ($mod && $mod !== ($blockType = $this->blockTypes[$name])) {
276:             if ($filter = (is_string($mod) ? Filters::getConvertor($blockType, $mod) : $mod)) {
277:                 echo $filter($this->capture(function () use ($block, $params) { $block($params); }), $blockType);
278:                 return;
279:             }
280:             trigger_error("Including block $name with content type " . strtoupper($blockType) . ' into incompatible type ' . strtoupper($mod) . '.', E_USER_WARNING);
281:         }
282:         $block($params);
283:     }
284: 
285: 
286:     /**
287:      * Renders parent block.
288:      * @return void
289:      * @internal
290:      */
291:     protected function renderBlockParent($name, array $params)
292:     {
293:         if (empty($this->blockQueue[$name]) || ($block = next($this->blockQueue[$name])) === false) {
294:             throw new \RuntimeException("Cannot include undefined parent block '$name'.");
295:         }
296:         $block($params);
297:         prev($this->blockQueue[$name]);
298:     }
299: 
300: 
301:     /**
302:      * @return void
303:      * @internal
304:      */
305:     protected function checkBlockContentType($current, $name)
306:     {
307:         $expected = &$this->blockTypes[$name];
308:         if ($expected === null) {
309:             $expected = $current;
310:         } elseif ($expected !== $current) {
311:             trigger_error("Overridden block $name with content type " . strtoupper($current) . ' by incompatible type ' . strtoupper($expected) . '.', E_USER_WARNING);
312:         }
313:     }
314: 
315: 
316:     /**
317:      * Captures output to string.
318:      * @return string
319:      * @internal
320:      */
321:     public function capture(callable $function)
322:     {
323:         ob_start(function () {});
324:         try {
325:             $this->global->coreCaptured = true;
326:             $function();
327:         } catch (\Exception $e) {
328:         } catch (\Throwable $e) {
329:         }
330:         $this->global->coreCaptured = false;
331:         if (isset($e)) {
332:             ob_end_clean();
333:             throw $e;
334:         }
335:         return ob_get_clean();
336:     }
337: 
338: 
339:     /** @deprecated */
340:     public function setParameters(array $params)
341:     {
342:         trigger_error(__METHOD__ . ' is deprecated.', E_USER_DEPRECATED);
343:         $this->params = $params;
344:         return $this;
345:     }
346: 
347: 
348:     /********************* deprecated ****************d*g**/
349: 
350: 
351:     /** @deprecated */
352:     public function __call($name, $args)
353:     {
354:         trigger_error("Invoking filters via \$template->$name(\$vars) is deprecated, use (\$vars|$name)", E_USER_DEPRECATED);
355:         return call_user_func_array($this->filters->$name, $args);
356:     }
357: 
358: 
359:     /** @deprecated */
360:     public function __set($name, $value)
361:     {
362:         trigger_error("Access to parameters via \$template->$name is deprecated", E_USER_DEPRECATED);
363:         $this->params[$name] = $value;
364:     }
365: 
366: 
367:     /** @deprecated */
368:     public function &__get($name)
369:     {
370:         trigger_error("Access to parameters via \$template->$name is deprecated, use \$this->getParameter('$name')", E_USER_DEPRECATED);
371:         if (!array_key_exists($name, $this->params)) {
372:             trigger_error("The variable '$name' does not exist in template.");
373:         }
374:         return $this->params[$name];
375:     }
376: 
377: 
378:     /** @deprecated */
379:     public function __isset($name)
380:     {
381:         trigger_error("Access to parameters via \$template->$name is deprecated, use isset(\$this->getParameters()['$name'])", E_USER_DEPRECATED);
382:         return isset($this->params[$name]);
383:     }
384: 
385: 
386:     /** @deprecated */
387:     public function __unset($name)
388:     {
389:         trigger_error("Access to parameters via \$template->$name is deprecated.", E_USER_DEPRECATED);
390:         unset($this->params[$name]);
391:     }
392: }
393: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0