PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/code/web/private_php/ams/smarty/libs/sysplugins/smarty_internal_templatebase.php

https://bitbucket.org/ryzom/ryzomcore
PHP | 860 lines | 537 code | 47 blank | 276 comment | 151 complexity | 71b6cc971a6a89768269e97594511dd6 MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0, GPL-3.0, LGPL-2.1
  1. <?php
  2. /**
  3. * Smarty Internal Plugin Smarty Template Base
  4. * This file contains the basic shared methods for template handling
  5. *
  6. * @package Smarty
  7. * @subpackage Template
  8. * @author Uwe Tews
  9. */
  10. /**
  11. * Class with shared template methods
  12. *
  13. * @package Smarty
  14. * @subpackage Template
  15. */
  16. abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data
  17. {
  18. /**
  19. * fetches a rendered Smarty template
  20. *
  21. * @param string $template the resource handle of the template file or template object
  22. * @param mixed $cache_id cache id to be used with this template
  23. * @param mixed $compile_id compile id to be used with this template
  24. * @param object $parent next higher level of Smarty variables
  25. * @param bool $display true: display, false: fetch
  26. * @param bool $merge_tpl_vars if true parent template variables merged in to local scope
  27. * @param bool $no_output_filter if true do not run output filter
  28. *
  29. * @throws Exception
  30. * @throws SmartyException
  31. * @return string rendered template output
  32. */
  33. public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false, $merge_tpl_vars = true, $no_output_filter = false)
  34. {
  35. if ($template === null && $this instanceof $this->template_class) {
  36. $template = $this;
  37. }
  38. if ($cache_id !== null && is_object($cache_id)) {
  39. $parent = $cache_id;
  40. $cache_id = null;
  41. }
  42. if ($parent === null && ($this instanceof Smarty || is_string($template))) {
  43. $parent = $this;
  44. }
  45. // create template object if necessary
  46. $_template = ($template instanceof $this->template_class)
  47. ? $template
  48. : $this->smarty->createTemplate($template, $cache_id, $compile_id, $parent, false);
  49. // if called by Smarty object make sure we use current caching status
  50. if ($this instanceof Smarty) {
  51. $_template->caching = $this->caching;
  52. }
  53. // merge all variable scopes into template
  54. if ($merge_tpl_vars) {
  55. // save local variables
  56. $save_tpl_vars = $_template->tpl_vars;
  57. $save_config_vars = $_template->config_vars;
  58. $ptr_array = array($_template);
  59. $ptr = $_template;
  60. while (isset($ptr->parent)) {
  61. $ptr_array[] = $ptr = $ptr->parent;
  62. }
  63. $ptr_array = array_reverse($ptr_array);
  64. $parent_ptr = reset($ptr_array);
  65. $tpl_vars = $parent_ptr->tpl_vars;
  66. $config_vars = $parent_ptr->config_vars;
  67. while ($parent_ptr = next($ptr_array)) {
  68. if (!empty($parent_ptr->tpl_vars)) {
  69. $tpl_vars = array_merge($tpl_vars, $parent_ptr->tpl_vars);
  70. }
  71. if (!empty($parent_ptr->config_vars)) {
  72. $config_vars = array_merge($config_vars, $parent_ptr->config_vars);
  73. }
  74. }
  75. if (!empty(Smarty::$global_tpl_vars)) {
  76. $tpl_vars = array_merge(Smarty::$global_tpl_vars, $tpl_vars);
  77. }
  78. $_template->tpl_vars = $tpl_vars;
  79. $_template->config_vars = $config_vars;
  80. }
  81. // dummy local smarty variable
  82. if (!isset($_template->tpl_vars['smarty'])) {
  83. $_template->tpl_vars['smarty'] = new Smarty_Variable;
  84. }
  85. if (isset($this->smarty->error_reporting)) {
  86. $_smarty_old_error_level = error_reporting($this->smarty->error_reporting);
  87. }
  88. // check URL debugging control
  89. if (!$this->smarty->debugging && $this->smarty->debugging_ctrl == 'URL') {
  90. if (isset($_SERVER['QUERY_STRING'])) {
  91. $_query_string = $_SERVER['QUERY_STRING'];
  92. } else {
  93. $_query_string = '';
  94. }
  95. if (false !== strpos($_query_string, $this->smarty->smarty_debug_id)) {
  96. if (false !== strpos($_query_string, $this->smarty->smarty_debug_id . '=on')) {
  97. // enable debugging for this browser session
  98. setcookie('SMARTY_DEBUG', true);
  99. $this->smarty->debugging = true;
  100. } elseif (false !== strpos($_query_string, $this->smarty->smarty_debug_id . '=off')) {
  101. // disable debugging for this browser session
  102. setcookie('SMARTY_DEBUG', false);
  103. $this->smarty->debugging = false;
  104. } else {
  105. // enable debugging for this page
  106. $this->smarty->debugging = true;
  107. }
  108. } else {
  109. if (isset($_COOKIE['SMARTY_DEBUG'])) {
  110. $this->smarty->debugging = true;
  111. }
  112. }
  113. }
  114. // must reset merge template date
  115. $_template->smarty->merged_templates_func = array();
  116. // get rendered template
  117. // disable caching for evaluated code
  118. if ($_template->source->recompiled) {
  119. $_template->caching = false;
  120. }
  121. // checks if template exists
  122. if (!$_template->source->exists) {
  123. if ($_template->parent instanceof Smarty_Internal_Template) {
  124. $parent_resource = " in '{$_template->parent->template_resource}'";
  125. } else {
  126. $parent_resource = '';
  127. }
  128. throw new SmartyException("Unable to load template {$_template->source->type} '{$_template->source->name}'{$parent_resource}");
  129. }
  130. // read from cache or render
  131. if (!($_template->caching == Smarty::CACHING_LIFETIME_CURRENT || $_template->caching == Smarty::CACHING_LIFETIME_SAVED) || !$_template->cached->valid) {
  132. // render template (not loaded and not in cache)
  133. if (!$_template->source->uncompiled) {
  134. /** @var Smarty_Internal_Template $_smarty_tpl
  135. * used in evaluated code
  136. */
  137. $_smarty_tpl = $_template;
  138. if ($_template->source->recompiled) {
  139. $code = $_template->compiler->compileTemplate($_template);
  140. if ($this->smarty->debugging) {
  141. Smarty_Internal_Debug::start_render($_template);
  142. }
  143. try {
  144. ob_start();
  145. eval("?>" . $code);
  146. unset($code);
  147. }
  148. catch (Exception $e) {
  149. ob_get_clean();
  150. throw $e;
  151. }
  152. } else {
  153. if (!$_template->compiled->exists || ($_template->smarty->force_compile && !$_template->compiled->isCompiled)) {
  154. $_template->compileTemplateSource();
  155. $code = file_get_contents($_template->compiled->filepath);
  156. eval("?>" . $code);
  157. unset($code);
  158. $_template->compiled->loaded = true;
  159. $_template->compiled->isCompiled = true;
  160. }
  161. if ($this->smarty->debugging) {
  162. Smarty_Internal_Debug::start_render($_template);
  163. }
  164. if (!$_template->compiled->loaded) {
  165. include($_template->compiled->filepath);
  166. if ($_template->mustCompile) {
  167. // recompile and load again
  168. $_template->compileTemplateSource();
  169. $code = file_get_contents($_template->compiled->filepath);
  170. eval("?>" . $code);
  171. unset($code);
  172. $_template->compiled->isCompiled = true;
  173. }
  174. $_template->compiled->loaded = true;
  175. } else {
  176. $_template->decodeProperties($_template->compiled->_properties, false);
  177. }
  178. try {
  179. ob_start();
  180. if (empty($_template->properties['unifunc']) || !is_callable($_template->properties['unifunc'])) {
  181. throw new SmartyException("Invalid compiled template for '{$_template->template_resource}'");
  182. }
  183. array_unshift($_template->_capture_stack, array());
  184. //
  185. // render compiled template
  186. //
  187. $_template->properties['unifunc']($_template);
  188. // any unclosed {capture} tags ?
  189. if (isset($_template->_capture_stack[0][0])) {
  190. $_template->capture_error();
  191. }
  192. array_shift($_template->_capture_stack);
  193. }
  194. catch (Exception $e) {
  195. ob_get_clean();
  196. throw $e;
  197. }
  198. }
  199. } else {
  200. if ($_template->source->uncompiled) {
  201. if ($this->smarty->debugging) {
  202. Smarty_Internal_Debug::start_render($_template);
  203. }
  204. try {
  205. ob_start();
  206. $_template->source->renderUncompiled($_template);
  207. }
  208. catch (Exception $e) {
  209. ob_get_clean();
  210. throw $e;
  211. }
  212. } else {
  213. throw new SmartyException("Resource '$_template->source->type' must have 'renderUncompiled' method");
  214. }
  215. }
  216. $_output = ob_get_clean();
  217. if (!$_template->source->recompiled && empty($_template->properties['file_dependency'][$_template->source->uid])) {
  218. $_template->properties['file_dependency'][$_template->source->uid] = array($_template->source->filepath, $_template->source->timestamp, $_template->source->type);
  219. }
  220. if ($_template->parent instanceof Smarty_Internal_Template) {
  221. $_template->parent->properties['file_dependency'] = array_merge($_template->parent->properties['file_dependency'], $_template->properties['file_dependency']);
  222. foreach ($_template->required_plugins as $code => $tmp1) {
  223. foreach ($tmp1 as $name => $tmp) {
  224. foreach ($tmp as $type => $data) {
  225. $_template->parent->required_plugins[$code][$name][$type] = $data;
  226. }
  227. }
  228. }
  229. }
  230. if ($this->smarty->debugging) {
  231. Smarty_Internal_Debug::end_render($_template);
  232. }
  233. // write to cache when nessecary
  234. if (!$_template->source->recompiled && ($_template->caching == Smarty::CACHING_LIFETIME_SAVED || $_template->caching == Smarty::CACHING_LIFETIME_CURRENT)) {
  235. if ($this->smarty->debugging) {
  236. Smarty_Internal_Debug::start_cache($_template);
  237. }
  238. $_template->properties['has_nocache_code'] = false;
  239. // get text between non-cached items
  240. $cache_split = preg_split("!/\*%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!s", $_output);
  241. // get non-cached items
  242. preg_match_all("!/\*%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!s", $_output, $cache_parts);
  243. $output = '';
  244. // loop over items, stitch back together
  245. foreach ($cache_split as $curr_idx => $curr_split) {
  246. // escape PHP tags in template content
  247. $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', "<?php echo '\$1'; ?>\n", $curr_split);
  248. if (isset($cache_parts[0][$curr_idx])) {
  249. $_template->properties['has_nocache_code'] = true;
  250. // remove nocache tags from cache output
  251. $output .= preg_replace("!/\*/?%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]);
  252. }
  253. }
  254. if (!$no_output_filter && !$_template->has_nocache_code && (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))) {
  255. $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $_template);
  256. }
  257. // rendering (must be done before writing cache file because of {function} nocache handling)
  258. /** @var Smarty_Internal_Template $_smarty_tpl
  259. * used in evaluated code
  260. */
  261. $_smarty_tpl = $_template;
  262. try {
  263. ob_start();
  264. eval("?>" . $output);
  265. $_output = ob_get_clean();
  266. }
  267. catch (Exception $e) {
  268. ob_get_clean();
  269. throw $e;
  270. }
  271. // write cache file content
  272. $_template->writeCachedContent($output);
  273. if ($this->smarty->debugging) {
  274. Smarty_Internal_Debug::end_cache($_template);
  275. }
  276. } else {
  277. // var_dump('renderTemplate', $_template->has_nocache_code, $_template->template_resource, $_template->properties['nocache_hash'], $_template->parent->properties['nocache_hash'], $_output);
  278. if (!empty($_template->properties['nocache_hash']) && !empty($_template->parent->properties['nocache_hash'])) {
  279. // replace nocache_hash
  280. $_output = str_replace("{$_template->properties['nocache_hash']}", $_template->parent->properties['nocache_hash'], $_output);
  281. $_template->parent->has_nocache_code = $_template->parent->has_nocache_code || $_template->has_nocache_code;
  282. }
  283. }
  284. } else {
  285. if ($this->smarty->debugging) {
  286. Smarty_Internal_Debug::start_cache($_template);
  287. }
  288. try {
  289. ob_start();
  290. array_unshift($_template->_capture_stack, array());
  291. //
  292. // render cached template
  293. //
  294. $_template->properties['unifunc']($_template);
  295. // any unclosed {capture} tags ?
  296. if (isset($_template->_capture_stack[0][0])) {
  297. $_template->capture_error();
  298. }
  299. array_shift($_template->_capture_stack);
  300. $_output = ob_get_clean();
  301. }
  302. catch (Exception $e) {
  303. ob_get_clean();
  304. throw $e;
  305. }
  306. if ($this->smarty->debugging) {
  307. Smarty_Internal_Debug::end_cache($_template);
  308. }
  309. }
  310. if ((!$this->caching || $_template->has_nocache_code || $_template->source->recompiled) && !$no_output_filter && (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))) {
  311. $_output = Smarty_Internal_Filter_Handler::runFilter('output', $_output, $_template);
  312. }
  313. if (isset($this->error_reporting)) {
  314. error_reporting($_smarty_old_error_level);
  315. }
  316. // display or fetch
  317. if ($display) {
  318. if ($this->caching && $this->cache_modified_check) {
  319. $_isCached = $_template->isCached() && !$_template->has_nocache_code;
  320. $_last_modified_date = @substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_SERVER['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3);
  321. if ($_isCached && $_template->cached->timestamp <= strtotime($_last_modified_date)) {
  322. switch (PHP_SAPI) {
  323. case 'cgi': // php-cgi < 5.3
  324. case 'cgi-fcgi': // php-cgi >= 5.3
  325. case 'fpm-fcgi': // php-fpm >= 5.3.3
  326. header('Status: 304 Not Modified');
  327. break;
  328. case 'cli':
  329. if ( /* ^phpunit */
  330. !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */
  331. ) {
  332. $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = '304 Not Modified';
  333. }
  334. break;
  335. default:
  336. header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
  337. break;
  338. }
  339. } else {
  340. switch (PHP_SAPI) {
  341. case 'cli':
  342. if ( /* ^phpunit */
  343. !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */
  344. ) {
  345. $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = 'Last-Modified: ' . gmdate('D, d M Y H:i:s', $_template->cached->timestamp) . ' GMT';
  346. }
  347. break;
  348. default:
  349. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $_template->cached->timestamp) . ' GMT');
  350. break;
  351. }
  352. echo $_output;
  353. }
  354. } else {
  355. echo $_output;
  356. }
  357. // debug output
  358. if ($this->smarty->debugging) {
  359. Smarty_Internal_Debug::display_debug($_template);
  360. }
  361. if ($merge_tpl_vars) {
  362. // restore local variables
  363. $_template->tpl_vars = $save_tpl_vars;
  364. $_template->config_vars = $save_config_vars;
  365. }
  366. return;
  367. } else {
  368. if ($merge_tpl_vars) {
  369. // restore local variables
  370. $_template->tpl_vars = $save_tpl_vars;
  371. $_template->config_vars = $save_config_vars;
  372. }
  373. // return fetched content
  374. return $_output;
  375. }
  376. }
  377. /**
  378. * displays a Smarty template
  379. *
  380. * @param string $template the resource handle of the template file or template object
  381. * @param mixed $cache_id cache id to be used with this template
  382. * @param mixed $compile_id compile id to be used with this template
  383. * @param object $parent next higher level of Smarty variables
  384. */
  385. public function display($template = null, $cache_id = null, $compile_id = null, $parent = null)
  386. {
  387. // display template
  388. $this->fetch($template, $cache_id, $compile_id, $parent, true);
  389. }
  390. /**
  391. * test if cache is valid
  392. *
  393. * @param string|object $template the resource handle of the template file or template object
  394. * @param mixed $cache_id cache id to be used with this template
  395. * @param mixed $compile_id compile id to be used with this template
  396. * @param object $parent next higher level of Smarty variables
  397. *
  398. * @return boolean cache status
  399. */
  400. public function isCached($template = null, $cache_id = null, $compile_id = null, $parent = null)
  401. {
  402. if ($template === null && $this instanceof $this->template_class) {
  403. return $this->cached->valid;
  404. }
  405. if (!($template instanceof $this->template_class)) {
  406. if ($parent === null) {
  407. $parent = $this;
  408. }
  409. $template = $this->smarty->createTemplate($template, $cache_id, $compile_id, $parent, false);
  410. }
  411. // return cache status of template
  412. return $template->cached->valid;
  413. }
  414. /**
  415. * creates a data object
  416. *
  417. * @param object $parent next higher level of Smarty variables
  418. *
  419. * @returns Smarty_Data data object
  420. */
  421. public function createData($parent = null)
  422. {
  423. return new Smarty_Data($parent, $this);
  424. }
  425. /**
  426. * Registers plugin to be used in templates
  427. *
  428. * @param string $type plugin type
  429. * @param string $tag name of template tag
  430. * @param callback $callback PHP callback to register
  431. * @param boolean $cacheable if true (default) this fuction is cachable
  432. * @param array $cache_attr caching attributes if any
  433. *
  434. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  435. * @throws SmartyException when the plugin tag is invalid
  436. */
  437. public function registerPlugin($type, $tag, $callback, $cacheable = true, $cache_attr = null)
  438. {
  439. if (isset($this->smarty->registered_plugins[$type][$tag])) {
  440. throw new SmartyException("Plugin tag \"{$tag}\" already registered");
  441. } elseif (!is_callable($callback)) {
  442. throw new SmartyException("Plugin \"{$tag}\" not callable");
  443. } else {
  444. $this->smarty->registered_plugins[$type][$tag] = array($callback, (bool) $cacheable, (array) $cache_attr);
  445. }
  446. return $this;
  447. }
  448. /**
  449. * Unregister Plugin
  450. *
  451. * @param string $type of plugin
  452. * @param string $tag name of plugin
  453. *
  454. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  455. */
  456. public function unregisterPlugin($type, $tag)
  457. {
  458. if (isset($this->smarty->registered_plugins[$type][$tag])) {
  459. unset($this->smarty->registered_plugins[$type][$tag]);
  460. }
  461. return $this;
  462. }
  463. /**
  464. * Registers a resource to fetch a template
  465. *
  466. * @param string $type name of resource type
  467. * @param Smarty_Resource|array $callback or instance of Smarty_Resource, or array of callbacks to handle resource (deprecated)
  468. *
  469. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  470. */
  471. public function registerResource($type, $callback)
  472. {
  473. $this->smarty->registered_resources[$type] = $callback instanceof Smarty_Resource ? $callback : array($callback, false);
  474. return $this;
  475. }
  476. /**
  477. * Unregisters a resource
  478. *
  479. * @param string $type name of resource type
  480. *
  481. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  482. */
  483. public function unregisterResource($type)
  484. {
  485. if (isset($this->smarty->registered_resources[$type])) {
  486. unset($this->smarty->registered_resources[$type]);
  487. }
  488. return $this;
  489. }
  490. /**
  491. * Registers a cache resource to cache a template's output
  492. *
  493. * @param string $type name of cache resource type
  494. * @param Smarty_CacheResource $callback instance of Smarty_CacheResource to handle output caching
  495. *
  496. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  497. */
  498. public function registerCacheResource($type, Smarty_CacheResource $callback)
  499. {
  500. $this->smarty->registered_cache_resources[$type] = $callback;
  501. return $this;
  502. }
  503. /**
  504. * Unregisters a cache resource
  505. *
  506. * @param string $type name of cache resource type
  507. *
  508. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  509. */
  510. public function unregisterCacheResource($type)
  511. {
  512. if (isset($this->smarty->registered_cache_resources[$type])) {
  513. unset($this->smarty->registered_cache_resources[$type]);
  514. }
  515. return $this;
  516. }
  517. /**
  518. * Registers object to be used in templates
  519. *
  520. * @param $object_name
  521. * @param object $object_impl the referenced PHP object to register
  522. * @param array $allowed list of allowed methods (empty = all)
  523. * @param boolean $smarty_args smarty argument format, else traditional
  524. * @param array $block_methods list of block-methods
  525. *
  526. * @throws SmartyException
  527. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  528. */
  529. public function registerObject($object_name, $object_impl, $allowed = array(), $smarty_args = true, $block_methods = array())
  530. {
  531. // test if allowed methods callable
  532. if (!empty($allowed)) {
  533. foreach ((array) $allowed as $method) {
  534. if (!is_callable(array($object_impl, $method)) && !property_exists($object_impl, $method)) {
  535. throw new SmartyException("Undefined method or property '$method' in registered object");
  536. }
  537. }
  538. }
  539. // test if block methods callable
  540. if (!empty($block_methods)) {
  541. foreach ((array) $block_methods as $method) {
  542. if (!is_callable(array($object_impl, $method))) {
  543. throw new SmartyException("Undefined method '$method' in registered object");
  544. }
  545. }
  546. }
  547. // register the object
  548. $this->smarty->registered_objects[$object_name] =
  549. array($object_impl, (array) $allowed, (boolean) $smarty_args, (array) $block_methods);
  550. return $this;
  551. }
  552. /**
  553. * return a reference to a registered object
  554. *
  555. * @param string $name object name
  556. *
  557. * @return object
  558. * @throws SmartyException if no such object is found
  559. */
  560. public function getRegisteredObject($name)
  561. {
  562. if (!isset($this->smarty->registered_objects[$name])) {
  563. throw new SmartyException("'$name' is not a registered object");
  564. }
  565. if (!is_object($this->smarty->registered_objects[$name][0])) {
  566. throw new SmartyException("registered '$name' is not an object");
  567. }
  568. return $this->smarty->registered_objects[$name][0];
  569. }
  570. /**
  571. * unregister an object
  572. *
  573. * @param string $name object name
  574. *
  575. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  576. */
  577. public function unregisterObject($name)
  578. {
  579. if (isset($this->smarty->registered_objects[$name])) {
  580. unset($this->smarty->registered_objects[$name]);
  581. }
  582. return $this;
  583. }
  584. /**
  585. * Registers static classes to be used in templates
  586. *
  587. * @param $class_name
  588. * @param string $class_impl the referenced PHP class to register
  589. *
  590. * @throws SmartyException
  591. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  592. */
  593. public function registerClass($class_name, $class_impl)
  594. {
  595. // test if exists
  596. if (!class_exists($class_impl)) {
  597. throw new SmartyException("Undefined class '$class_impl' in register template class");
  598. }
  599. // register the class
  600. $this->smarty->registered_classes[$class_name] = $class_impl;
  601. return $this;
  602. }
  603. /**
  604. * Registers a default plugin handler
  605. *
  606. * @param callable $callback class/method name
  607. *
  608. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  609. * @throws SmartyException if $callback is not callable
  610. */
  611. public function registerDefaultPluginHandler($callback)
  612. {
  613. if (is_callable($callback)) {
  614. $this->smarty->default_plugin_handler_func = $callback;
  615. } else {
  616. throw new SmartyException("Default plugin handler '$callback' not callable");
  617. }
  618. return $this;
  619. }
  620. /**
  621. * Registers a default template handler
  622. *
  623. * @param callable $callback class/method name
  624. *
  625. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  626. * @throws SmartyException if $callback is not callable
  627. */
  628. public function registerDefaultTemplateHandler($callback)
  629. {
  630. if (is_callable($callback)) {
  631. $this->smarty->default_template_handler_func = $callback;
  632. } else {
  633. throw new SmartyException("Default template handler '$callback' not callable");
  634. }
  635. return $this;
  636. }
  637. /**
  638. * Registers a default template handler
  639. *
  640. * @param callable $callback class/method name
  641. *
  642. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  643. * @throws SmartyException if $callback is not callable
  644. */
  645. public function registerDefaultConfigHandler($callback)
  646. {
  647. if (is_callable($callback)) {
  648. $this->smarty->default_config_handler_func = $callback;
  649. } else {
  650. throw new SmartyException("Default config handler '$callback' not callable");
  651. }
  652. return $this;
  653. }
  654. /**
  655. * Registers a filter function
  656. *
  657. * @param string $type filter type
  658. * @param callback $callback
  659. *
  660. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  661. */
  662. public function registerFilter($type, $callback)
  663. {
  664. $this->smarty->registered_filters[$type][$this->_get_filter_name($callback)] = $callback;
  665. return $this;
  666. }
  667. /**
  668. * Unregisters a filter function
  669. *
  670. * @param string $type filter type
  671. * @param callback $callback
  672. *
  673. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  674. */
  675. public function unregisterFilter($type, $callback)
  676. {
  677. $name = $this->_get_filter_name($callback);
  678. if (isset($this->smarty->registered_filters[$type][$name])) {
  679. unset($this->smarty->registered_filters[$type][$name]);
  680. }
  681. return $this;
  682. }
  683. /**
  684. * Return internal filter name
  685. *
  686. * @param callback $function_name
  687. *
  688. * @return string internal filter name
  689. */
  690. public function _get_filter_name($function_name)
  691. {
  692. if (is_array($function_name)) {
  693. $_class_name = (is_object($function_name[0]) ?
  694. get_class($function_name[0]) : $function_name[0]);
  695. return $_class_name . '_' . $function_name[1];
  696. } else {
  697. return $function_name;
  698. }
  699. }
  700. /**
  701. * load a filter of specified type and name
  702. *
  703. * @param string $type filter type
  704. * @param string $name filter name
  705. *
  706. * @throws SmartyException if filter could not be loaded
  707. */
  708. public function loadFilter($type, $name)
  709. {
  710. $_plugin = "smarty_{$type}filter_{$name}";
  711. $_filter_name = $_plugin;
  712. if ($this->smarty->loadPlugin($_plugin)) {
  713. if (class_exists($_plugin, false)) {
  714. $_plugin = array($_plugin, 'execute');
  715. }
  716. if (is_callable($_plugin)) {
  717. $this->smarty->registered_filters[$type][$_filter_name] = $_plugin;
  718. return true;
  719. }
  720. }
  721. throw new SmartyException("{$type}filter \"{$name}\" not callable");
  722. }
  723. /**
  724. * unload a filter of specified type and name
  725. *
  726. * @param string $type filter type
  727. * @param string $name filter name
  728. *
  729. * @return Smarty_Internal_Templatebase current Smarty_Internal_Templatebase (or Smarty or Smarty_Internal_Template) instance for chaining
  730. */
  731. public function unloadFilter($type, $name)
  732. {
  733. $_filter_name = "smarty_{$type}filter_{$name}";
  734. if (isset($this->smarty->registered_filters[$type][$_filter_name])) {
  735. unset ($this->smarty->registered_filters[$type][$_filter_name]);
  736. }
  737. return $this;
  738. }
  739. /**
  740. * preg_replace callback to convert camelcase getter/setter to underscore property names
  741. *
  742. * @param string $match match string
  743. *
  744. * @return string replacemant
  745. */
  746. private function replaceCamelcase($match)
  747. {
  748. return "_" . strtolower($match[1]);
  749. }
  750. /**
  751. * Handle unknown class methods
  752. *
  753. * @param string $name unknown method-name
  754. * @param array $args argument array
  755. *
  756. * @throws SmartyException
  757. */
  758. public function __call($name, $args)
  759. {
  760. static $_prefixes = array('set' => true, 'get' => true);
  761. static $_resolved_property_name = array();
  762. static $_resolved_property_source = array();
  763. // method of Smarty object?
  764. if (method_exists($this->smarty, $name)) {
  765. return call_user_func_array(array($this->smarty, $name), $args);
  766. }
  767. // see if this is a set/get for a property
  768. $first3 = strtolower(substr($name, 0, 3));
  769. if (isset($_prefixes[$first3]) && isset($name[3]) && $name[3] !== '_') {
  770. if (isset($_resolved_property_name[$name])) {
  771. $property_name = $_resolved_property_name[$name];
  772. } else {
  773. // try to keep case correct for future PHP 6.0 case-sensitive class methods
  774. // lcfirst() not available < PHP 5.3.0, so improvise
  775. $property_name = strtolower(substr($name, 3, 1)) . substr($name, 4);
  776. // convert camel case to underscored name
  777. $property_name = preg_replace_callback('/([A-Z])/', array($this, 'replaceCamelcase'), $property_name);
  778. $_resolved_property_name[$name] = $property_name;
  779. }
  780. if (isset($_resolved_property_source[$property_name])) {
  781. $_is_this = $_resolved_property_source[$property_name];
  782. } else {
  783. $_is_this = null;
  784. if (property_exists($this, $property_name)) {
  785. $_is_this = true;
  786. } elseif (property_exists($this->smarty, $property_name)) {
  787. $_is_this = false;
  788. }
  789. $_resolved_property_source[$property_name] = $_is_this;
  790. }
  791. if ($_is_this) {
  792. if ($first3 == 'get') {
  793. return $this->$property_name;
  794. } else {
  795. return $this->$property_name = $args[0];
  796. }
  797. } elseif ($_is_this === false) {
  798. if ($first3 == 'get') {
  799. return $this->smarty->$property_name;
  800. } else {
  801. return $this->smarty->$property_name = $args[0];
  802. }
  803. } else {
  804. throw new SmartyException("property '$property_name' does not exist.");
  805. }
  806. }
  807. if ($name == 'Smarty') {
  808. throw new SmartyException("PHP5 requires you to call __construct() instead of Smarty()");
  809. }
  810. // must be unknown
  811. throw new SmartyException("Call of unknown method '$name'.");
  812. }
  813. }