XiTemplate Home Page XiTemplate
[ class tree: XiTemplate ] [ index: XiTemplate ] [ all elements ]

Source for file class.XiTemplate.php

Documentation is available at class.XiTemplate.php

  1. <?php
  2. /* vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2: */
  3. /**
  4. * class.XiTemplate.php
  5. *
  6. * PHP version 5.X REQUIRED
  7. *
  8. * This class file runs with error_reporting(E_STRICT) without creating any
  9. * E_NOTICE's.
  10. *
  11. * XiTemplate is based on Xtemplate by Barnabas Debreceni.
  12. * XiTemplate has been ported to take advantage of the PHP 5 object model,
  13. * which adds speed and more accurate handling of member variables and methods
  14. * within the class. Several new features are introduced like the ability to
  15. * pass a template from the buffer as well as from a file and the ability to
  16. * dynamically interpolate multidimensional arrays.
  17. * An attempt was also made to reduce the memory foot print and increase
  18. * performance. The performance gain comes during higher load situation
  19. * where there is less free memory.
  20. *
  21. * @package XiTemplate
  22. */
  23. /**
  24. * XiTemplate is a very fast and very easy to use PHP template engine that
  25. * enables a developer to completely seperate logic from presentation.
  26. *
  27. * @package XiTemplate
  28. * @version 1.0.1
  29. * @author Travis Miller <tmiller@web-1hosting.net>
  30. * @author Jim Grill <jimgrill@jimgrill.com>
  31. * @copyright Copyright (c) 2004, Travis Miller, Jim Grill
  32. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  33. * @tutorial XiTemplate.cls
  34. */
  35. class XiTemplate
  36. {
  37. /**
  38. * @desc raw contents of template file
  39. */
  40. private $fileContents = '';
  41. /**
  42. * @desc unparsed blocks
  43. */
  44. private $blocks = array();
  45. /**
  46. * @desc parsed blocks
  47. */
  48. private $parsedBlocks = array();
  49. /**
  50. * @desc store sub-block names for fast resetting
  51. */
  52. private $subBlocks = array();
  53. /**
  54. * @desc variables array
  55. */
  56. private $VARS = array();
  57. /**
  58. * auto-reset sub blocks
  59. */
  60. private $AUTORESET = true;
  61. /**
  62. * @desc what to assign to unassigned template variables. Defaults to ''.
  63. * Sometimes a null value is desired, but if you are parsing a table
  64. * and a null value populates a cell this can cause problems. In this case
  65. * setting $nullValue to &nbsp; might be a better idea.
  66. *
  67. * Note: Sometimes it may be desireable to set a null value temporarily.
  68. * To achieve this simply reset null values to ''.
  69. *
  70. * @var string $value
  71. * @example output/nullValue.html Resulting HTML after parsing
  72. * @example templates/nullValue.tpl HTML Template used for this example
  73. * @example nullValue.php Example usage of $nullValue
  74. */
  75. public $nullValue = '';
  76.  
  77. /**
  78. * @return object $XiTemplate
  79. * @param string $template
  80. * @desc XiTemplate constructor, loads the template text from file or buffer
  81. * and instantiates the XiTemplate object.
  82. * @example output/construct.html Resulting HTML after parsing
  83. * @example templates/construct.tpl HTML template used for this example
  84. * @example construct.php Example usage of __construct()
  85. */
  86. function __construct($template)
  87. {
  88. /*check to see if the template comes from the buffer*/
  89. /*by looking for "<!-- BEGIN tags"*/
  90. if (preg_match('/\<!--\sBEGIN/', $template))
  91. $this->fileContents = $template;
  92. else
  93. $this->_recursiveReadFile($template);
  94. $this->_makeTree();
  95. }
  96.  
  97. /******************************************************************************/
  98.  
  99. /* private methods */
  100. /******************************************************************************/
  101.  
  102.  
  103. /**
  104. * @return void
  105. * @param string $msg
  106. * @desc Issues a warning via trigger_error()
  107. */
  108. private function logWarning($msg)
  109. {
  110. trigger_error($msg, E_USER_WARNING);
  111. }
  112. /**
  113. * @return void
  114. * @param string $msg
  115. * @desc Issues a fatal error via trigger_error()
  116. */
  117. private function logError($msg)
  118. {
  119. trigger_error($msg, E_USER_ERROR);
  120. exit;
  121. }
  122. /**
  123. * @return string $fileText
  124. * @param string $fileName
  125. * @desc Read the contents of $fileName.
  126. */
  127. private function _readFile($fileName)
  128. {
  129. if (!is_file($fileName))
  130. $this->logError($fileName . ' does not exist.');
  131. if (($fileText = file_get_contents($fileName)) === false)
  132. $this->logError($fileName . ' is not readable.');
  133. return($fileText);
  134. }
  135. /**
  136. * @return void
  137. * @param string $fileName
  138. * @desc Read the contents of $fileName in a recursive manner such that
  139. * FILE blocks are also included.
  140. */
  141. private function _recursiveReadFile($fileName)
  142. {
  143. /*Read main file contents*/
  144. $this->fileContents = $this->_readFile($fileName);
  145. $matches = array();
  146. /*Read FILE: includes*/
  147. while (preg_match('/\{FILE\s*\"([^\"]+)\"\s*\}/m', $this->fileContents, $matches))
  148. {
  149. $includedFile = $this->_readFile($matches[1]);
  150. $this->fileContents = preg_replace('\'' . preg_quote($matches[0]) . '\'',
  151. $includedFile, $this->fileContents);
  152. }
  153. }
  154.  
  155. /**
  156. * @return void
  157. * @desc Parse all the blocks out of $this->fileContents.
  158. */
  159. private function _makeTree()
  160. {
  161. /*Initialize variables.*/
  162. $level = 0;
  163. $blockNames = array();
  164. $matches = array();
  165. /*Find all the delimiters*/
  166. $delimiters = explode('<!-- ', $this->fileContents);
  167. /*Loop through checking for begining or ending delimiter and manipulate*/
  168. /*the tree as needed.*/
  169. foreach($delimiters as $v)
  170. {
  171. if (preg_match_all('/^(BEGIN:|END:)\s*(\w+)\s*-->(.*)/ims', $v, $matches, PREG_SET_ORDER))
  172. {
  173. /* $matches[0][1] = BEGIN or END*/
  174. /* $matches[0][2] = block name*/
  175. /* $matches[0][3] = kinda content*/
  176. if ($matches[0][1] == 'BEGIN:')
  177. {
  178. /*If we have a BEGIN: block, add it to blocks list.*/
  179. $parentName = implode('.', $blockNames);
  180. $blockNames[++$level] = $matches[0][2];
  181. $currentBlockName = implode('.', $blockNames);
  182. $this->blocks[$currentBlockName] = isset($this->blocks[$currentBlockName]) ?
  183. $this->blocks[$currentBlockName] . $matches[0][3] :
  184. $matches[0][3];
  185. $this->blocks[$parentName] .= '{_BLOCK_.' . $currentBlockName . '}';
  186. $this->subBlocks[$parentName][] = $currentBlockName;
  187. $this->subBlocks[$currentBlockName][] = "";
  188. }
  189. elseif ($matches[0][1] == 'END:' )
  190. {
  191. /*If we have an END block, reduce our parent list.*/
  192. unset($blockNames[$level--]);
  193. $parentName = implode('.', $blockNames);
  194. /*Add rest of block to parent block*/
  195. $this->blocks[$parentName] .= $matches[0][3];
  196. }
  197. }
  198. else
  199. {
  200. $index = implode('.', $blockNames);
  201. $this->blocks[$index] = (isset($this->blocks[$index])) ?
  202. ($this->blocks[$index] . '<!-- ' . $v) : '<!-- ' . $v;
  203. }
  204. }
  205. }
  206. /**
  207. * @return void
  208. * @param array $array
  209. * @param string $templateVariable
  210. * @desc Integrate an array, regardless of dimension, into the VARS array.
  211. */
  212. private function _assignArray($array, $templateVariable)
  213. {
  214. /*Recursively reduce the array until we don't have an array as the value,*/
  215. /*then store the path of the array key to the value.*/
  216. if (is_array($array))
  217. {
  218. foreach($array as $k=>$v)
  219. $this->_assignArray($v, $templateVariable. '.' . $k);
  220. }
  221. else
  222. {
  223. $this->VARS[$templateVariable] = $array;
  224. }
  225. }
  226.  
  227.  
  228. /******************************************************************************/
  229.  
  230. /* public methods */
  231. /******************************************************************************/
  232.  
  233.  
  234. /**
  235. * @return void
  236. * @param string $templateVariable
  237. * @param mixed $value
  238. * @desc Assign a value to a template variable. $value can be either a
  239. * string or a single or multidimensional array.
  240. * @example output/assign.html Resulting HTML after parsing
  241. * @example templates/assign.tpl HTML Template used for this example
  242. * @example assign.php Example usage of assign()
  243. */
  244. public function assign($templateVariable, $value='')
  245. {
  246. /*If assigning an array, use special function to*/
  247. /*allow multidimensional arrays.*/
  248. if (is_array($value))
  249. $this->_assignArray($value, $templateVariable);
  250. /*Otherwise, just stick it in the list.*/
  251. else
  252. $this->VARS[$templateVariable] = $value;
  253. }
  254. /**
  255. * @return void
  256. * @param string $blockName
  257. * @desc Parse a block of the template replacing parsed blocks and variables.
  258. * @example output/parse.html Resulting HTML after parsing
  259. * @example templates/parse.tpl HTML template used in this example
  260. * @example parse.php Example usage of parse()
  261. */
  262. public function parse($blockName='main')
  263. {
  264. if (!isset($this->blocks[$blockName]))
  265. {
  266. $this->logError('Template::parse() - block [' .
  267. $blockName . '] does not exist.');
  268. }
  269.  
  270. /*Save a copy of the old block so that it can be appended to.*/
  271. $blockCopy = $this->blocks[$blockName];
  272. /*Find all the variables in this block.*/
  273. $varArray = array();
  274. preg_match_all('/\{([A-Za-z0-9\._]+?)}/',
  275. $this->blocks[$blockName], $varArray);
  276. $varArray = $varArray[1];
  277. /*For each variable, determine if it represents a block or an assigned var, then*/
  278. /*replace it accordingly.*/
  279. foreach($varArray as $v)
  280. {
  281. if (strncmp($v, '_BLOCK_', 7) == 0)
  282. {
  283. /*We are dealing with a parsed block.*/
  284. $parsedBlockName = substr($v, 8);
  285. /*If it has been parsed, replace it with the parsed text, else leave it blank.*/
  286. $var = (isset($this->parsedBlocks[$parsedBlockName])) ?
  287. trim(($this->parsedBlocks[$parsedBlockName])) : '';
  288. /*str_replace is faster and fixes the old Xtemplate US$ bug #440545*/
  289. $blockCopy = str_replace('{' . $v . '}', $var, $blockCopy);
  290. }
  291. else
  292. {
  293. /*If variable has been assigned, replace it, else assign it*/
  294. /*our default $nullValue.*/
  295. $var = (isset($this->VARS[$v]) && !empty($this->VARS[$v])) ?
  296. $this->VARS[$v] : $this->nullValue;
  297. /*str_replace is faster and fixes the old Xtemplate US$ bug #440545*/
  298. $blockCopy = str_replace('{' . $v . '}', $var, $blockCopy);
  299. }
  300. }
  301. /*Replace the old parsed block with itself plus the new data.*/
  302. $this->parsedBlocks[$blockName] = (isset($this->parsedBlocks[$blockName])) ?
  303. $this->parsedBlocks[$blockName] . $blockCopy : $blockCopy;
  304. /*reset sub-blocks*/
  305. if ($this->AUTORESET && (!empty($this->subBlocks[$blockName])))
  306. {
  307. reset($this->subBlocks[$blockName]);
  308. foreach($this->subBlocks[$blockName] as $subBlock)
  309. $this->reset($subBlock);
  310. }
  311. }
  312.  
  313. /**
  314. * @return void
  315. * @param string $blockName
  316. * @desc Parse a block of the template and all sub-blocks under it.
  317. * @example output/rparse.html Resulting HTML after parsing
  318. * @example templates/rparse.tpl HTML template used in this example
  319. * @example rparse.php Example usage of rparse()
  320. */
  321. public function rparse($blockName='main')
  322. {
  323. if (!empty($blockName))
  324. {
  325. reset($this->subBlocks[$blockName]);
  326. foreach($this->subBlocks[$blockName] as $block)
  327. if (!empty($block)) $this->rparse($block);
  328. }
  329. $this->parse($blockName);
  330. }
  331.  
  332. /**
  333. * @return void
  334. * @param string $blockName
  335. * @desc Resets a parsed block to empty.
  336. */
  337. public function reset($blockName)
  338. {
  339. if (!isset($this->parsedBlocks[$blockName]))
  340. return;
  341. $this->parsedBlocks[$blockName] = '';
  342. }
  343. /**
  344. * @return string parsedBlock
  345. * @param string $blockName
  346. * @desc Returns parsed block of template.
  347. */
  348. public function text($blockName='main')
  349. {
  350. if (sizeof($this->parsedBlocks) == 0)
  351. $this->logError('Cannot get template content,
  352. main block has yet to be parsed');
  353. if (!isset($this->parsedBlocks[$blockName]))
  354. $this->logError('Block: "'. $blockName .'" does not exist');
  355. return($this->parsedBlocks[$blockName]);
  356. }
  357. /**
  358. * @return void
  359. * @param string $blockName
  360. * @desc Outputs a parsed block of a template to the browser.
  361. * Will generate a fatal error if $blockName does not exist in the
  362. * template instance.
  363. * @example output/out.html Resulting HTML after parsing
  364. * @example templates/out.tpl HTML template used in this example
  365. * @example out.php Example usage of out()
  366. */
  367. public function out($blockName='main')
  368. {
  369. echo($this->text($blockName));
  370. }
  371. }
  372. ?>

Documentation generated on Fri, 20 Aug 2004 10:57:43 -0500 by phpDocumentor 1.3.0RC3