PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/pattemplate/patTemplate/Compiler.php

https://gitlab.com/endomorphosis/greenrenaissancejoomla
PHP | 485 lines | 227 code | 58 blank | 200 comment | 16 complexity | b05ed74e393daab17455807d9e7f4bf8 MD5 | raw file
  1. <?PHP
  2. /**
  3. * Compiler for patTemplate
  4. *
  5. * $Id: Compiler.php 10094 2008-03-02 04:35:10Z instance $
  6. *
  7. * WARNING: This is still experimental!
  8. *
  9. * @package patTemplate
  10. * @subpackage Compiler
  11. * @author Stephan Schmidt <schst@php.net>
  12. */
  13. // Check to ensure this file is within the rest of the framework
  14. defined('JPATH_BASE') or die();
  15. /**
  16. * Compiler for patTemplate
  17. *
  18. * $Id: Compiler.php 10094 2008-03-02 04:35:10Z instance $
  19. *
  20. * WARNING: This is still experimental!
  21. *
  22. * @package patTemplate
  23. * @subpackage Compiler
  24. * @author Stephan Schmidt <schst@php.net>
  25. *
  26. * @todo implement all template types
  27. * @todo implement variable modifiers
  28. * @todo implement getParsedTemplate
  29. * @todo check for existing compiled template
  30. */
  31. class patTemplate_Compiler extends patTemplate
  32. {
  33. /**
  34. * list of all templates that already have been compiled
  35. *
  36. * @access private
  37. * @var array()
  38. */
  39. var $_compiledTemplates = array();
  40. /**
  41. * file pointer to the compiled template
  42. *
  43. * @access private
  44. * @var resource
  45. */
  46. var $_fp;
  47. /**
  48. * constructor
  49. *
  50. * Creates a new patTemplate Compiler
  51. *
  52. * @access public
  53. * @param string type of the templates, either 'html' or 'tex'
  54. */
  55. function patTemplate_Compiler( $type = 'html' )
  56. {
  57. $GLOBALS['patTemplate_Compiler'] = &$this;
  58. patTemplate::patTemplate( $type );
  59. }
  60. /**
  61. * compile the currently loaded templates
  62. *
  63. * @access public
  64. * @param string name of the input (filename, shm segment, etc.)
  65. */
  66. function compile( $compileName = null )
  67. {
  68. $this->_varRegexp = '/'.$this->_startTag.'([^a-z:]+)'.$this->_endTag.'/U';
  69. $this->_depRegexp = '/'.$this->_startTag.'TMPL:([^a-z:]+)'.$this->_endTag.'/U';
  70. $compileFolder = $this->getOption( 'compileFolder' );
  71. $compileFile = sprintf( '%s/%s', $compileFolder, $compileName );
  72. $this->_fp = fopen( $compileFile, 'w' );
  73. $this->_addToCode( '<?PHP' );
  74. $this->_addToCode( '/**' );
  75. $this->_addToCode( ' * compiled patTemplate file' );
  76. $this->_addToCode( ' *' );
  77. $this->_addToCode( ' * compiled on '. date( 'Y-m-d H:i:s' ) );
  78. $this->_addToCode( ' */' );
  79. $this->_addToCode( 'class compiledTemplate {' );
  80. foreach( $this->_templates as $template => $spec )
  81. {
  82. $this->compileTemplate( $template );
  83. }
  84. $this->_addToCode( '}' );
  85. $this->_addToCode( '?>' );
  86. fclose( $this->_fp );
  87. include_once $compileFile;
  88. return true;
  89. }
  90. /**
  91. * compile a template
  92. *
  93. * @access public
  94. * @param string name of the template
  95. */
  96. function compileTemplate( $template )
  97. {
  98. $name = strtolower( $template );
  99. if( !isset( $this->_templates[$template] ) )
  100. {
  101. return patErrorManager::raiseWarning(
  102. PATTEMPLATE_WARNING_NO_TEMPLATE,
  103. "Template '$name' does not exist."
  104. );
  105. }
  106. /**
  107. * check, if the template has been loaded
  108. * and load it if necessary.
  109. */
  110. if( $this->_templates[$template]['loaded'] !== true )
  111. {
  112. if( $this->_templates[$template]['attributes']['parse'] == 'on' )
  113. {
  114. $result = $this->readTemplatesFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], null, $template );
  115. }
  116. else
  117. {
  118. $result = $this->loadTemplateFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], $template );
  119. }
  120. if( patErrorManager::isError( $result ) )
  121. {
  122. return $result;
  123. }
  124. }
  125. $this->_addToCode( '' );
  126. $this->_addToCode( '/**' );
  127. $this->_addToCode( ' * Compiled version of '.$template );
  128. $this->_addToCode( ' *' );
  129. $this->_addToCode( ' * Template type is '.$this->_templates[$template]['attributes']['type'] );
  130. $this->_addToCode( ' */' );
  131. /**
  132. * start the output
  133. */
  134. $this->_addToCode( 'function '.$template.'()' );
  135. $this->_addToCode( '{' );
  136. $this->_addToCode( '$this->_prepareCompiledTemplate( "'.$template.'" );', 1 );
  137. $this->_addToCode( '$this->prepareTemplate( "'.$template.'" );', 1 );
  138. /**
  139. * attributes
  140. */
  141. $this->_addToCode( '$this->_templates["'.$template.'"]["attributes"] = unserialize( \''.serialize($this->_templates[$template]['attributes']).'\' );', 1, 'Read the attributes' );
  142. /**
  143. * copyVars
  144. */
  145. $this->_addToCode( '$this->_templates["'.$template.'"]["copyVars"] = unserialize( \''.serialize($this->_templates[$template]['copyVars']).'\' );', 1, 'Read the copyVars' );
  146. /**
  147. * check visibility
  148. */
  149. $this->_addToCode( 'if( $this->_templates["'.$template.'"]["attributes"]["visibility"] != "hidden" ) {', 1, 'Check, whether template is hidden' );
  150. /**
  151. * autoloop the template
  152. */
  153. $this->_addToCode( '$this->_templates["'.$template.'"]["iteration"] = 0;', 2, 'Reset the iteration' );
  154. $this->_addToCode( '$loop = count( $this->_vars["'.$template.'"]["rows"] );', 2, 'Get the amount of loops' );
  155. $this->_addToCode( '$loop = max( $loop, 1 );', 2 );
  156. $this->_addToCode( '$this->_templates["'.$template.'"]["loop"] = $loop;', 2 );
  157. $this->_addToCode( 'for( $i = 0; $i < $loop; $i++ ) {', 2, 'Traverse all variables.' );
  158. /**
  159. * fetch the variables
  160. */
  161. $this->_addToCode( 'unset( $this->_templates["'.$template.'"]["vars"] );', 3 );
  162. $this->_addToCode( '$this->_fetchVariables("'.$template.'");', 3 );
  163. /**
  164. * different templates have to be compiled differently
  165. */
  166. switch( $this->_templates[$template]['attributes']['type'] )
  167. {
  168. /**
  169. * modulo template
  170. */
  171. case 'modulo':
  172. $this->_compileModuloTemplate( $template );
  173. break;
  174. /**
  175. * simple condition template
  176. */
  177. case 'simplecondition':
  178. $this->_compileSimpleConditionTemplate( $template );
  179. break;
  180. /**
  181. * condition template
  182. */
  183. case 'condition':
  184. $this->_compileConditionTemplate( $template );
  185. break;
  186. /**
  187. * standard template
  188. */
  189. default:
  190. $this->_compileStandardTemplate( $template );
  191. break;
  192. }
  193. $this->_addToCode( '$this->_templates["'.$template.'"]["iteration"]++;', 3 );
  194. $this->_addToCode( '}', 2 );
  195. $this->_addToCode( '}', 1 );
  196. $this->_addToCode( '}' );
  197. /**
  198. * remember this template
  199. */
  200. array_push( $this->_compiledTemplates, $template );
  201. }
  202. /**
  203. * compile a standard template
  204. *
  205. * @access private
  206. * @param string name of the template
  207. */
  208. function _compileStandardTemplate( $template )
  209. {
  210. $content = $this->_templateToPHP( $this->_templates[$template]['content'], $template );
  211. $this->_addToCode( $content );
  212. return true;
  213. }
  214. /**
  215. * compile a modulo template
  216. *
  217. * A modulo template will be compiled into a switch/case
  218. * statement.
  219. *
  220. * @access private
  221. * @param string name of the template
  222. * @todo check special conditions (__first, __last, __default)
  223. */
  224. function _compileModuloTemplate( $template )
  225. {
  226. $this->_compileBuiltinConditions( $template );
  227. $this->_addToCode( 'if( !$_displayed ) {', 3, 'Builtin condition has been displayed?' );
  228. /**
  229. * build switch statement
  230. */
  231. $this->_addToCode( 'switch( ( $this->_templates["'.$template.'"]["iteration"] + 1 ) % '.$this->_templates[$template]['attributes']['modulo'].' ) {', 4 );
  232. foreach( $this->_templates[$template]['subtemplates'] as $condition => $spec )
  233. {
  234. $this->_addToCode( 'case "'.$condition.'":', 5 );
  235. $content = $this->_templateToPHP( $spec['data'], $template );
  236. $this->_addToCode( $content );
  237. $this->_addToCode( 'break;', 6 );
  238. }
  239. $this->_addToCode( '}', 4 );
  240. $this->_addToCode( '}', 3 );
  241. return true;
  242. }
  243. /**
  244. * compile a simpleCondition template
  245. *
  246. * A simpleCondition template will be compiled into an 'if'
  247. * statement.
  248. *
  249. * @access private
  250. * @param string name of the template
  251. */
  252. function _compileSimpleConditionTemplate( $template )
  253. {
  254. $conditions = array();
  255. foreach( $this->_templates[$template]['attributes']['requiredvars'] as $var )
  256. {
  257. array_push( $conditions, 'isset( $this->_templates["'.$template.'"]["vars"]["'.$var.'"] )' );
  258. }
  259. /**
  260. * build switch statement
  261. */
  262. $this->_addToCode( 'if( '.implode( ' && ', $conditions ).' ) {', 3, 'Check for required variables' );
  263. $content = $this->_templateToPHP( $this->_templates[$template]['content'], $template );
  264. $this->_addToCode( $content );
  265. $this->_addToCode( '}', 3 );
  266. return true;
  267. }
  268. /**
  269. * compile a condition template
  270. *
  271. * A condition template will be compiled into an 'switch/case'
  272. * statement.
  273. *
  274. * @access private
  275. * @param string name of the template
  276. */
  277. function _compileConditionTemplate( $template )
  278. {
  279. /**
  280. * __first, __last
  281. */
  282. $this->_compileBuiltinConditions( $template );
  283. $this->_addToCode( 'if( !$_displayed ) {', 3, 'Builtin condition has been displayed?' );
  284. /**
  285. * build switch statement
  286. */
  287. $this->_addToCode( 'switch( $this->_templates["'.$template.'"]["vars"]["'.$this->_templates[$template]["attributes"]["conditionvar"].'"] ) {', 4 );
  288. foreach( $this->_templates[$template]['subtemplates'] as $condition => $spec )
  289. {
  290. if( $condition == '__default' )
  291. {
  292. $this->_addToCode( 'default:', 5 );
  293. }
  294. else
  295. {
  296. $this->_addToCode( 'case "'.$condition.'":', 5 );
  297. }
  298. $content = $this->_templateToPHP( $spec['data'], $template );
  299. $this->_addToCode( $content );
  300. $this->_addToCode( 'break;', 6 );
  301. }
  302. $this->_addToCode( '}', 4 );
  303. $this->_addToCode( '}', 3 );
  304. return true;
  305. }
  306. /**
  307. * compile built-in conditions
  308. *
  309. * This will create the neccessary PHP code for:
  310. * - __first
  311. * - __last
  312. *
  313. * @access private
  314. * @param string template name
  315. */
  316. function _compileBuiltinConditions( $template )
  317. {
  318. $this->_addToCode( '$_displayed = false;', 3 );
  319. if( isset( $this->_templates[$template]['subtemplates']['__first'] ) )
  320. {
  321. $this->_addToCode( 'if( $this->_templates["'.$template.'"]["iteration"] == 0 ) {', 3, 'Check for first entry' );
  322. $content = $this->_templateToPHP( $this->_templates[$template]['subtemplates']['__first']['data'], $template );
  323. $this->_addToCode( $content );
  324. $this->_addToCode( '$_displayed = true;', 4 );
  325. $this->_addToCode( '}', 3 );
  326. }
  327. if( isset( $this->_templates[$template]['subtemplates']['__last'] ) )
  328. {
  329. $this->_addToCode( 'if( $this->_templates["'.$template.'"]["iteration"] == ($this->_templates["'.$template.'"]["loop"]-1) ) {', 3, 'Check for last entry' );
  330. $content = $this->_templateToPHP( $this->_templates[$template]['subtemplates']['__last']['data'], $template );
  331. $this->_addToCode( $content );
  332. $this->_addToCode( '$_displayed = true;', 4 );
  333. $this->_addToCode( '}', 3 );
  334. }
  335. }
  336. /**
  337. * build PHP code from a template
  338. *
  339. * This will replace the variables in a template with
  340. * PHP Code.
  341. *
  342. * @access private
  343. * @param string template content
  344. * @param string name of the template
  345. * @return string PHP code
  346. */
  347. function _templateToPHP( $content, $template )
  348. {
  349. $content = preg_replace( $this->_varRegexp, '<?PHP echo $this->_getVar( "'.$template.'", "$1"); ?>', $content );
  350. $content = preg_replace( $this->_depRegexp, '<?PHP compiledTemplate::$1(); ?>', $content );
  351. $content = '?>'.$content.'<?PHP';
  352. return $content;
  353. }
  354. /**
  355. * display the compiled template
  356. *
  357. * This is a replacement for patTemplate::displayParsedTemplate.
  358. *
  359. * @access public
  360. * @param string name of the template to display
  361. */
  362. function displayParsedTemplate( $name = null )
  363. {
  364. if( is_null( $name ) )
  365. $name = $this->_root;
  366. $name = strtolower( $name );
  367. if( !is_callable( 'compiledTemplate', $name ) )
  368. {
  369. jexit( 'Unknown template' );
  370. }
  371. compiledTemplate::$name();
  372. }
  373. /**
  374. * add a line to the compiled code
  375. *
  376. * @access public
  377. * @param string line to add
  378. * @param integer indentation
  379. * @return void
  380. */
  381. function _addToCode( $line, $indent = 0, $comment = null )
  382. {
  383. if( !is_null( $comment ) )
  384. {
  385. fputs( $this->_fp, "\n" );
  386. if( $indent > 0 )
  387. fputs( $this->_fp, str_repeat( "\t", $indent ) );
  388. fputs( $this->_fp, "/* $comment */\n" );
  389. }
  390. if( $indent > 0 )
  391. fputs( $this->_fp, str_repeat( "\t", $indent ) );
  392. fputs( $this->_fp, $line."\n" );
  393. }
  394. /**
  395. * function, used by the compiler to get a value of a variable
  396. *
  397. * Checks, whether the value is locally or globally set
  398. *
  399. * @access private
  400. * @param string template
  401. * @param string variable name
  402. *
  403. * @todo check for 'unusedvars' attribute
  404. */
  405. function _getVar( $template, $varname )
  406. {
  407. if( isset( $this->_templates[$template]['vars'][$varname] ) )
  408. return $this->_templates[$template]['vars'][$varname];
  409. if( isset( $this->_globals[$this->_startTag.$varname.$this->_endTag] ) )
  410. return $this->_globals[$this->_startTag.$varname.$this->_endTag];
  411. return '';
  412. }
  413. /**
  414. * prepare a template for the compiler
  415. *
  416. * @access private
  417. * @param string template name
  418. */
  419. function _prepareCompiledTemplate( $template )
  420. {
  421. $this->_templates[$template] = array(
  422. 'attributes' => array(),
  423. 'copyVars' => array(),
  424. );
  425. }
  426. }
  427. ?>