Template::setLeftDelimiter()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * Smarty Internal Plugin Template
4
 * This file contains the Smarty template engine
5
 *
6
7
8
 * @author     Uwe Tews
9
 */
10
11
namespace Smarty;
12
13
use Smarty\Resource\BasePlugin;
14
use Smarty\Runtime\InheritanceRuntime;
15
use Smarty\Template\Source;
16
use Smarty\Template\Cached;
17
use Smarty\Template\Compiled;
18
use Smarty\Template\Config;
19
20
/**
21
 * Main class with template data structures and methods
22
 */
23
#[\AllowDynamicProperties]
24
class Template extends TemplateBase {
25
26
	/**
27
	 * caching mode to create nocache code but no cache file
28
	 */
29
	public const CACHING_NOCACHE_CODE = 9999;
30
31
	/**
32
	 * @var Compiled
33
	 */
34
	private $compiled = null;
35
36
	/**
37
	 * @var Cached
38
	 */
39
	private $cached = null;
40
41
	/**
42
	 * @var \Smarty\Compiler\Template
43
	 */
44
	private $compiler = null;
45
46
	/**
47
	 * Source instance
48
	 *
49
	 * @var Source|Config
50
	 */
51
	private $source = null;
52
53
	/**
54
	 * Template resource
55
	 *
56
	 * @var string
57
	 */
58
	public $template_resource = null;
59
60
	/**
61
	 * Template ID
62
	 *
63
	 * @var null|string
64
	 */
65
	public $templateId = null;
66
67
	/**
68
	 * Callbacks called before rendering template
69
	 *
70
	 * @var callback[]
71
	 */
72
	public $startRenderCallbacks = [];
73
74
	/**
75
	 * Callbacks called after rendering template
76
	 *
77
	 * @var callback[]
78
	 */
79
	public $endRenderCallbacks = [];
80
81
	/**
82
	 * Template left-delimiter. If null, defaults to $this->getSmarty()-getLeftDelimiter().
83
	 *
84
	 * @var string
85
	 */
86
	private $left_delimiter = null;
87
88
	/**
89
	 * Template right-delimiter. If null, defaults to $this->getSmarty()-getRightDelimiter().
90
	 *
91
	 * @var string
92
	 */
93
	private $right_delimiter = null;
94
95
	/**
96
	 * @var InheritanceRuntime|null
97
	 */
98
	private $inheritance;
99
100
	/**
101
	 * Create template data object
102
	 * Some of the global Smarty settings copied to template scope
103
	 * It load the required template resources and caching plugins
104
	 *
105
	 * @param string $template_resource template resource string
106
	 * @param Smarty $smarty Smarty instance
107
	 * @param \Smarty\Data|null $_parent back pointer to parent object with variables or null
108
	 * @param mixed $_cache_id cache   id or null
109
	 * @param mixed $_compile_id compile id or null
110
	 * @param bool|int|null $_caching use caching?
111
	 * @param bool $_isConfig
112
	 *
113
	 * @throws \Smarty\Exception
114
	 */
115
	public function __construct(
116
		$template_resource,
117
		Smarty $smarty,
118
		?\Smarty\Data $_parent = null,
119
		$_cache_id = null,
120
		$_compile_id = null,
121
		$_caching = null,
122
		$_isConfig = false
123
	) {
124
		$this->smarty = $smarty;
125
		// Smarty parameter
126
		$this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id;
127
		$this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id;
128
		$this->caching = (int)($_caching === null ? $this->smarty->caching : $_caching);
129
		$this->cache_lifetime = $this->smarty->cache_lifetime;
130
		$this->compile_check = (int)$smarty->compile_check;
131
		$this->parent = $_parent;
132
		// Template resource
133
		$this->template_resource = $template_resource;
134
135
		$this->source = $_isConfig ? Config::load($this) : Source::load($this);
136
		$this->compiled = Compiled::load($this);
137
138
		if ($smarty->security_policy) {
139
			$smarty->security_policy->registerCallBacks($this);
140
		}
141
	}
142
143
	/**
144
	 * render template
145
	 *
146
	 * @param bool $no_output_filter if true do not run output filter
147
	 * @param null|bool $display true: display, false: fetch null: sub-template
148
	 *
149
	 * @return string
150
	 * @throws \Exception
151
	 * @throws \Smarty\Exception
152
	 */
153
	private function render($no_output_filter = true, $display = null) {
154
		if ($this->smarty->debugging) {
155
			$this->smarty->getDebug()->start_template($this, $display);
0 ignored issues
show
Bug introduced by
It seems like $display can also be of type boolean; however, parameter $mode of Smarty\Debug::start_template() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

155
			$this->smarty->getDebug()->start_template($this, /** @scrutinizer ignore-type */ $display);
Loading history...
156
		}
157
		// checks if template exists
158
		if ($this->compile_check && !$this->getSource()->exists) {
159
			throw new Exception(
160
				"Unable to load '{$this->getSource()->type}:{$this->getSource()->name}'" .
161
				($this->_isSubTpl() ? " in '{$this->parent->template_resource}'" : '')
162
			);
163
		}
164
165
		// disable caching for evaluated code
166
		if ($this->getSource()->handler->recompiled) {
167
			$this->caching = \Smarty\Smarty::CACHING_OFF;
168
		}
169
170
		foreach ($this->startRenderCallbacks as $callback) {
171
			call_user_func($callback, $this);
172
		}
173
174
		try {
175
176
			// read from cache or render
177
			if ($this->caching === \Smarty\Smarty::CACHING_LIFETIME_CURRENT || $this->caching === \Smarty\Smarty::CACHING_LIFETIME_SAVED) {
178
				$this->getCached()->render($this, $no_output_filter);
179
			} else {
180
				$this->getCompiled()->render($this);
181
			}
182
183
		} finally {
184
			foreach ($this->endRenderCallbacks as $callback) {
185
				call_user_func($callback, $this);
186
			}
187
		}
188
189
		// display or fetch
190
		if ($display) {
191
			if ($this->caching && $this->smarty->cache_modified_check) {
192
				$this->smarty->cacheModifiedCheck(
193
					$this->getCached(),
194
					$this,
195
					isset($content) ? $content : ob_get_clean()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $content seems to never exist and therefore isset should always be false.
Loading history...
196
				);
197
			} else {
198
				if ((!$this->caching || $this->getCached()->getNocacheCode() || $this->getSource()->handler->recompiled)
199
					&& !$no_output_filter
200
				) {
201
					echo $this->smarty->runOutputFilters(ob_get_clean(), $this);
202
				} else {
203
					echo ob_get_clean();
204
				}
205
			}
206
			if ($this->smarty->debugging) {
207
				$this->smarty->getDebug()->end_template($this);
208
				// debug output
209
				$this->smarty->getDebug()->display_debug($this, true);
210
			}
211
			return '';
212
		} else {
213
			if ($this->smarty->debugging) {
214
				$this->smarty->getDebug()->end_template($this);
215
				if ($this->smarty->debugging === 2 && $display === false) {
216
					$this->smarty->getDebug()->display_debug($this, true);
217
				}
218
			}
219
			if (
220
				!$no_output_filter
221
				&& (!$this->caching || $this->getCached()->getNocacheCode() || $this->getSource()->handler->recompiled)
222
			) {
223
224
				return $this->smarty->runOutputFilters(ob_get_clean(), $this);
225
			}
226
			// return cache content
227
			return null;
228
		}
229
	}
230
231
	/**
232
	 * Runtime function to render sub-template
233
	 *
234
	 * @param string $template_name template name
235
	 * @param mixed $cache_id cache id
236
	 * @param mixed $compile_id compile id
237
	 * @param integer $caching cache mode
238
	 * @param integer $cache_lifetime lifetime of cache data
239
	 * @param array $extra_vars passed parameter template variables
240
	 * @param int|null $scope
241
	 *
242
	 * @throws Exception
243
	 */
244
	public function renderSubTemplate(
245
		$template_name,
246
		$cache_id,
247
		$compile_id,
248
		$caching,
249
		$cache_lifetime,
250
		array $extra_vars = [],
251
		?int $scope = null,
252
		?string $currentDir = null
253
	) {
254
255
		$name = $this->parseResourceName($template_name);
256
		if ($currentDir && preg_match('/^\.{1,2}\//', $name)) {
257
			// relative template resource name, append it to current template name
258
			$template_name = $currentDir . DIRECTORY_SEPARATOR . $name;
259
		}
260
261
		$tpl = $this->smarty->doCreateTemplate($template_name, $cache_id, $compile_id, $this, $caching, $cache_lifetime);
262
263
		$tpl->inheritance = $this->getInheritance(); // re-use the same Inheritance object inside the inheritance tree
264
265
		if ($scope) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $scope of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
266
			$tpl->defaultScope = $scope;
267
		}
268
269
		if ($caching) {
270
			if ($tpl->templateId !== $this->templateId && $caching !== \Smarty\Template::CACHING_NOCACHE_CODE) {
271
				$tpl->getCached(true);
272
			} else {
273
				// re-use the same Cache object across subtemplates to gather hashes and file dependencies.
274
				$tpl->setCached($this->getCached());
275
			}
276
		}
277
278
		foreach ($extra_vars as $_key => $_val) {
279
			$tpl->assign($_key, $_val);
280
		}
281
		if ($tpl->caching === \Smarty\Template::CACHING_NOCACHE_CODE) {
282
			if ($tpl->getCompiled()->getNocacheCode()) {
283
				$this->getCached()->hashes[$tpl->getCompiled()->nocache_hash] = true;
284
			}
285
		}
286
287
		$tpl->render();
288
	}
