Template.class.php 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632
  1. <?php
  2. /**
  3. * Template.class.php
  4. *
  5. * This file contains an abstract (PHP 4, so "abstract" is relative)
  6. * class meant to define the basic template interface for the
  7. * SquirrelMail core application. Subclasses should extend this
  8. * class with any custom functionality needed to interface a target
  9. * templating engine with SquirrelMail.
  10. *
  11. * @copyright &copy; 2003-2007 The SquirrelMail Project Team
  12. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  13. * @version $Id$
  14. * @package squirrelmail
  15. * @subpackage Template
  16. * @since 1.5.2
  17. *
  18. */
  19. /** load template functions */
  20. require(SM_PATH . 'functions/template/general_util.php');
  21. /**
  22. * The SquirrelMail Template class.
  23. *
  24. * Basic template class for capturing values and pluging them into a template.
  25. * This class uses a similar API to Smarty.
  26. *
  27. * Methods that must be implemented by subclasses are as follows (see method
  28. * stubs below for further information about expected behavior):
  29. *
  30. * assign()
  31. * assign_by_ref()
  32. * clear_all_assign()
  33. * get_template_vars()
  34. * append()
  35. * append_by_ref()
  36. * apply_template()
  37. *
  38. * @author Paul Lesniewski <paul at squirrelmail.org>
  39. * @package squirrelmail
  40. *
  41. */
  42. class Template
  43. {
  44. /**
  45. * The template ID
  46. *
  47. * @var string
  48. *
  49. */
  50. var $template_set_id = '';
  51. /**
  52. * The template set base directory (relative path from
  53. * the main SquirrelMail directory (SM_PATH))
  54. *
  55. * @var string
  56. *
  57. */
  58. var $template_dir = '';
  59. /**
  60. * The template engine (please use constants defined in constants.php)
  61. *
  62. * @var string
  63. *
  64. */
  65. var $template_engine = '';
  66. /**
  67. * The content type for this template set
  68. */
  69. var $content_type = '';
  70. /**
  71. * The fall-back template ID
  72. *
  73. * @var string
  74. *
  75. */
  76. var $fallback_template_set_id = '';
  77. /**
  78. * The fall-back template directory (relative
  79. * path from the main SquirrelMail directory (SM_PATH))
  80. *
  81. * @var string
  82. *
  83. */
  84. var $fallback_template_dir = '';
  85. /**
  86. * The fall-back template engine (please use
  87. * constants defined in constants.php)
  88. *
  89. * @var string
  90. *
  91. */
  92. var $fallback_template_engine = '';
  93. /**
  94. * Template file cache. Structured as an array, whose keys
  95. * are all the template file names (with path information relative
  96. * to the template set's base directory, e.g., "css/style.css")
  97. * found in all parent template sets including the ultimate fall-back
  98. * template set. Array values are sub-arrays with the
  99. * following key-value pairs:
  100. *
  101. * PATH -- file path, relative to SM_PATH
  102. * SET_ID -- the ID of the template set that this file belongs to
  103. * ENGINE -- the engine needed to render this template file
  104. *
  105. */
  106. var $template_file_cache = array();
  107. /**
  108. * Extra template engine class objects for rendering templates
  109. * that require a different engine than the one for the current
  110. * template set. Keys should be the name of the template engine,
  111. * values are the corresponding class objects.
  112. *
  113. * @var array
  114. *
  115. */
  116. var $other_template_engine_objects = array();
  117. /**
  118. * Constructor
  119. *
  120. * Please do not call directly. Use Template::construct_template().
  121. *
  122. * @param string $template_set_id the template ID
  123. *
  124. */
  125. function Template($template_set_id) {
  126. //FIXME: find a way to test that this is ONLY ever called
  127. // from the construct_template() method (I doubt it
  128. // is worth the trouble to parse the current stack trace)
  129. // if (???)
  130. // trigger_error('Please do not use default Template() constructor. Instead, use Template::construct_template().', E_USER_ERROR);
  131. $this->set_up_template($template_set_id);
  132. }
  133. /**
  134. * Construct Template
  135. *
  136. * This method should always be called instead of trying
  137. * to get a Template object from the normal/default constructor,
  138. * and is necessary in order to control the return value.
  139. *
  140. * @param string $template_set_id the template ID
  141. *
  142. * @return object The correct Template object for the given template set
  143. *
  144. * @static
  145. *
  146. */
  147. function construct_template($template_set_id) {
  148. $template = new Template($template_set_id);
  149. $template->override_plugins();
  150. return $template->get_template_engine_subclass();
  151. }
  152. /**
  153. * Set up internal attributes
  154. *
  155. * This method does most of the work for setting up
  156. * newly constructed objects.
  157. *
  158. * @param string $template_set_id the template ID
  159. *
  160. */
  161. function set_up_template($template_set_id) {
  162. // FIXME: do we want to place any restrictions on the ID like
  163. // making sure no slashes included?
  164. // get template ID
  165. //
  166. $this->template_set_id = $template_set_id;
  167. $this->fallback_template_set_id = Template::get_fallback_template_set();
  168. // set up template directories
  169. //
  170. $this->template_dir
  171. = Template::calculate_template_file_directory($this->template_set_id);
  172. $this->fallback_template_dir
  173. = Template::calculate_template_file_directory($this->fallback_template_set_id);
  174. // determine content type, defaulting to text/html
  175. //
  176. $this->content_type = Template::get_template_config($this->template_set_id,
  177. 'content_type',
  178. 'text/html');
  179. // determine template engine
  180. // FIXME: assuming PHP template engine may not necessarily be a good thing
  181. //
  182. $this->template_engine = Template::get_template_config($this->template_set_id,
  183. 'template_engine',
  184. SQ_PHP_TEMPLATE);
  185. // get template file cache
  186. //
  187. $this->template_file_cache = Template::cache_template_file_hierarchy($template_set_id);
  188. }
  189. /**
  190. * Determine what the ultimate fallback template set is.
  191. *
  192. * NOTE that if the fallback setting cannot be found in the
  193. * main SquirrelMail configuration settings that the value
  194. * of $default is returned.
  195. *
  196. * @param string $default The template set ID to use if
  197. * the fallback setting cannot be
  198. * found in SM config (optional;
  199. * defaults to "default").
  200. *
  201. * @return string The ID of the fallback template set.
  202. *
  203. * @static
  204. *
  205. */
  206. function get_fallback_template_set($default='default') {
  207. // FIXME: do we want to place any restrictions on the ID such as
  208. // making sure no slashes included?
  209. // values are in main SM config file
  210. //
  211. global $templateset_fallback, $aTemplateSet;
  212. $aTemplateSet = (!isset($aTemplateSet) || !is_array($aTemplateSet)
  213. ? array() : $aTemplateSet);
  214. $templateset_fallback = (!isset($templateset_fallback)
  215. ? $default : $templateset_fallback);
  216. // iterate through all template sets, is this a valid skin ID?
  217. //
  218. $found_it = FALSE;
  219. foreach ($aTemplateSet as $aTemplate) {
  220. if ($aTemplate['ID'] === $templateset_fallback) {
  221. $found_it = TRUE;
  222. break;
  223. }
  224. }
  225. if ($found_it)
  226. return $templateset_fallback;
  227. // FIXME: note that it is possible for $default to
  228. // point to an invalid (nonexistent) template set
  229. // and that error will not be caught here
  230. //
  231. return $default;
  232. }
  233. /**
  234. * Determine what the default template set is.
  235. *
  236. * NOTE that if the default setting cannot be found in the
  237. * main SquirrelMail configuration settings that the value
  238. * of $default is returned.
  239. *
  240. * @param string $default The template set ID to use if
  241. * the default setting cannot be
  242. * found in SM config (optional;
  243. * defaults to "default").
  244. *
  245. * @return string The ID of the default template set.
  246. *
  247. * @static
  248. *
  249. */
  250. function get_default_template_set($default='default') {
  251. // FIXME: do we want to place any restrictions on the ID such as
  252. // making sure no slashes included?
  253. // values are in main SM config file
  254. //
  255. global $templateset_default, $aTemplateSet;
  256. $aTemplateSet = (!isset($aTemplateSet) || !is_array($aTemplateSet)
  257. ? array() : $aTemplateSet);
  258. $templateset_default = (!isset($templateset_default)
  259. ? $default : $templateset_default);
  260. // iterate through all template sets, is this a valid skin ID?
  261. //
  262. $found_it = FALSE;
  263. foreach ($aTemplateSet as $aTemplate) {
  264. if ($aTemplate['ID'] === $templateset_default) {
  265. $found_it = TRUE;
  266. break;
  267. }
  268. }
  269. if ($found_it)
  270. return $templateset_default;
  271. // FIXME: note that it is possible for $default to
  272. // point to an invalid (nonexistent) template set
  273. // and that error will not be caught here
  274. //
  275. return $default;
  276. }
  277. /**
  278. * Determine what the RPC template set is.
  279. *
  280. * NOTE that if the default setting cannot be found in the
  281. * main SquirrelMail configuration settings that the value
  282. * of $default is returned.
  283. *
  284. * @param string $default The template set ID to use if
  285. * the default setting cannot be
  286. * found in SM config (optional;
  287. * defaults to "default_rpc").
  288. *
  289. * @return string The ID of the RPC template set.
  290. *
  291. * @static
  292. *
  293. */
  294. function get_rpc_template_set($default='default_rpc') {
  295. // FIXME: do we want to place any restrictions on the ID such as
  296. // making sure no slashes included?
  297. // values are in main SM config file
  298. //
  299. global $rpc_templateset;
  300. $rpc_templateset = (!isset($rpc_templateset)
  301. ? $default : $rpc_templateset);
  302. // FIXME: note that it is possible for this to
  303. // point to an invalid (nonexistent) template set
  304. // and that error will not be caught here
  305. //
  306. return $rpc_templateset;
  307. }
  308. /**
  309. * Allow template set to override plugin configuration by either
  310. * adding or removing plugins.
  311. *
  312. * NOTE: due to when this code executes, plugins activated here
  313. * do not have access to the config_override and loading_prefs
  314. * hooks; instead, such plugins can use the
  315. * "template_plugins_override_after" hook defined below.
  316. *
  317. */
  318. function override_plugins() {
  319. global $disable_plugins, $plugins, $squirrelmail_plugin_hooks, $null;
  320. if ($disable_plugins) return;
  321. $add_plugins = Template::get_template_config($this->template_set_id,
  322. 'add_plugins', array());
  323. $remove_plugins = Template::get_template_config($this->template_set_id,
  324. 'remove_plugins', array());
  325. //FIXME (?) we assume $add_plugins and $remove_plugins are arrays -- we could
  326. // error check here, or just assume that template authors or admins
  327. // won't screw up their config files
  328. // disable all plugins? (can still add some by using $add_plugins)
  329. //
  330. if (in_array('*', $remove_plugins)) {
  331. $plugins = array();
  332. $squirrelmail_plugin_hooks = array();
  333. $remove_plugins = array();
  334. }
  335. foreach ($add_plugins as $plugin_name) {
  336. // add plugin to global plugin array
  337. //
  338. $plugins[] = $plugin_name;
  339. // enable plugin -- emulate code from use_plugin() function
  340. // in SquirrelMail core, but also need to call the
  341. // "squirrelmail_plugin_init_<plugin_name>" function, which
  342. // in static configuration is not called (this inconsistency
  343. // could be a source of anomalous-seeming bugs in poorly
  344. // coded plugins)
  345. //
  346. if (file_exists(SM_PATH . "plugins/$plugin_name/setup.php")) {
  347. include_once(SM_PATH . "plugins/$plugin_name/setup.php");
  348. $function = "squirrelmail_plugin_init_$plugin_name";
  349. if (function_exists($function))
  350. $function();
  351. }
  352. }
  353. foreach ($remove_plugins as $plugin_name) {
  354. // remove plugin from both global plugin & plugin hook arrays
  355. //
  356. $plugin_key = array_search($plugin_name, $plugins);
  357. if (!is_null($plugin_key) && $plugin_key !== FALSE) {
  358. unset($plugins[$plugin_key]);
  359. if (is_array($squirrelmail_plugin_hooks))
  360. foreach (array_keys($squirrelmail_plugin_hooks) as $hookName) {
  361. unset($squirrelmail_plugin_hooks[$hookName][$plugin_name]);
  362. }
  363. }
  364. }
  365. do_hook('template_plugins_override_after', $null);
  366. }
  367. /**
  368. * Instantiate and return correct subclass for this template
  369. * set's templating engine.
  370. *
  371. * @param string $template_set_id The template set whose engine
  372. * is to be used as an override
  373. * (if not given, this template
  374. * set's engine is used) (optional).
  375. *
  376. * @return object The Template subclass object for the template engine.
  377. *
  378. */
  379. function get_template_engine_subclass($template_set_id='') {
  380. if (empty($template_set_id)) $template_set_id = $this->template_set_id;
  381. // FIXME: assuming PHP template engine may not necessarily be a good thing
  382. $engine = Template::get_template_config($template_set_id,
  383. 'template_engine', SQ_PHP_TEMPLATE);
  384. $engine_class_file = SM_PATH . 'class/template/'
  385. . $engine . 'Template.class.php';
  386. if (!file_exists($engine_class_file)) {
  387. trigger_error('Unknown template engine (' . $engine
  388. . ') was specified in template configuration file',
  389. E_USER_ERROR);
  390. }
  391. $engine_class = $engine . 'Template';
  392. require_once($engine_class_file);
  393. return new $engine_class($template_set_id);
  394. }
  395. /**
  396. * Determine the relative template directory path for
  397. * the given template ID.
  398. *
  399. * @param string $template_set_id The template ID from which to build
  400. * the directory path
  401. *
  402. * @return string The relative template path (based off of SM_PATH)
  403. *
  404. * @static
  405. *
  406. */
  407. function calculate_template_file_directory($template_set_id) {
  408. return 'templates/' . $template_set_id . '/';
  409. }
  410. /**
  411. * Determine the relative images directory path for
  412. * the given template ID.
  413. *
  414. * @param string $template_set_id The template ID from which to build
  415. * the directory path
  416. *
  417. * @return string The relative images path (based off of SM_PATH)
  418. *
  419. * @static
  420. *
  421. */
  422. function calculate_template_images_directory($template_set_id) {
  423. return 'templates/' . $template_set_id . '/images/';
  424. }
  425. /**
  426. * Return the relative template directory path for this template set.
  427. *
  428. * @return string The relative path to the template directory based
  429. * from the main SquirrelMail directory (SM_PATH).
  430. *
  431. */
  432. function get_template_file_directory() {
  433. return $this->template_dir;
  434. }
  435. /**
  436. * Return the template ID for the fallback template set.
  437. *
  438. * @return string The ID of the fallback template set.
  439. *
  440. */
  441. function get_fallback_template_set_id() {
  442. return $this->fallback_template_set_id;
  443. }
  444. /**
  445. * Return the relative template directory path for the
  446. * fallback template set.
  447. *
  448. * @return string The relative path to the fallback template
  449. * directory based from the main SquirrelMail
  450. * directory (SM_PATH).
  451. *
  452. */
  453. function get_fallback_template_file_directory() {
  454. return $this->fallback_template_dir;
  455. }
  456. /**
  457. * Return the content-type for this template set.
  458. *
  459. * @return string The content-type.
  460. *
  461. */
  462. function get_content_type() {
  463. return $this->content_type;
  464. }
  465. /**
  466. * Get template set config setting
  467. *
  468. * Given a template set ID and setting name, returns the
  469. * setting's value. Note that settings are cached in
  470. * session, so "live" changes to template configuration
  471. * won't be reflected until the user logs out and back
  472. * in again.
  473. *
  474. * @param string $template_set_id The template set for which
  475. * to look up the setting.
  476. * @param string $setting The name of the setting to
  477. * retrieve.
  478. * @param mixed $default When the requested setting
  479. * is not found, the contents
  480. * of this value are returned
  481. * instead (optional; default
  482. * is NULL).
  483. * NOTE that unlike sqGetGlobalVar(),
  484. * this function will also return
  485. * the default value if the
  486. * requested setting is found
  487. * but is empty.
  488. * @param boolean $live_config When TRUE, the target template
  489. * set's configuration file is
  490. * reloaded every time this
  491. * method is called. Default
  492. * behavior is to only load the
  493. * configuration file if it had
  494. * never been loaded before, but
  495. * not again after that (optional;
  496. * default FALSE). Use with care!
  497. * Should mostly be used for
  498. * debugging.
  499. *
  500. * @return mixed The desired setting's value or if not found,
  501. * the contents of $default are returned.
  502. *
  503. * @static
  504. *
  505. */
  506. function get_template_config($template_set_id, $setting,
  507. $default=NULL, $live_config=FALSE) {
  508. sqGetGlobalVar('template_configuration_settings',
  509. $template_configuration_settings,
  510. SQ_SESSION,
  511. array());
  512. if ($live_config) unset($template_configuration_settings[$template_set_id]);
  513. // NOTE: could use isset() instead of empty() below, but
  514. // this function is designed to replace empty values
  515. // as well as non-existing values with $default
  516. //
  517. if (!empty($template_configuration_settings[$template_set_id][$setting]))
  518. return $template_configuration_settings[$template_set_id][$setting];
  519. // if template set configuration has been loaded, but this
  520. // setting is not known, return $default
  521. //
  522. if (!empty($template_configuration_settings[$template_set_id]))
  523. return $default;
  524. // otherwise (template set configuration has not been loaded before),
  525. // load it into session and return the desired setting after that
  526. //
  527. $template_config_file = SM_PATH
  528. . Template::calculate_template_file_directory($template_set_id)
  529. . 'config.php';
  530. if (!file_exists($template_config_file)) {
  531. trigger_error('No template configuration file was found where expected: ("'
  532. . $template_config_file . '")', E_USER_ERROR);
  533. } else {
  534. // we require() the file to let PHP do the variable value
  535. // parsing for us, and read the file in manually so we can
  536. // know what variable names are used in the config file
  537. // (settings can be different depending on specific requirements
  538. // of different template engines)... the other way this may
  539. // be accomplished is to somehow diff the symbol table
  540. // before/after the require(), but anyway, this code should
  541. // only run once for this template set...
  542. //
  543. require($template_config_file);
  544. $file_contents = implode("\n", file($template_config_file));
  545. // note that this assumes no template settings have
  546. // a string in them that looks like a variable name like $x
  547. // also note that this will attempt to grab things like
  548. // $Id found in CVS headers, so we try to adjust for that
  549. // by checking that the variable is actually set
  550. //
  551. preg_match_all('/\$(\w+)/', $file_contents, $variables, PREG_PATTERN_ORDER);
  552. foreach ($variables[1] as $variable) {
  553. if (isset($$variable))
  554. $template_configuration_settings[$template_set_id][$variable]
  555. = $$variable;
  556. }
  557. sqsession_register($template_configuration_settings,
  558. 'template_configuration_settings');
  559. // NOTE: could use isset() instead of empty() below, but
  560. // this function is designed to replace empty values
  561. // as well as non-existing values with $default
  562. //
  563. if (!empty($template_configuration_settings[$template_set_id][$setting]))
  564. return $template_configuration_settings[$template_set_id][$setting];
  565. else
  566. return $default;
  567. }
  568. }
  569. /**
  570. * Obtain template file hierarchy from cache.
  571. *
  572. * If the file hierarchy does not exist in session, it is
  573. * constructed and stored in session before being returned
  574. * to the caller.
  575. *
  576. * @param string $template_set_id The template set for which
  577. * the cache should be built.
  578. * This function will save more
  579. * than one set's files, so it
  580. * may be called multiple times
  581. * with different values for this
  582. * argument. When regenerating,
  583. * all set caches are dumped.
  584. * @param boolean $regenerate_cache When TRUE, the file hierarchy
  585. * is reloaded and stored fresh
  586. * (optional; default FALSE).
  587. * @param array $additional_files Must be in same form as the
  588. * files in the file hierarchy
  589. * cache. These are then added
  590. * to the cache (optional; default
  591. * empty - no additional files).
  592. *
  593. * @return array Template file hierarchy array, whose keys
  594. * are all the template file names for the given
  595. * template set ID (with path information relative
  596. * to the template set's base directory, e.g.,
  597. * "css/style.css") found in all parent template
  598. * sets including the ultimate fall-back template
  599. * set. Array values are sub-arrays with the
  600. * following key-value pairs:
  601. *
  602. * PATH -- file path, relative to SM_PATH
  603. * SET_ID -- the ID of the template set that this file belongs to
  604. * ENGINE -- the engine needed to render this template file
  605. *
  606. * @static
  607. *
  608. */
  609. function cache_template_file_hierarchy($template_set_id,
  610. $regenerate_cache=FALSE,
  611. $additional_files=array()) {
  612. sqGetGlobalVar('template_file_hierarchy', $template_file_hierarchy,
  613. SQ_SESSION, array());
  614. if ($regenerate_cache) unset($template_file_hierarchy);
  615. if (!empty($template_file_hierarchy[$template_set_id])) {
  616. // have to add additional files if given before returning
  617. //
  618. if (!empty($additional_files)) {
  619. $template_file_hierarchy[$template_set_id]
  620. = array_merge($template_file_hierarchy[$template_set_id],
  621. $additional_files);
  622. sqsession_register($template_file_hierarchy,
  623. 'template_file_hierarchy');
  624. }
  625. return $template_file_hierarchy[$template_set_id];
  626. }
  627. // nothing in cache apparently, so go build it now
  628. //
  629. $template_file_hierarchy[$template_set_id] = Template::catalog_template_files($template_set_id);
  630. // additional files, if any
  631. //
  632. if (!empty($additional_files)) {
  633. $template_file_hierarchy[$template_set_id]
  634. = array_merge($template_file_hierarchy[$template_set_id],
  635. $additional_files);
  636. }
  637. sqsession_register($template_file_hierarchy,
  638. 'template_file_hierarchy');
  639. return $template_file_hierarchy[$template_set_id];
  640. }
  641. /**
  642. * Traverse template hierarchy and catalogue all template
  643. * files (for storing in cache).
  644. *
  645. * Paths to all files in all parent, grand-parent, great grand
  646. * parent, etc. template sets (including the fallback template)
  647. * are catalogued; for identically named files, the file earlier
  648. * in the hierarchy (closest to this template set) is used.
  649. *
  650. * Refuses to traverse directories called ".svn"
  651. *
  652. * @param string $template_set_id The template set in which to
  653. * search for files
  654. * @param array $file_list The file list so far to be added
  655. * to (allows recursive behavior)
  656. * (optional; default empty array).
  657. * @param string $directory The directory in which to search for
  658. * files (must be given as full path).
  659. * If empty, starts at top-level template
  660. * set directory (optional; default empty).
  661. * NOTE! Use with care, as behavior is
  662. * unpredictable if directory given is not
  663. * part of correct template set.
  664. *
  665. * @return mixed The top-level caller will have an array of template
  666. * files returned to it; recursive calls to this function
  667. * do not receive any return value at all. The format
  668. * of the template file array is as described for the
  669. * Template class attribute $template_file_cache
  670. *
  671. * @static
  672. *
  673. */
  674. function catalog_template_files($template_set_id, $file_list=array(), $directory='') {
  675. $template_base_dir = SM_PATH
  676. . Template::calculate_template_file_directory($template_set_id);
  677. if (empty($directory)) {
  678. $directory = $template_base_dir;
  679. }
  680. // bail if we have been asked to traverse a Subversion directory
  681. //
  682. if (strpos($directory, '/.svn') === strlen($directory) - 5) return $file_list;
  683. $files_and_dirs = list_files($directory, '', FALSE, TRUE, FALSE, TRUE);
  684. // recurse for all the subdirectories in the template set
  685. //
  686. foreach ($files_and_dirs['DIRECTORIES'] as $dir) {
  687. $file_list = Template::catalog_template_files($template_set_id, $file_list, $dir);
  688. }
  689. // place all found files in the cache
  690. // FIXME: assuming PHP template engine may not necessarily be a good thing
  691. //
  692. $engine = Template::get_template_config($template_set_id,
  693. 'template_engine', SQ_PHP_TEMPLATE);
  694. foreach ($files_and_dirs['FILES'] as $file) {
  695. // remove the part of the file path corresponding to the
  696. // template set's base directory
  697. //
  698. $relative_file = substr($file, strlen($template_base_dir));
  699. /**
  700. * only put file in cache if not already found in earlier template
  701. * PATH should be relative to SquirrelMail top directory
  702. */
  703. if (!isset($file_list[$relative_file])) {
  704. $file_list[$relative_file] = array(
  705. 'PATH' => substr($file,strlen(SM_PATH)),
  706. 'SET_ID' => $template_set_id,
  707. 'ENGINE' => $engine,
  708. );
  709. }
  710. }
  711. // now if we are currently at the top-level of the template
  712. // set base directory, we need to move on to the parent
  713. // template set, if any
  714. //
  715. if ($directory == $template_base_dir) {
  716. // use fallback when we run out of parents
  717. //
  718. $fallback_id = Template::get_fallback_template_set();
  719. $parent_id = Template::get_template_config($template_set_id,
  720. 'parent_template_set',
  721. $fallback_id);
  722. // were we already all the way to the last level? just exit
  723. //
  724. // note that this code allows the fallback set to have
  725. // a parent, too, but can result in endless loops
  726. // if ($parent_id == $template_set_id) {
  727. //
  728. if ($fallback_id == $template_set_id) {
  729. return $file_list;
  730. }
  731. $file_list = Template::catalog_template_files($parent_id, $file_list);
  732. }
  733. return $file_list;
  734. }
  735. /**
  736. * Look for a template file in a plugin; add to template
  737. * file cache if found.
  738. *
  739. * The file is searched for in the following order:
  740. *
  741. * - A directory for the current template set within the plugin:
  742. * SM_PATH/plugins/<plugin name>/templates/<template name>/
  743. * - In a directory for one of the current template set's ancestor
  744. * (inherited) template sets within the plugin:
  745. * SM_PATH/plugins/<plugin name>/templates/<parent template name>/
  746. * - In a directory for the fallback template set within the plugin:
  747. * SM_PATH/plugins/<plugin name>/templates/<fallback template name>/
  748. *
  749. * @param string $plugin The name of the plugin
  750. * @param string $file The name of the template file
  751. * @param string $template_set_id The ID of the template for which
  752. * to start looking for the file
  753. * (optional; default is current
  754. * template set ID).
  755. *
  756. * @return boolean TRUE if the template file was found, FALSE otherwise.
  757. *
  758. */
  759. function find_and_cache_plugin_template_file($plugin, $file, $template_set_id='') {
  760. if (empty($template_set_id))
  761. $template_set_id = $this->template_set_id;
  762. $file_path = SM_PATH . 'plugins/' . $plugin . '/'
  763. . $this->calculate_template_file_directory($template_set_id)
  764. . $file;
  765. if (file_exists($file_path)) {
  766. // FIXME: assuming PHP template engine may not necessarily be a good thing
  767. $engine = $this->get_template_config($template_set_id,
  768. 'template_engine', SQ_PHP_TEMPLATE);
  769. $file_list = array('plugins/' . $plugin . '/' . $file => array(
  770. 'PATH' => substr($file_path, strlen(SM_PATH)),
  771. 'SET_ID' => $template_set_id,
  772. 'ENGINE' => $engine,
  773. )
  774. );
  775. $this->template_file_cache
  776. = $this->cache_template_file_hierarchy($this->template_set_id,
  777. FALSE,
  778. $file_list);
  779. return TRUE;
  780. }
  781. // not found yet, try parent template set
  782. // (use fallback when we run out of parents)
  783. //
  784. $fallback_id = $this->get_fallback_template_set();
  785. $parent_id = $this->get_template_config($template_set_id,
  786. 'parent_template_set',
  787. $fallback_id);
  788. // were we already all the way to the last level? just exit
  789. //
  790. // note that this code allows the fallback set to have
  791. // a parent, too, but can result in endless loops
  792. // if ($parent_id == $template_set_id) {
  793. //
  794. if ($fallback_id == $template_set_id) {
  795. return FALSE;
  796. }
  797. return $this->find_and_cache_plugin_template_file($plugin, $file, $parent_id);
  798. }
  799. /**
  800. * Find the right template file.
  801. *
  802. * The template file is taken from the template file cache, thus
  803. * the file is taken from the current template, one of its
  804. * ancestors or the fallback template.
  805. *
  806. * Note that it is perfectly acceptable to load template files from
  807. * template subdirectories. For example, JavaScript templates found
  808. * in the js/ subdirectory would be loaded by passing
  809. * "js/<javascript file name>" as the $filename.
  810. *
  811. * Note that the caller can also ask for ALL files in a directory
  812. * (and those in the same directory for all ancestor template sets)
  813. * by giving a $filename that is a directory name (ending with a
  814. * slash).
  815. *
  816. * If not found and the file is a plugin template file (indicated
  817. * by the presence of "plugins/" on the beginning of $filename),
  818. * the target plugin is searched for a substitue template file
  819. * before just returning nothing.
  820. *
  821. * Plugin authors must note that the $filename MUST be prefaced
  822. * with "plugins/<plugin name>/" in order to correctly resolve the
  823. * template file.
  824. *
  825. * @param string $filename The name of the template file,
  826. * possibly prefaced with
  827. * "plugins/<plugin name>/"
  828. * indicating that it is a plugin
  829. * template, or ending with a
  830. * slash, indicating that all files
  831. * for that directory name should
  832. * be returned.
  833. * @param boolean $directories_ok When TRUE, directory names
  834. * are acceptable search values,
  835. * and when returning a list of
  836. * directory contents, sub-directory
  837. * names will also be included
  838. * (optional; default FALSE).
  839. * NOTE that empty directories
  840. * are NOT included in the cache!
  841. * @param boolean $directories_only When TRUE, only directory names
  842. * are included in the returned
  843. * results. (optional; default
  844. * FALSE). Setting this argument
  845. * to TRUE forces $directories_ok
  846. * to TRUE as well.
  847. * NOTE that empty directories
  848. * are NOT included in the cache!
  849. *
  850. * @return mixed The full path to the template file or a list
  851. * of all files in the given directory if $filename
  852. * ends with a slash; if not found, an empty string
  853. * is returned. The caller is responsible for
  854. * throwing errors or other actions if template
  855. * file is not found.
  856. *
  857. */
  858. function get_template_file_path($filename,
  859. $directories_ok=FALSE,
  860. $directories_only=FALSE) {
  861. if ($directories_only) $directories_ok = TRUE;
  862. // only looking for directory listing first...
  863. //
  864. // return list of all files in a directory (and that
  865. // of any ancestors)
  866. //
  867. if ($filename{strlen($filename) - 1} == '/') {
  868. $return_array = array();
  869. foreach ($this->template_file_cache as $file => $file_info) {
  870. // only want files in the requested directory
  871. // (AND not in a subdirectory!)
  872. //
  873. if (!$directories_only && strpos($file, $filename) === 0
  874. && strpos($file, '/', strlen($filename)) === FALSE)
  875. $return_array[] = SM_PATH . $file_info['PATH'];
  876. // directories too? detect by finding any
  877. // array key that matches a file in a sub-directory
  878. // of the directory being processed
  879. //
  880. if ($directories_ok && strpos($file, $filename) === 0
  881. && ($pos = strpos($file, '/', strlen($filename))) !== FALSE
  882. && strpos($file, '/', $pos + 1) === FALSE) {
  883. $directory_name = SM_PATH
  884. . substr($file_info['PATH'],
  885. 0,
  886. strrpos($file_info['PATH'], '/'));
  887. if (!in_array($directory_name, $return_array))
  888. $return_array[] = $directory_name;
  889. }
  890. }
  891. return $return_array;
  892. }
  893. // just looking for singular file or directory below...
  894. //
  895. // figure out what to do with files not found
  896. //
  897. if ($directories_only || empty($this->template_file_cache[$filename]['PATH'])) {
  898. // if looking for directories...
  899. // have to iterate through cache and detect
  900. // directory by matching any file inside of it
  901. //
  902. if ($directories_ok) {
  903. foreach ($this->template_file_cache as $file => $file_info) {
  904. if (strpos($file, $filename) === 0
  905. && ($pos = strpos($file, '/', strlen($filename))) !== FALSE
  906. && strpos($file, '/', $pos + 1) === FALSE) {
  907. return SM_PATH . substr($file_info['PATH'],
  908. 0,
  909. strrpos($file_info['PATH'], '/'));
  910. }
  911. }
  912. if ($directories_only) return '';
  913. }
  914. // plugins get one more chance
  915. //
  916. if (strpos($filename, 'plugins/') === 0) {
  917. $plugin_name = substr($filename, 8, strpos($filename, '/', 8) - 8);
  918. $file = substr($filename, strlen($plugin_name) + 9);
  919. if (!$this->find_and_cache_plugin_template_file($plugin_name, $file))
  920. return '';
  921. //FIXME: technically I guess we should check for directories
  922. // here too, but that's overkill (no need) presently
  923. // (plugin-provided alternate stylesheet dirs?!? bah.)
  924. }
  925. // nothing... return empty string (yes, the else is intentional!)
  926. //
  927. else return '';
  928. }
  929. return SM_PATH . $this->template_file_cache[$filename]['PATH'];
  930. }
  931. /**
  932. * Get template engine needed to render given template file.
  933. *
  934. * If at all possible, just returns a reference to $this, but
  935. * some template files may require a different engine, thus
  936. * an object for that engine (which will subsequently be kept
  937. * in this object for future use) is returned.
  938. *
  939. * @param string $filename The name of the template file,
  940. *
  941. * @return object The needed template object to render the template.
  942. *
  943. */
  944. function get_rendering_template_engine_object($filename) {
  945. // for files that we cannot find engine info for,
  946. // just return $this
  947. //
  948. if (empty($this->template_file_cache[$filename]['ENGINE']))
  949. return $this;
  950. // otherwise, compare $this' engine to the file's engine
  951. //
  952. $engine = $this->template_file_cache[$filename]['ENGINE'];
  953. if ($this->template_engine == $engine)
  954. return $this;
  955. // need to load another engine... if already instantiated,
  956. // and stored herein, return that
  957. // FIXME: this assumes same engine setup in all template
  958. // set config files that have same engine in common
  959. // (but keeping a separate class object for every
  960. // template set seems like overkill... for now we
  961. // won't do that unless it becomes a problem)
  962. //
  963. if (!empty($this->other_template_engine_objects[$engine])) {
  964. $rendering_engine = $this->other_template_engine_objects[$engine];
  965. // otherwise, instantiate new engine object, add to cache
  966. // and return it
  967. //
  968. } else {
  969. $template_set_id = $this->template_file_cache[$filename]['SET_ID'];
  970. $this->other_template_engine_objects[$engine]
  971. = $this->get_template_engine_subclass($template_set_id);
  972. $rendering_engine = $this->other_template_engine_objects[$engine];
  973. }
  974. // now, need to copy over all the assigned variables
  975. // from $this to the rendering engine (YUCK! -- we need
  976. // to discourage template authors from creating
  977. // situations where engine changes occur)
  978. //
  979. $rendering_engine->clear_all_assign();
  980. $rendering_engine->assign($this->get_template_vars());
  981. // finally ready to go
  982. //
  983. return $rendering_engine;
  984. }
  985. /**
  986. * Return all JavaScript files provided by the template.
  987. *
  988. * All files found in the template set's "js" directory (and
  989. * that of its ancestors) with the extension ".js" are returned.
  990. *
  991. * @param boolean $full_path When FALSE, only the file names
  992. * are included in the return array;
  993. * otherwise, path information is
  994. * included (relative to SM_PATH)
  995. * (OPTIONAL; default only file names)
  996. *
  997. * @return array The required file names/paths.
  998. *
  999. */
  1000. function get_javascript_includes($full_path=FALSE) {
  1001. // since any page from a parent template set
  1002. // could end up being loaded, we have to load
  1003. // all js files from ancestor template sets,
  1004. // not just this set
  1005. //
  1006. //$directory = SM_PATH . $this->get_template_file_directory() . 'js';
  1007. //$js_files = list_files($directory, '.js', !$full_path);
  1008. //
  1009. $js_files = $this->get_template_file_path('js/');
  1010. // parse out .js files only
  1011. //
  1012. $return_array = array();
  1013. foreach ($js_files as $file) {
  1014. if (substr($file, strlen($file) - 3) != '.js') continue;
  1015. if ($full_path) {
  1016. $return_array[] = $file;
  1017. } else {
  1018. $return_array[] = basename($file);
  1019. }
  1020. }
  1021. return $return_array;
  1022. }
  1023. /**
  1024. * Return all alternate stylesheets provided by template.
  1025. *
  1026. * All (non-empty) directories found in the template set's
  1027. * "css/alternates" directory (and that of its ancestors)
  1028. * are returned.
  1029. *
  1030. * Note that prettified names are constructed herein by
  1031. * taking the directory name, changing underscores to spaces
  1032. * and capitalizing each word in the resultant name.
  1033. *
  1034. * @param boolean $full_path When FALSE, only the file names
  1035. * are included in the return array;
  1036. * otherwise, path information is
  1037. * included (relative to SM_PATH)
  1038. * (OPTIONAL; default only file names)
  1039. *
  1040. * @return array A list of the available alternate stylesheets,
  1041. * where the keys are the file names (formatted
  1042. * according to $full_path) for the stylesheets,
  1043. * and the values are the prettified version of
  1044. * the file names for display to the user.
  1045. *
  1046. */
  1047. function get_alternative_stylesheets($full_path=FALSE) {
  1048. // since any page from a parent template set
  1049. // could end up being loaded, we will load
  1050. // all alternate css files from ancestor
  1051. // template sets, not just this set
  1052. //
  1053. $css_directories = $this->get_template_file_path('css/alternates/', TRUE, TRUE);
  1054. // prettify names
  1055. //
  1056. $return_array = array();
  1057. foreach ($css_directories as $directory) {
  1058. // CVS and SVN directories are not wanted
  1059. //
  1060. if ((strpos($directory, '/CVS') === strlen($directory) - 4)
  1061. || (strpos($directory, '/.svn') === strlen($directory) - 5)) continue;
  1062. $pretty_name = ucwords(str_replace('_', ' ', basename($directory)));
  1063. if ($full_path) {
  1064. $return_array[$directory] = $pretty_name;
  1065. } else {
  1066. $return_array[basename($directory)] = $pretty_name;
  1067. }
  1068. }
  1069. return $return_array;
  1070. }
  1071. /**
  1072. * Return all standard stylsheets provided by the template.
  1073. *
  1074. * All files found in the template set's "css" directory (and
  1075. * that of its ancestors) with the extension ".css" except
  1076. * "rtl.css" (which is dealt with separately) are returned.
  1077. *
  1078. * @param boolean $full_path When FALSE, only the file names
  1079. * are included in the return array;
  1080. * otherwise, path information is
  1081. * included (relative to SM_PATH)
  1082. * (OPTIONAL; default only file names)
  1083. *
  1084. * @return array The required file names/paths.
  1085. *
  1086. */
  1087. function get_stylesheets($full_path=FALSE) {
  1088. // since any page from a parent template set
  1089. // could end up being loaded, we have to load
  1090. // all css files from ancestor template sets,
  1091. // not just this set
  1092. //
  1093. //$directory = SM_PATH . $this->get_template_file_directory() . 'css';
  1094. //$css_files = list_files($directory, '.css', !$full_path);
  1095. //
  1096. $css_files = $this->get_template_file_path('css/');
  1097. // need to leave out "rtl.css"
  1098. //
  1099. $return_array = array();
  1100. foreach ($css_files as $file) {
  1101. if (substr($file, strlen($file) - 4) != '.css') continue;
  1102. if (strtolower(basename($file)) == 'rtl.css') continue;
  1103. if ($full_path) {
  1104. $return_array[] = $file;
  1105. } else {
  1106. $return_array[] = basename($file);
  1107. }
  1108. }
  1109. // return sheets for the current template set
  1110. // last so we can enable any custom overrides
  1111. // of styles in ancestor sheets
  1112. //
  1113. return array_reverse($return_array);
  1114. }
  1115. /**
  1116. * Generate links to all this template set's standard stylesheets
  1117. *
  1118. * Subclasses can override this function if stylesheets are
  1119. * created differently for the template set's target output
  1120. * interface.
  1121. *
  1122. * @return string The stylesheet links as they should be sent
  1123. * to the browser.
  1124. *
  1125. */
  1126. function fetch_standard_stylesheet_links()
  1127. {
  1128. $sheets = $this->get_stylesheets(TRUE);
  1129. return $this->fetch_external_stylesheet_links($sheets);
  1130. }
  1131. /**
  1132. * Push out any other stylesheet links as provided (for
  1133. * stylesheets not included with the current template set)
  1134. *
  1135. * Subclasses can override this function if stylesheets are
  1136. * created differently for the template set's target output
  1137. * interface.
  1138. *
  1139. * @param mixed $sheets List of the desired stylesheets
  1140. * (file path to be used in stylesheet
  1141. * href attribute) to output (or single
  1142. * stylesheet file path).
  1143. FIXME: We could make the incoming array more complex so it can
  1144. also contain the other parameters for create_css_link()
  1145. such as $name, $alt, $mtype, and $xhtml_end
  1146. But do we need to?
  1147. *
  1148. * @return string The stylesheet links as they should be sent
  1149. * to the browser.
  1150. *
  1151. */
  1152. function fetch_external_stylesheet_links($sheets)
  1153. {
  1154. if (!is_array($sheets)) $sheets = array($sheets);
  1155. $output = '';
  1156. foreach ($sheets as $sheet) {
  1157. $output .= create_css_link($sheet);
  1158. }
  1159. return $output;
  1160. }
  1161. /**
  1162. * Send HTTP header(s) to browser.
  1163. *
  1164. * Subclasses can override this function if headers are
  1165. * managed differently in the engine's target output
  1166. * interface.
  1167. *
  1168. * @param mixed $headers A list of (or a single) header
  1169. * text to be sent.
  1170. * @param boolean $replace Whether or not to replace header(s)
  1171. * previously sent header(s) of the
  1172. * same type (this parameter may be
  1173. * ignored in some implementations
  1174. * of this class if the target interface
  1175. * does not support this functionality)
  1176. * (OPTIONAL; default = TRUE, always replace).
  1177. *
  1178. */
  1179. function header($headers, $replace=TRUE)
  1180. {
  1181. if (!is_array($headers)) $headers = array($headers);
  1182. foreach ($headers as $header) {
  1183. $this->assign('header', $header);
  1184. header($this->fetch('header.tpl'), $replace);
  1185. }
  1186. }
  1187. /**
  1188. * Generate a link to the right-to-left stylesheet for
  1189. * this template set by getting the "rtl.css" file from
  1190. * this template set, its parent (or grandparent, etc.)
  1191. * template set, the fall-back template set, or finally,
  1192. * fall back to SquirrelMail's own "rtl.css" if need be.
  1193. *
  1194. * Subclasses can override this function if stylesheets are
  1195. * created differently for the template set's target output
  1196. * interface.
  1197. *
  1198. * @return string The stylesheet link as it should be sent
  1199. * to the browser.
  1200. *
  1201. */
  1202. function fetch_right_to_left_stylesheet_link()
  1203. {
  1204. // get right template file
  1205. //
  1206. $sheet = $this->get_template_file_path('css/rtl.css');
  1207. // fall back to SquirrelMail's own default stylesheet
  1208. //
  1209. if (empty($sheet)) {
  1210. $sheet = SM_PATH . 'css/rtl.css';
  1211. }
  1212. return create_css_link($sheet);
  1213. }
  1214. /**
  1215. * Display the template
  1216. *
  1217. * @param string $file The template file to use
  1218. *
  1219. */
  1220. function display($file)
  1221. {
  1222. echo $this->fetch($file);
  1223. }
  1224. /**
  1225. * Applies the template and returns the resultant content string.
  1226. *
  1227. * @param string $file The template file to use
  1228. *
  1229. * @return string The template contents after applying the given template
  1230. *
  1231. */
  1232. function fetch($file) {
  1233. // get right template file
  1234. //
  1235. $template = $this->get_template_file_path($file);
  1236. // special case stylesheet.tpl falls back to SquirrelMail's
  1237. // own default stylesheet
  1238. //
  1239. if (empty($template) && $file == 'css/stylesheet.tpl') {
  1240. $template = SM_PATH . 'css/default.css';
  1241. }
  1242. if (empty($template)) {
  1243. trigger_error('The template "' . htmlspecialchars($file)
  1244. . '" could not be fetched!', E_USER_ERROR);
  1245. } else {
  1246. $aPluginOutput = array();
  1247. $temp = array(&$aPluginOutput, &$this);
  1248. $aPluginOutput = concat_hook_function('template_construct_' . $file,
  1249. $temp, TRUE);
  1250. $this->assign('plugin_output', $aPluginOutput);
  1251. //$output = $this->apply_template($template);
  1252. $rendering_engine = $this->get_rendering_template_engine_object($file);
  1253. $output = $rendering_engine->apply_template($template);
  1254. // CAUTION: USE OF THIS HOOK IS HIGHLY DISCOURAGED AND CAN
  1255. // RESULT IN NOTICABLE PERFORMANCE DEGREDATION. Plugins
  1256. // using this hook will probably be rejected by the
  1257. // SquirrelMail team.
  1258. //
  1259. do_hook('template_output', $output);
  1260. return $output;
  1261. }
  1262. }
  1263. /**
  1264. * Assigns values to template variables
  1265. *
  1266. * Note: this is an abstract method that must be implemented by subclass.
  1267. *
  1268. * @param array|string $tpl_var the template variable name(s)
  1269. * @param mixed $value the value to assign
  1270. *
  1271. */
  1272. function assign($tpl_var, $value = NULL) {
  1273. trigger_error('Template subclass (' . $this->template_engine . 'Template.class.php) needs to implement the assign() method.', E_USER_ERROR);
  1274. }
  1275. /**
  1276. * Assigns values to template variables by reference
  1277. *
  1278. * Note: this is an abstract method that must be implemented by subclass.
  1279. *
  1280. * @param string $tpl_var the template variable name
  1281. * @param mixed $value the referenced value to assign
  1282. *
  1283. */
  1284. function assign_by_ref($tpl_var, &$value) {
  1285. trigger_error('Template subclass (' . $this->template_engine . 'Template.class.php) needs to implement the assign_by_ref() method.', E_USER_ERROR);
  1286. }
  1287. /**
  1288. * Clears the values of all assigned varaiables.
  1289. *
  1290. */
  1291. function clear_all_assign() {
  1292. trigger_error('Template subclass (' . $this->template_engine . 'Template.class.php) needs to implement the clear_all_assign() method.', E_USER_ERROR);
  1293. }
  1294. /**
  1295. * Returns assigned variable value(s).
  1296. *
  1297. * @param string $varname If given, the value of that variable
  1298. * is returned, assuming it has been
  1299. * previously assigned. If not specified
  1300. * an array of all assigned variables is
  1301. * returned. (optional)
  1302. *
  1303. * @return mixed Desired single variable value or list of all
  1304. * assigned variable values.
  1305. *
  1306. */
  1307. function get_template_vars($varname=NULL) {
  1308. trigger_error('Template subclass (' . $this->template_engine . 'Template.class.php) needs to implement the get_template_vars() method.', E_USER_ERROR);
  1309. }
  1310. /**
  1311. * Appends values to template variables
  1312. *
  1313. * Note: this is an abstract method that must be implemented by subclass.
  1314. *
  1315. * @param array|string $tpl_var the template variable name(s)
  1316. * @param mixed $value the value to append
  1317. * @param boolean $merge when $value is given as an array,
  1318. * this indicates whether or not that
  1319. * array itself should be appended as
  1320. * a new template variable value or if
  1321. * that array's values should be merged
  1322. * into the existing array of template
  1323. * variable values
  1324. *
  1325. */
  1326. function append($tpl_var, $value = NULL, $merge = FALSE) {
  1327. trigger_error('Template subclass (' . $this->template_engine . 'Template.class.php) needs to implement the append() method.', E_USER_ERROR);
  1328. }
  1329. /**
  1330. * Appends values to template variables by reference
  1331. *
  1332. * Note: this is an abstract method that must be implemented by subclass.
  1333. *
  1334. * @param string $tpl_var the template variable name
  1335. * @param mixed $value the referenced value to append
  1336. * @param boolean $merge when $value is given as an array,
  1337. * this indicates whether or not that
  1338. * array itself should be appended as
  1339. * a new template variable value or if
  1340. * that array's values should be merged
  1341. * into the existing array of template
  1342. * variable values
  1343. *
  1344. */
  1345. function append_by_ref($tpl_var, &$value, $merge = FALSE) {
  1346. trigger_error('Template subclass (' . $this->template_engine . 'Template.class.php) needs to implement the append_by_ref() method.', E_USER_ERROR);
  1347. }
  1348. /**
  1349. * Applys the template and generates final output destined
  1350. * for the user's browser
  1351. *
  1352. * Note: this is an abstract method that must be implemented by subclass.
  1353. *
  1354. * @param string $filepath The full file path to the template to be applied
  1355. *
  1356. * @return string The output for the given template
  1357. *
  1358. */
  1359. function apply_template($filepath) {
  1360. trigger_error('Template subclass (' . $this->template_engine . 'Template.class.php) needs to implement the apply_template() method.', E_USER_ERROR);
  1361. }
  1362. }