smarty_internal_template.php (35233B)
1 <?php 2 /** 3 * Smarty Internal Plugin Template 4 * This file contains the Smarty template engine 5 * 6 * @package Smarty 7 * @subpackage Template 8 * @author Uwe Tews 9 */ 10 11 /** 12 * Main class with template data structures and methods 13 * 14 * @package Smarty 15 * @subpackage Template 16 * 17 * @property Smarty_Template_Source $source 18 * @property Smarty_Template_Compiled $compiled 19 * @property Smarty_Template_Cached $cached 20 */ 21 class Smarty_Internal_Template extends Smarty_Internal_TemplateBase 22 { 23 /** 24 * Global smarty instance 25 * 26 * @var Smarty 27 */ 28 public $smarty = null; 29 30 /** 31 * Template resource 32 * 33 * @var string 34 */ 35 public $template_resource = null; 36 /** 37 * Saved template Id 38 * 39 * @var null|string 40 */ 41 public $templateId = null; 42 /** 43 * flag if compiled template is invalid and must be (re)compiled 44 * 45 * @var bool 46 */ 47 public $mustCompile = null; 48 /** 49 * flag if template does contain nocache code sections 50 * 51 * @var bool 52 */ 53 public $has_nocache_code = false; 54 /** 55 * special compiled and cached template properties 56 * 57 * @var array 58 */ 59 public $properties = array('file_dependency' => array(), 60 'nocache_hash' => '', 61 'tpl_function' => array(), 62 ); 63 /** 64 * required plugins 65 * 66 * @var array 67 */ 68 public $required_plugins = array('compiled' => array(), 'nocache' => array()); 69 /** 70 * blocks for template inheritance 71 * 72 * @var array 73 */ 74 public $block_data = array(); 75 /** 76 * variable filters 77 * 78 * @var array 79 */ 80 public $variable_filters = array(); 81 /** 82 * optional log of tag/attributes 83 * 84 * @var array 85 */ 86 public $used_tags = array(); 87 /** 88 * internal flag to allow relative path in child template blocks 89 * 90 * @var bool 91 */ 92 public $allow_relative_path = false; 93 /** 94 * internal capture runtime stack 95 * 96 * @var array 97 */ 98 public $_capture_stack = array(0 => array()); 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_Internal_Template $_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 $_caching use caching? 111 * @param int $_cache_lifetime cache life-time in seconds 112 */ 113 public function __construct($template_resource, $smarty, $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null) 114 { 115 $this->smarty = &$smarty; 116 // Smarty parameter 117 $this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id; 118 $this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id; 119 $this->caching = $_caching === null ? $this->smarty->caching : $_caching; 120 if ($this->caching === true) { 121 $this->caching = Smarty::CACHING_LIFETIME_CURRENT; 122 } 123 $this->cache_lifetime = $_cache_lifetime === null ? $this->smarty->cache_lifetime : $_cache_lifetime; 124 $this->parent = $_parent; 125 // Template resource 126 $this->template_resource = $template_resource; 127 // copy block data of template inheritance 128 if ($this->parent instanceof Smarty_Internal_Template) { 129 $this->block_data = $this->parent->block_data; 130 } 131 } 132 133 /** 134 * fetches rendered template 135 * 136 * @throws Exception 137 * @throws SmartyException 138 * @return string rendered template output 139 */ 140 public function fetch() 141 { 142 return $this->render(true, false, false); 143 } 144 145 /** 146 * displays a Smarty template 147 */ 148 public function display() 149 { 150 $this->render(true, false, true); 151 } 152 153 /** 154 * render template 155 * 156 * @param bool $merge_tpl_vars if true parent template variables merged in to local scope 157 * @param bool $no_output_filter if true do not run output filter 158 * @param bool $display true: display, false: fetch null: subtemplate 159 * 160 * @throws Exception 161 * @throws SmartyException 162 * @return string rendered template output 163 */ 164 public function render($merge_tpl_vars = false, $no_output_filter = true, $display = null) 165 { 166 $parentIsTpl = $this->parent instanceof Smarty_Internal_Template; 167 if ($this->smarty->debugging) { 168 Smarty_Internal_Debug::start_template($this, $display); 169 } 170 $save_tpl_vars = null; 171 $save_config_vars = null; 172 // merge all variable scopes into template 173 if ($merge_tpl_vars) { 174 // save local variables 175 $save_tpl_vars = $this->tpl_vars; 176 $save_config_vars = $this->config_vars; 177 $ptr_array = array($this); 178 $ptr = $this; 179 while (isset($ptr->parent)) { 180 $ptr_array[] = $ptr = $ptr->parent; 181 } 182 $ptr_array = array_reverse($ptr_array); 183 $parent_ptr = reset($ptr_array); 184 $tpl_vars = $parent_ptr->tpl_vars; 185 $config_vars = $parent_ptr->config_vars; 186 while ($parent_ptr = next($ptr_array)) { 187 if (!empty($parent_ptr->tpl_vars)) { 188 $tpl_vars = array_merge($tpl_vars, $parent_ptr->tpl_vars); 189 } 190 if (!empty($parent_ptr->config_vars)) { 191 $config_vars = array_merge($config_vars, $parent_ptr->config_vars); 192 } 193 } 194 if (!empty(Smarty::$global_tpl_vars)) { 195 $tpl_vars = array_merge(Smarty::$global_tpl_vars, $tpl_vars); 196 } 197 $this->tpl_vars = $tpl_vars; 198 $this->config_vars = $config_vars; 199 } 200 // dummy local smarty variable 201 if (!isset($this->tpl_vars['smarty'])) { 202 $this->tpl_vars['smarty'] = new Smarty_Variable; 203 } 204 $_smarty_old_error_level = isset($this->smarty->error_reporting) ? error_reporting($this->smarty->error_reporting) : null; 205 // check URL debugging control 206 if (!$this->smarty->debugging && $this->smarty->debugging_ctrl == 'URL') { 207 Smarty_Internal_Debug::debugUrl($this); 208 } 209 if (!isset($this->source)) { 210 $this->loadSource(); 211 } 212 // checks if template exists 213 if (!$this->source->exists) { 214 if ($parentIsTpl) { 215 $parent_resource = " in '{$this->parent->template_resource}'"; 216 } else { 217 $parent_resource = ''; 218 } 219 throw new SmartyException("Unable to load template {$this->source->type} '{$this->source->name}'{$parent_resource}"); 220 } 221 // disable caching for evaluated code 222 if ($this->source->recompiled) { 223 $this->caching = false; 224 } 225 // read from cache or render 226 $isCacheTpl = $this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED; 227 if ($isCacheTpl) { 228 if (!isset($this->cached)) { 229 $this->loadCached(); 230 } 231 $this->cached->isCached($this); 232 } 233 if (!($isCacheTpl) || !$this->cached->valid) { 234 if ($isCacheTpl) { 235 $this->properties['tpl_function'] = array(); 236 } 237 // render template (not loaded and not in cache) 238 if ($this->smarty->debugging) { 239 Smarty_Internal_Debug::start_render($this); 240 } 241 if (!$this->source->uncompiled) { 242 // render compiled code 243 if (!isset($this->compiled)) { 244 $this->loadCompiled(); 245 } 246 $content = $this->compiled->render($this); 247 } else { 248 $content = $this->source->renderUncompiled($this); 249 } 250 if (!$this->source->recompiled && empty($this->properties['file_dependency'][$this->source->uid])) { 251 $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $this->source->type); 252 } 253 if ($parentIsTpl) { 254 $this->parent->properties['file_dependency'] = array_merge($this->parent->properties['file_dependency'], $this->properties['file_dependency']); 255 //$this->parent->properties['tpl_function'] = array_merge($this->parent->properties['tpl_function'], $this->properties['tpl_function']); 256 } 257 if ($this->smarty->debugging) { 258 Smarty_Internal_Debug::end_render($this); 259 } 260 // write to cache when necessary 261 if (!$this->source->recompiled && $isCacheTpl) { 262 if ($this->smarty->debugging) { 263 Smarty_Internal_Debug::start_cache($this); 264 } 265 $this->cached->updateCache($this, $content, $no_output_filter); 266 $compile_check = $this->smarty->compile_check; 267 $this->smarty->compile_check = false; 268 if ($parentIsTpl) { 269 $this->properties['tpl_function'] = $this->parent->properties['tpl_function']; 270 } 271 if (!$this->cached->processed) { 272 $this->cached->process($this); 273 } 274 $this->smarty->compile_check = $compile_check; 275 $content = $this->getRenderedTemplateCode(); 276 if ($this->smarty->debugging) { 277 Smarty_Internal_Debug::end_cache($this); 278 } 279 } else { 280 if (!empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) { 281 // replace nocache_hash 282 $content = str_replace("{$this->properties['nocache_hash']}", $this->parent->properties['nocache_hash'], $content); 283 $this->parent->has_nocache_code = $this->parent->has_nocache_code || $this->has_nocache_code; 284 } 285 } 286 } else { 287 if ($this->smarty->debugging) { 288 Smarty_Internal_Debug::start_cache($this); 289 } 290 $content = $this->cached->render($this); 291 if ($this->smarty->debugging) { 292 Smarty_Internal_Debug::end_cache($this); 293 } 294 } 295 if ((!$this->caching || $this->has_nocache_code || $this->source->recompiled) && !$no_output_filter && (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))) { 296 $content = Smarty_Internal_Filter_Handler::runFilter('output', $content, $this); 297 } 298 if (isset($_smarty_old_error_level)) { 299 error_reporting($_smarty_old_error_level); 300 } 301 // display or fetch 302 if ($display) { 303 if ($this->caching && $this->smarty->cache_modified_check) { 304 $this->cached->cacheModifiedCheck($this, $content); 305 } else { 306 echo $content; 307 } 308 if ($this->smarty->debugging) { 309 Smarty_Internal_Debug::end_template($this); 310 } 311 // debug output 312 if ($this->smarty->debugging) { 313 Smarty_Internal_Debug::display_debug($this, true); 314 } 315 if ($merge_tpl_vars) { 316 // restore local variables 317 $this->tpl_vars = $save_tpl_vars; 318 $this->config_vars = $save_config_vars; 319 } 320 return ''; 321 } else { 322 if ($merge_tpl_vars) { 323 // restore local variables 324 $this->tpl_vars = $save_tpl_vars; 325 $this->config_vars = $save_config_vars; 326 } 327 if ($this->smarty->debugging) { 328 Smarty_Internal_Debug::end_template($this); 329 } 330 if ($this->smarty->debugging == 2 and $display === false) { 331 if ($this->smarty->debugging) { 332 Smarty_Internal_Debug::display_debug($this, true); 333 } 334 } 335 if ($parentIsTpl) { 336 $this->parent->properties['tpl_function'] = array_merge($this->parent->properties['tpl_function'], $this->properties['tpl_function']); 337 foreach ($this->required_plugins as $code => $tmp1) { 338 foreach ($tmp1 as $name => $tmp) { 339 foreach ($tmp as $type => $data) { 340 $this->parent->required_plugins[$code][$name][$type] = $data; 341 } 342 } 343 } 344 } 345 // return cache content 346 return $content; 347 } 348 } 349 350 /** 351 * get rendered template content by calling compiled or cached template code 352 * 353 * @return string 354 * @throws Exception 355 */ 356 public function getRenderedTemplateCode() 357 { 358 $level = ob_get_level(); 359 try { 360 ob_start(); 361 if (empty($this->properties['unifunc']) || !is_callable($this->properties['unifunc'])) { 362 throw new SmartyException("Invalid compiled template for '{$this->template_resource}'"); 363 } 364 if (isset($this->smarty->security_policy)) { 365 $this->smarty->security_policy->startTemplate($this); 366 } 367 array_unshift($this->_capture_stack, array()); 368 // 369 // render compiled or saved template code 370 // 371 $this->properties['unifunc']($this); 372 // any unclosed {capture} tags ? 373 if (isset($this->_capture_stack[0][0])) { 374 $this->capture_error(); 375 } 376 array_shift($this->_capture_stack); 377 if (isset($this->smarty->security_policy)) { 378 $this->smarty->security_policy->exitTemplate($this); 379 } 380 return ob_get_clean(); 381 } 382 catch (Exception $e) { 383 while (ob_get_level() > $level) { 384 ob_end_clean(); 385 } 386 throw $e; 387 } 388 } 389 390 /** 391 * Returns if the current template must be compiled by the Smarty compiler 392 * It does compare the timestamps of template source and the compiled templates and checks the force compile 393 * configuration 394 * 395 * @throws SmartyException 396 * @return boolean true if the template must be compiled 397 */ 398 public function mustCompile() 399 { 400 if (!$this->source->exists) { 401 if ($this->parent instanceof Smarty_Internal_Template) { 402 $parent_resource = " in '$this->parent->template_resource}'"; 403 } else { 404 $parent_resource = ''; 405 } 406 throw new SmartyException("Unable to load template {$this->source->type} '{$this->source->name}'{$parent_resource}"); 407 } 408 if ($this->mustCompile === null) { 409 $this->mustCompile = (!$this->source->uncompiled && ($this->smarty->force_compile || $this->source->recompiled || $this->compiled->timestamp === false || 410 ($this->smarty->compile_check && $this->compiled->timestamp < $this->source->timestamp))); 411 } 412 413 return $this->mustCompile; 414 } 415 416 /** 417 * Compiles the template 418 * If the template is not evaluated the compiled template is saved on disk 419 */ 420 public function compileTemplateSource() 421 { 422 return $this->compiled->compileTemplateSource($this); 423 } 424 425 /** 426 * Writes the content to cache resource 427 * 428 * @param string $content 429 * 430 * @return bool 431 */ 432 public function writeCachedContent($content) 433 { 434 return $this->cached->writeCachedContent($this, $content); 435 } 436 437 /** 438 * Template code runtime function to get subtemplate content 439 * 440 * @param string $template the resource handle of the template file 441 * @param mixed $cache_id cache id to be used with this template 442 * @param mixed $compile_id compile id to be used with this template 443 * @param integer $caching cache mode 444 * @param integer $cache_lifetime life time of cache data 445 * @param $data 446 * @param int $parent_scope scope in which {include} should execute 447 * 448 * @returns string template content 449 */ 450 public function getSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope) 451 { 452 $tpl = $this->setupSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope); 453 return $tpl->render(); 454 } 455 456 /** 457 * Template code runtime function to set up an inline subtemplate 458 * 459 * @param string $template the resource handle of the template file 460 * @param mixed $cache_id cache id to be used with this template 461 * @param mixed $compile_id compile id to be used with this template 462 * @param integer $caching cache mode 463 * @param integer $cache_lifetime life time of cache data 464 * @param array $data passed parameter template variables 465 * @param int $parent_scope scope in which {include} should execute 466 * 467 * @returns object template object 468 */ 469 public function setupSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope) 470 { 471 $_templateId = $this->getTemplateId($template, $cache_id, $compile_id); 472 // already in template cache? 473 if (isset($this->smarty->template_objects[$_templateId])) { 474 // clone cached template object because of possible recursive call 475 $tpl = clone $this->smarty->template_objects[$_templateId]; 476 $tpl->parent = $this; 477 if ((bool) $tpl->caching !== (bool) $caching) { 478 unset($tpl->compiled); 479 } 480 $tpl->caching = $caching; 481 $tpl->cache_lifetime = $cache_lifetime; 482 } else { 483 $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime); 484 $tpl->templateId = $_templateId; 485 } 486 // get variables from calling scope 487 if ($parent_scope == Smarty::SCOPE_LOCAL) { 488 $tpl->tpl_vars = $this->tpl_vars; 489 $tpl->tpl_vars['smarty'] = clone $this->tpl_vars['smarty']; 490 } elseif ($parent_scope == Smarty::SCOPE_PARENT) { 491 $tpl->tpl_vars = &$this->tpl_vars; 492 } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) { 493 $tpl->tpl_vars = &Smarty::$global_tpl_vars; 494 } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) { 495 $tpl->tpl_vars = &$this->tpl_vars; 496 } else { 497 $tpl->tpl_vars = &$scope_ptr->tpl_vars; 498 } 499 $tpl->config_vars = $this->config_vars; 500 if (!empty($data)) { 501 // set up variable values 502 foreach ($data as $_key => $_val) { 503 $tpl->tpl_vars[$_key] = new Smarty_Variable($_val); 504 } 505 } 506 $tpl->properties['tpl_function'] = $this->properties['tpl_function']; 507 return $tpl; 508 } 509 510 /** 511 * Template code runtime function to set up an inline subtemplate 512 * 513 * @param string $template the resource handle of the template file 514 * @param mixed $cache_id cache id to be used with this template 515 * @param mixed $compile_id compile id to be used with this template 516 * @param integer $caching cache mode 517 * @param integer $cache_lifetime life time of cache data 518 * @param array $data passed parameter template variables 519 * @param int $parent_scope scope in which {include} should execute 520 * @param string $hash nocache hash code 521 * @param string $content_func name of content function 522 * 523 * @returns object template content 524 */ 525 public function getInlineSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $hash, $content_func) 526 { 527 $tpl = $this->setupSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope); 528 $tpl->properties['nocache_hash'] = $hash; 529 if (!isset($this->smarty->template_objects[$tpl->templateId])) { 530 $this->smarty->template_objects[$tpl->templateId] = $tpl; 531 } 532 if ($this->smarty->debugging) { 533 Smarty_Internal_Debug::start_template($tpl); 534 Smarty_Internal_Debug::start_render($tpl); 535 } 536 $tpl->properties['unifunc'] = $content_func; 537 $output = $tpl->getRenderedTemplateCode(); 538 if ($this->smarty->debugging) { 539 Smarty_Internal_Debug::end_template($tpl); 540 Smarty_Internal_Debug::end_render($tpl); 541 } 542 if (!empty($tpl->properties['file_dependency'])) { 543 $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $tpl->properties['file_dependency']); 544 } 545 $this->properties['tpl_function'] = $tpl->properties['tpl_function']; 546 return str_replace($tpl->properties['nocache_hash'], $this->properties['nocache_hash'], $output); 547 } 548 549 /** 550 * Call template function 551 * 552 * @param string $name template function name 553 * @param object|\Smarty_Internal_Template $_smarty_tpl template object 554 * @param array $params parameter array 555 * @param bool $nocache true if called nocache 556 * 557 * @throws \SmartyException 558 */ 559 public function callTemplateFunction($name, Smarty_Internal_Template $_smarty_tpl, $params, $nocache) 560 { 561 if (isset($_smarty_tpl->properties['tpl_function'][$name])) { 562 if (!$_smarty_tpl->caching || ($_smarty_tpl->caching && $nocache)) { 563 $function = $_smarty_tpl->properties['tpl_function'][$name]['call_name']; 564 } else { 565 if (isset($_smarty_tpl->properties['tpl_function'][$name]['call_name_caching'])) { 566 $function = $_smarty_tpl->properties['tpl_function'][$name]['call_name_caching']; 567 } else { 568 $function = $_smarty_tpl->properties['tpl_function'][$name]['call_name']; 569 } 570 } 571 if (function_exists($function)) { 572 $function ($_smarty_tpl, $params); 573 return; 574 } 575 // try to load template function dynamically 576 if (Smarty_Internal_Function_Call_Handler::call($name, $_smarty_tpl, $function, $params, $nocache)) { 577 $function ($_smarty_tpl, $params); 578 return; 579 } 580 } 581 throw new SmartyException("Unable to find template function '{$name}'"); 582 } 583 584 /** 585 * This function is executed automatically when a compiled or cached template file is included 586 * - Decode saved properties from compiled template and cache files 587 * - Check if compiled or cache file is valid 588 * 589 * @param array $properties special template properties 590 * @param bool $cache flag if called from cache file 591 * 592 * @return bool flag if compiled or cache file is valid 593 */ 594 public function decodeProperties($properties, $cache = false) 595 { 596 $properties['version'] = (isset($properties['version'])) ? $properties['version'] : ''; 597 $is_valid = true; 598 if (Smarty::SMARTY_VERSION != $properties['version']) { 599 // new version must rebuild 600 $is_valid = false; 601 } elseif ((!$cache && $this->smarty->compile_check || $cache && ($this->smarty->compile_check === true || $this->smarty->compile_check === Smarty::COMPILECHECK_ON)) && !empty($properties['file_dependency'])) { 602 // check file dependencies at compiled code 603 foreach ($properties['file_dependency'] as $_file_to_check) { 604 if ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'php') { 605 if ($this->source->filepath == $_file_to_check[0] && isset($this->source->timestamp)) { 606 // do not recheck current template 607 $mtime = $this->source->timestamp; 608 } else { 609 // file and php types can be checked without loading the respective resource handlers 610 $mtime = is_file($_file_to_check[0]) ? @filemtime($_file_to_check[0]) : false; 611 } 612 } elseif ($_file_to_check[2] == 'string') { 613 continue; 614 } else { 615 $source = Smarty_Resource::source(null, $this->smarty, $_file_to_check[0]); 616 $mtime = $source->timestamp; 617 } 618 if (!$mtime || $mtime > $_file_to_check[1]) { 619 $is_valid = false; 620 break; 621 } 622 } 623 } 624 if ($cache) { 625 // CACHING_LIFETIME_SAVED cache expiry has to be validated here since otherwise we'd define the unifunc 626 if ($this->caching === Smarty::CACHING_LIFETIME_SAVED && 627 $properties['cache_lifetime'] >= 0 && 628 (time() > ($this->cached->timestamp + $properties['cache_lifetime'])) 629 ) { 630 $is_valid = false; 631 } 632 $this->cached->valid = $is_valid; 633 } else { 634 $this->mustCompile = !$is_valid; 635 } 636 if ($is_valid) { 637 $this->has_nocache_code = $properties['has_nocache_code']; 638 // $this->properties['nocache_hash'] = $properties['nocache_hash']; 639 if (isset($properties['cache_lifetime'])) { 640 $this->properties['cache_lifetime'] = $properties['cache_lifetime']; 641 } 642 if (isset($properties['file_dependency'])) { 643 $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']); 644 } 645 if (isset($properties['tpl_function'])) { 646 $this->properties['tpl_function'] = array_merge($this->properties['tpl_function'], $properties['tpl_function']); 647 } 648 $this->properties['version'] = $properties['version']; 649 $this->properties['unifunc'] = $properties['unifunc']; 650 } 651 return $is_valid; 652 } 653 654 /** 655 * Template code runtime function to create a local Smarty variable for array assignments 656 * 657 * @param string $tpl_var template variable name 658 * @param bool $nocache cache mode of variable 659 * @param int $scope scope of variable 660 */ 661 public function createLocalArrayVariable($tpl_var, $nocache = false, $scope = Smarty::SCOPE_LOCAL) 662 { 663 if (!isset($this->tpl_vars[$tpl_var])) { 664 $this->tpl_vars[$tpl_var] = new Smarty_Variable(array(), $nocache, $scope); 665 } else { 666 $this->tpl_vars[$tpl_var] = clone $this->tpl_vars[$tpl_var]; 667 if ($scope != Smarty::SCOPE_LOCAL) { 668 $this->tpl_vars[$tpl_var]->scope = $scope; 669 } 670 if (!(is_array($this->tpl_vars[$tpl_var]->value) || $this->tpl_vars[$tpl_var]->value instanceof ArrayAccess)) { 671 settype($this->tpl_vars[$tpl_var]->value, 'array'); 672 } 673 } 674 } 675 676 /** 677 * Template code runtime function to get pointer to template variable array of requested scope 678 * 679 * @param int $scope requested variable scope 680 * 681 * @return array array of template variables 682 */ 683 public function &getScope($scope) 684 { 685 if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) { 686 return $this->parent->tpl_vars; 687 } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) { 688 $ptr = $this->parent; 689 while (!empty($ptr->parent)) { 690 $ptr = $ptr->parent; 691 } 692 693 return $ptr->tpl_vars; 694 } elseif ($scope == Smarty::SCOPE_GLOBAL) { 695 return Smarty::$global_tpl_vars; 696 } 697 $null = null; 698 699 return $null; 700 } 701 702 /** 703 * Get parent or root of template parent chain 704 * 705 * @param int $scope parent or root scope 706 * 707 * @return mixed object 708 */ 709 public function getScopePointer($scope) 710 { 711 if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) { 712 return $this->parent; 713 } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) { 714 $ptr = $this->parent; 715 while (!empty($ptr->parent)) { 716 $ptr = $ptr->parent; 717 } 718 719 return $ptr; 720 } 721 722 return null; 723 } 724 725 /** 726 * [util function] counts an array, arrayAccess/traversable or PDOStatement object 727 * 728 * @param mixed $value 729 * 730 * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0 731 * for empty elements 732 */ 733 public function _count($value) 734 { 735 if (is_array($value) === true || $value instanceof Countable) { 736 return count($value); 737 } elseif ($value instanceof IteratorAggregate) { 738 // Note: getIterator() returns a Traversable, not an Iterator 739 // thus rewind() and valid() methods may not be present 740 return iterator_count($value->getIterator()); 741 } elseif ($value instanceof Iterator) { 742 return iterator_count($value); 743 } elseif ($value instanceof PDOStatement) { 744 return $value->rowCount(); 745 } elseif ($value instanceof Traversable) { 746 return iterator_count($value); 747 } elseif ($value instanceof ArrayAccess) { 748 if ($value->offsetExists(0)) { 749 return 1; 750 } 751 } elseif (is_object($value)) { 752 return count($value); 753 } 754 755 return 0; 756 } 757 758 /** 759 * runtime error not matching capture tags 760 */ 761 public function capture_error() 762 { 763 throw new SmartyException("Not matching {capture} open/close in \"{$this->template_resource}\""); 764 } 765 766 /** 767 * Empty cache for this template 768 * 769 * @param integer $exp_time expiration time 770 * 771 * @return integer number of cache files deleted 772 */ 773 public function clearCache($exp_time = null) 774 { 775 Smarty_CacheResource::invalidLoadedCache($this->smarty); 776 777 return $this->cached->handler->clear($this->smarty, $this->template_resource, $this->cache_id, $this->compile_id, $exp_time); 778 } 779 780 /** 781 * Load source resource 782 * 783 * @throws SmartyException 784 */ 785 public function loadSource() 786 { 787 $this->source = Smarty_Template_Source::load($this); 788 if ($this->smarty->template_resource_caching && !$this->source->recompiled && isset($this->templateId)) { 789 $this->smarty->template_objects[$this->templateId] = $this; 790 } 791 } 792 793 /** 794 * Load compiled object 795 * 796 */ 797 public function loadCompiled() 798 { 799 if (!isset($this->compiled)) { 800 if (!class_exists('Smarty_Template_Compiled', false)) { 801 require SMARTY_SYSPLUGINS_DIR . 'smarty_template_compiled.php'; 802 } 803 $this->compiled = Smarty_Template_Compiled::load($this); 804 } 805 } 806 807 /** 808 * Load cached object 809 * 810 */ 811 public function loadCached() 812 { 813 if (!isset($this->cached)) { 814 if (!class_exists('Smarty_Template_Cached', false)) { 815 require SMARTY_SYSPLUGINS_DIR . 'smarty_template_cached.php'; 816 } 817 $this->cached = Smarty_Template_Cached::load($this); 818 } 819 } 820 821 /** 822 * Load compiler object 823 * 824 * @throws \SmartyException 825 */ 826 public function loadCompiler() 827 { 828 $this->smarty->loadPlugin($this->source->compiler_class); 829 $this->compiler = new $this->source->compiler_class($this->source->template_lexer_class, $this->source->template_parser_class, $this->smarty); 830 } 831 832 /** 833 * Handle unknown class methods 834 * 835 * @param string $name unknown method-name 836 * @param array $args argument array 837 * 838 * @return mixed 839 * @throws SmartyException 840 */ 841 public function __call($name, $args) 842 { 843 // method of Smarty object? 844 if (method_exists($this->smarty, $name)) { 845 return call_user_func_array(array($this->smarty, $name), $args); 846 } 847 // parent 848 return parent::__call($name, $args); 849 } 850 851 /** 852 * set Smarty property in template context 853 * 854 * @param string $property_name property name 855 * @param mixed $value value 856 * 857 * @throws SmartyException 858 */ 859 public function __set($property_name, $value) 860 { 861 switch ($property_name) { 862 case 'source': 863 case 'compiled': 864 case 'cached': 865 case 'compiler': 866 $this->$property_name = $value; 867 return; 868 default: 869 // Smarty property ? 870 if (property_exists($this->smarty, $property_name)) { 871 $this->smarty->$property_name = $value; 872 return; 873 } 874 } 875 throw new SmartyException("invalid template property '$property_name'."); 876 } 877 878 /** 879 * get Smarty property in template context 880 * 881 * @param string $property_name property name 882 * 883 * @return mixed|Smarty_Template_Cached 884 * @throws SmartyException 885 */ 886 public function __get($property_name) 887 { 888 switch ($property_name) { 889 case 'source': 890 $this->loadSource(); 891 return $this->source; 892 893 case 'compiled': 894 $this->loadCompiled(); 895 return $this->compiled; 896 897 case 'cached': 898 $this->loadCached(); 899 return $this->cached; 900 901 case 'compiler': 902 $this->loadCompiler(); 903 return $this->compiler; 904 default: 905 // Smarty property ? 906 if (property_exists($this->smarty, $property_name)) { 907 return $this->smarty->$property_name; 908 } 909 } 910 throw new SmartyException("template property '$property_name' does not exist."); 911 } 912 913 /** 914 * Template data object destructor 915 */ 916 public function __destruct() 917 { 918 if ($this->smarty->cache_locking && isset($this->cached) && $this->cached->is_locked) { 919 $this->cached->handler->releaseLock($this->smarty, $this->cached); 920 } 921 } 922 }