289
290
	/**
291
	 * Remove type indicator from resource name if present.
292
	 * E.g. $this->parseResourceName('file:template.tpl') returns 'template.tpl'
293
	 *
294
	 * @note "C:/foo.tpl" was forced to file resource up till Smarty 3.1.3 (including).
295
	 *
296
	 * @param string $resource_name    template_resource or config_resource to parse
297
	 *
298
	 * @return string
299
	 */
300
	private function parseResourceName($resource_name): string {
301
		if (preg_match('/^([A-Za-z0-9_\-]{2,}):/', $resource_name, $match)) {
302
			return substr($resource_name, strlen($match[0]));
303
		}
304
		return $resource_name;
305
	}
306
307
	/**
308
	 * Check if this is a sub template
309
	 *
310
	 * @return bool true is sub template
311
	 */
312
	public function _isSubTpl() {
313
		return isset($this->parent) && $this->parent instanceof Template;
314
	}
315
316
	public function assign($tpl_var, $value = null, $nocache = false, $scope = null) {
317
		return parent::assign($tpl_var, $value, $nocache, $scope);
318
	}
319
320
	/**
321
	 * Compiles the template
322
	 * If the template is not evaluated the compiled template is saved on disk
323
	 *
324
	 * @TODO only used in compileAll and 1 unit test: can we move this and make compileAndWrite private?
325
	 *
326
	 * @throws \Exception
327
	 */
328
	public function compileTemplateSource() {
329
		return $this->getCompiled()->compileAndWrite($this);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getCompiled()->compileAndWrite($this) targeting Smarty\Template\Compiled::compileAndWrite() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
330
	}
331
332
	/**
333
	 * Return cached content
334
	 *
335
	 * @return null|string
336
	 * @throws Exception
337
	 */
338
	public function getCachedContent() {
339
		return $this->getCached()->getContent($this);
340
	}
341
342
	/**
343
	 * Writes the content to cache resource
344
	 *
345
	 * @param string $content
346
	 *
347
	 * @return bool
348
	 *
349
	 * @TODO this method is only used in unit tests that (mostly) try to test CacheResources.
350
	 */
351
	public function writeCachedContent($content) {
352
		if ($this->getSource()->handler->recompiled || !$this->caching
353
		) {
354
			// don't write cache file
355
			return false;
356
		}
357
		$codeframe = $this->createCodeFrame($content, '', true);
358
		return $this->getCached()->writeCache($this, $codeframe);
359
	}
360
361
	/**
362
	 * Get unique template id
363
	 *
364
	 * @return string
365
	 */
366
	public function getTemplateId() {
367
		return $this->templateId;
368
	}
369
370
	/**
371
	 * runtime error not matching capture tags
372
	 *
373
	 * @throws \Smarty\Exception
374
	 */
375
	public function capture_error() {
376
		throw new Exception("Not matching {capture} open/close in '{$this->template_resource}'");
377
	}
378
379
	/**
380
	 * Return Compiled object
381
	 *
382
	 * @param bool $forceNew force new compiled object
383
	 */
384
	public function getCompiled($forceNew = false) {
385
		if ($forceNew || !isset($this->compiled)) {
386
			$this->compiled = Compiled::load($this);
387
		}
388
		return $this->compiled;
389
	}
390
391
	/**
392
	 * Return Cached object
393
	 *
394
	 * @param bool $forceNew force new cached object
395
	 *
396
	 * @throws Exception
397
	 */
398
	public function getCached($forceNew = false): Cached {
399
		if ($forceNew || !isset($this->cached)) {
400
			$cacheResource = $this->smarty->getCacheResource();
401
			$this->cached = new Cached(
402
				$this->source,
403
				$cacheResource,
404
				$this->compile_id,
405
				$this->cache_id
406
			);
407
			if ($this->isCachingEnabled()) {
408
				$cacheResource->populate($this->cached, $this);
409
			} else {
410
				$this->cached->setValid(false);
411
			}
412
		}
413
		return $this->cached;
414
	}
415
416
	private function isCachingEnabled(): bool {
417
		return $this->caching && !$this->getSource()->handler->recompiled;
418
	}
419
420
	/**
421
	 * Helper function for InheritanceRuntime object
422
	 *
423
	 * @return InheritanceRuntime
424
	 * @throws Exception
425
	 */
426
	public function getInheritance(): InheritanceRuntime {
427
		if (is_null($this->inheritance)) {
428
			$this->inheritance = clone $this->getSmarty()->getRuntime('Inheritance');
429
		}
430
		return $this->inheritance;
431
	}
432
433
	/**
434
	 * Sets a new InheritanceRuntime object.
435
	 *
436
	 * @param InheritanceRuntime $inheritanceRuntime
437
	 *
438
	 * @return void
439
	 */
440
	public function setInheritance(InheritanceRuntime $inheritanceRuntime) {
441
		$this->inheritance = $inheritanceRuntime;
442
	}
443
444
	/**
445
	 * Return Compiler object
446
	 */
447
	public function getCompiler() {
448
		if (!isset($this->compiler)) {
449
			$this->compiler = $this->getSource()->createCompiler();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getSource()->createCompiler() can also be of type Smarty\Compiler\Configfile. However, the property $compiler is declared as type Smarty\Compiler\Template. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
450
		}
451
		return $this->compiler;
452
	}
453
454
	/**
455
	 * Create code frame for compiled and cached templates
456
	 *
457
	 * @param string $content optional template content
458
	 * @param string $functions compiled template function and block code
459
	 * @param bool $cache flag for cache file
460
	 * @param Compiler\Template|null $compiler
461
	 *
462
	 * @return string
463
	 * @throws Exception
464
	 */
465
	public function createCodeFrame($content = '', $functions = '', $cache = false, ?\Smarty\Compiler\Template $compiler = null) {
466
		return $this->getCodeFrameCompiler()->create($content, $functions, $cache, $compiler);
467
	}
468
469
	/**
470
	 * Template data object destructor
471
	 */
472
	public function __destruct() {
473
		if ($this->smarty->cache_locking && $this->getCached()->is_locked) {
474
			$this->getCached()->handler->releaseLock($this->smarty, $this->getCached());
475
		}
476
	}
477
478
	/**
479
	 * Returns if the current template must be compiled by the Smarty compiler
480
	 * It does compare the timestamps of template source and the compiled templates and checks the force compile
481
	 * configuration
482
	 *
483
	 * @return bool
484
	 * @throws \Smarty\Exception
485
	 */
486
	public function mustCompile(): bool {
487
		if (!$this->getSource()->exists) {
488
			if ($this->_isSubTpl()) {
489
				$parent_resource = " in '{$this->parent->template_resource}'";
490
			} else {
491
				$parent_resource = '';
492
			}
493
			throw new Exception("Unable to load {$this->getSource()->type} '{$this->getSource()->name}'{$parent_resource}");
494
		}
495
496
		// @TODO move this logic to Compiled
497
		return $this->smarty->force_compile
498
			|| $this->getSource()->handler->recompiled
499
			|| !$this->getCompiled()->exists
500
			|| ($this->compile_check &&	$this->getCompiled()->getTimeStamp() < $this->getSource()->getTimeStamp());
501
	}
502
503
	private function getCodeFrameCompiler(): Compiler\CodeFrame {
504
		return new \Smarty\Compiler\CodeFrame($this);
505
	}
506
507
	/**
508
	 * Get left delimiter
509
	 *
510
	 * @return string
511
	 */
512
	public function getLeftDelimiter()
513
	{
514
		return $this->left_delimiter ?? $this->getSmarty()->getLeftDelimiter();
515
	}
516
517
	/**
518
	 * Set left delimiter
519
	 *
520
	 * @param string $left_delimiter
521
	 */
522
	public function setLeftDelimiter($left_delimiter)
523
	{
524
		$this->left_delimiter = $left_delimiter;
525
	}
526
527
	/**
528
	 * Get right delimiter
529
	 *
530
	 * @return string $right_delimiter
531
	 */
532
	public function getRightDelimiter()
533
	{
534
		return $this->right_delimiter ?? $this->getSmarty()->getRightDelimiter();;
535
	}
536
537
	/**
538
	 * Set right delimiter
539
	 *
540
	 * @param string
541
	 */
542
	public function setRightDelimiter($right_delimiter)
543
	{
544
		$this->right_delimiter = $right_delimiter;
545
	}
546
547
	/**
548
	 * gets  a stream variable
549
	 *
550
	 * @param string                                                  $variable the stream of the variable
551
	 *
552
	 * @return mixed
553
	 * @throws \Smarty\Exception
554
	 *
555
	 */
556
	public function getStreamVariable($variable)
557
	{
558
559
		trigger_error("Using stream variables (\`\{\$foo:bar\}\`)is deprecated.", E_USER_DEPRECATED);
560
561
		$_result = '';
562
		$fp = fopen($variable, 'r+');
563
		if ($fp) {
0 ignored issues
show
introduced by
$fp is of type resource, thus it always evaluated to false.
Loading history...
564
			while (!feof($fp) && ($current_line = fgets($fp)) !== false) {
565
				$_result .= $current_line;
566
			}
567
			fclose($fp);
568
			return $_result;
569
		}
570
		if ($this->getSmarty()->error_unassigned) {
571
			throw new Exception('Undefined stream variable "' . $variable . '"');
572
		}
573
		return null;
574
	}
575
	/**
576
	 * @inheritdoc
577
	 */
578
	public function configLoad($config_file, $sections = null)
579
	{
580
		$confObj = parent::configLoad($config_file, $sections);
581
582
		$this->getCompiled()->file_dependency[ $confObj->getSource()->uid ] =
0 ignored issues
show
Bug introduced by
The method getSource() does not exist on Smarty\TemplateBase. It seems like you code against a sub-type of Smarty\TemplateBase such as Smarty\Template. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

582
		$this->getCompiled()->file_dependency[ $confObj->/** @scrutinizer ignore-call */ getSource()->uid ] =
Loading history...
583
			array($confObj->getSource()->getResourceName(), $confObj->getSource()->getTimeStamp(), $confObj->getSource()->type);
584
585
		return $confObj;
586
	}
587
588
	public function fetch() {
589
		$result = $this->_execute(0);
590
		return $result === null ? ob_get_clean() : $result;
0 ignored issues
show
introduced by
The condition $result === null is always false.
Loading history...
591
	}
592
593
	public function display() {
594
		$this->_execute(1);
595
	}
596
597
	/**
598
	 * test if cache is valid
599
	 *
600
	 * @param mixed $cache_id cache id to be used with this template
601
	 * @param mixed $compile_id compile id to be used with this template
602
	 * @param object $parent next higher level of Smarty variables
603
	 *
604
	 * @return bool cache status
605
	 * @throws \Exception
606
	 * @throws \Smarty\Exception
607
	 *
608
	 * @api  Smarty::isCached()
609
	 */
610
	public function isCached(): bool {
611
		return (bool) $this->_execute(2);
612
	}
613
614
	/**
615
	 * fetches a rendered Smarty template
616
	 *
617
	 * @param string $function function type 0 = fetch,  1 = display, 2 = isCache
618
	 *
619
	 * @return mixed
620
	 * @throws Exception
621
	 * @throws \Throwable
622
	 */
623
	private function _execute($function) {
624
625
		$smarty = $this->getSmarty();
626
627
		// make sure we have integer values
628
		$this->caching = (int)$this->caching;
629
		// fetch template content
630
		$level = ob_get_level();
631
		try {
632
			$_smarty_old_error_level =
633
				isset($smarty->error_reporting) ? error_reporting($smarty->error_reporting) : null;
634
635
			if ($smarty->isMutingUndefinedOrNullWarnings()) {
636
				$errorHandler = new \Smarty\ErrorHandler();
637
				$errorHandler->activate();
638
			}
639
640
			if ($function === 2) {
0 ignored issues
show
introduced by
The condition $function === 2 is always false.
Loading history...
641
				if ($this->caching) {
642
					// return cache status of template
643
					$result = $this->getCached()->isCached($this);
644
				} else {
645
					return false;
646
				}
647
			} else {
648
649
				// After rendering a template, the tpl/config variables are reset, so the template can be re-used.
650
				$this->pushStack();
651
652
				// Start output-buffering.
653
				ob_start();
654
655
				$result = $this->render(false, $function);
0 ignored issues
show
Bug introduced by
$function of type string is incompatible with the type boolean|null expected by parameter $display of Smarty\Template::render(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

655
				$result = $this->render(false, /** @scrutinizer ignore-type */ $function);
Loading history...
656
657
				// Restore the template to its previous state
658
				$this->popStack();
659
			}
660
661
			if (isset($errorHandler)) {
662
				$errorHandler->deactivate();
663
			}
664
665
			if (isset($_smarty_old_error_level)) {
666
				error_reporting($_smarty_old_error_level);
667
			}
668
			return $result;
669
		} catch (\Throwable $e) {
670
			while (ob_get_level() > $level) {
671
				ob_end_clean();
672
			}
673
			if (isset($errorHandler)) {
674
				$errorHandler->deactivate();
675
			}
676
677
			if (isset($_smarty_old_error_level)) {
678
				error_reporting($_smarty_old_error_level);
679
			}
680
			throw $e;
681
		}
682
	}
683
684
	/**
685
	 * @return Config|Source|null
686
	 */
687
	public function getSource() {
688
		return $this->source;
689
	}
690
691
	/**
692
	 * @param Config|Source|null $source
693
	 */
694
	public function setSource($source): void {
695
		$this->source = $source;
696
	}
697
698
	/**
699
	 * Sets the Cached object, so subtemplates can share one Cached object to gather meta-data.
700
	 *
701
	 * @param Cached $cached
702
	 *
703
	 * @return void
704
	 */
705
	private function setCached(Cached $cached) {
706
		$this->cached = $cached;
707
	}
708
709
	/**
710
	 * @param string $compile_id
711
	 *
712
	 * @throws Exception
713
	 */
714
	public function setCompileId($compile_id) {
715
		parent::setCompileId($compile_id);
716
		$this->getCompiled(true);
717
		if ($this->caching) {
718
			$this->getCached(true);
719
		}
720
	}
721
722
	/**
723
	 * @param string $cache_id
724
	 *
725
	 * @throws Exception
726
	 */
727
	public function setCacheId($cache_id) {
728
		parent::setCacheId($cache_id);
729
		$this->getCached(true);
730
	}
731
732
}
733