PageRenderTime 65ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/includes/patTemplate/patTemplate.php

https://bitbucket.org/dgough/annamaria-daneswood-25102012
PHP | 2705 lines | 1426 code | 292 blank | 987 comment | 275 complexity | ebc942aece73ba3dea10a23e77542987 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?PHP
  2. /**
  3. * patTemplate
  4. *
  5. * $Id: patTemplate.php 1544 2005-12-23 07:01:01Z eddieajau $
  6. *
  7. * powerful templating engine
  8. *
  9. * @version 3.1.0
  10. * @package patTemplate
  11. * @author Stephan Schmidt <schst@php.net>
  12. * @license LGPL
  13. * @link http://www.php-tools.net
  14. */
  15. // ** Following line Joomla! specific **
  16. require_once( dirname( __FILE__ ) . '/patErrorManager.php' );
  17. /**
  18. * template already exists
  19. */
  20. define( 'PATTEMPLATE_ERROR_TEMPLATE_EXISTS', 5010 );
  21. /**
  22. * template does not exist
  23. */
  24. define ( 'PATTEMPLATE_WARNING_NO_TEMPLATE', 5011 );
  25. /**
  26. * unknown type
  27. */
  28. define ( 'PATTEMPLATE_WARNING_UNKNOWN_TYPE', 5012 );
  29. /**
  30. * base class for module could not be found
  31. */
  32. define( 'PATTEMPLATE_ERROR_BASECLASS_NOT_FOUND', 5050 );
  33. /**
  34. * module could not be found
  35. */
  36. define( 'PATTEMPLATE_ERROR_MODULE_NOT_FOUND', 5051 );
  37. /**
  38. * array expected
  39. */
  40. define( 'PATTEMPLATE_ERROR_EXPECTED_ARRAY', 5052 );
  41. /**
  42. * No input
  43. */
  44. define( 'PATTEMPLATE_ERROR_NO_INPUT', 6000 );
  45. /**
  46. * Recursion
  47. */
  48. define( 'PATTEMPLATE_ERROR_RECURSION', 6010 );
  49. /**
  50. * patTemplate
  51. *
  52. * powerful templating engine
  53. *
  54. * @version 3.1.0
  55. * @package patTemplate
  56. * @author Stephan Schmidt <schst@php.net>
  57. * @license LGPL
  58. * @link http://www.php-tools.net
  59. */
  60. class patTemplate
  61. {
  62. /**
  63. * standard system vars that identify pat tools
  64. * @var array
  65. */
  66. var $_systemVars = array(
  67. 'appName' => 'patTemplate',
  68. 'appVersion' => '3.1.0',
  69. 'author' => array(
  70. 'Stephan Schmidt <schst@php.net>'
  71. )
  72. );
  73. /**
  74. * default attributes for new templates
  75. * @access private
  76. * @var array
  77. */
  78. var $_defaultAttributes = array(
  79. 'type' => 'standard',
  80. 'visibility' => 'visible',
  81. 'loop' => 1,
  82. 'unusedvars' => 'strip',
  83. 'whitespace' => 'keep',
  84. 'autoclear' => 'off',
  85. 'autoload' => 'on'
  86. );
  87. /**
  88. * options for patTemplate
  89. *
  90. * Currently the following options are implemented:
  91. * - maintainBc defines, whether patTemplate should be backwards compatible.
  92. * This means, that you may use 'default' and 'empty' for subtemplates.
  93. *
  94. * @access private
  95. * @var array
  96. */
  97. var $_options = array(
  98. 'startTag' => '{',
  99. 'endTag' => '}',
  100. 'root' => array('__default' => '.'),
  101. 'namespace' => 'patTemplate',
  102. 'maintainBc' => true,
  103. 'defaultFunction' => false
  104. );
  105. /**
  106. * start tag
  107. *
  108. * @access private
  109. * @var string
  110. */
  111. var $_startTag = '{';
  112. /**
  113. * end tag
  114. *
  115. * @access private
  116. * @var string
  117. */
  118. var $_endTag = '}';
  119. /**
  120. * loaded modules
  121. *
  122. * Modules are:
  123. * - Readers
  124. * - Caches
  125. * - Variable modifiers
  126. * - Filters
  127. *
  128. * @access private
  129. * @var array
  130. */
  131. var $_modules = array();
  132. /**
  133. * directories, where modules can be stored
  134. * @access private
  135. * @var array
  136. */
  137. var $_moduleDirs = array();
  138. /**
  139. * stores all template names
  140. * @access private
  141. * @var array
  142. */
  143. var $_templateList = array();
  144. /**
  145. * stores all template data
  146. * @access private
  147. * @var array
  148. */
  149. var $_templates = array();
  150. /**
  151. * stores all global variables
  152. * @access private
  153. * @var array
  154. */
  155. var $_globals = array();
  156. /**
  157. * stores all local variables
  158. * @access private
  159. * @var array
  160. */
  161. var $_vars = array();
  162. /**
  163. * stores the name of the first template that has been
  164. * found
  165. *
  166. * @access private
  167. * @var string
  168. */
  169. var $_root;
  170. /**
  171. * output filters that should be used
  172. *
  173. * @access private
  174. * @var array
  175. */
  176. var $_outputFilters = array();
  177. /**
  178. * input filters that should be used
  179. *
  180. * @access private
  181. * @var array
  182. */
  183. var $_inputFilters = array();
  184. /**
  185. * template cache, that should be used
  186. *
  187. * @access private
  188. * @var array
  189. */
  190. var $_tmplCache = null;
  191. /**
  192. * placeholders, that have been discovered
  193. *
  194. * @access private
  195. * @var array
  196. */
  197. var $_discoveredPlaceholders = array();
  198. /**
  199. * Create a new patTemplate instance.
  200. *
  201. * The constructor accepts the type of the templates as sole parameter.
  202. * You may choose one of:
  203. * - html (default)
  204. * - tex
  205. *
  206. * The type influences the tags you are using in your templates.
  207. *
  208. * @access public
  209. * @param string type (either html or tex)
  210. */
  211. function patTemplate( $type = 'html' )
  212. {
  213. if( !defined( 'PATTEMPLATE_INCLUDE_PATH' ) ) {
  214. define( 'PATTEMPLATE_INCLUDE_PATH', dirname( __FILE__ ) . '/patTemplate' );
  215. }
  216. $this->setType( $type );
  217. }
  218. /**
  219. * sets an option
  220. *
  221. * Currently, the following options are supported
  222. * - maintainBc (true|false)
  223. * - namespace (string)
  224. *
  225. * @access public
  226. * @param string option to set
  227. * @param string value of the option
  228. */
  229. function setOption($option, $value)
  230. {
  231. $this->_options[$option] = $value;
  232. }
  233. /**
  234. * gets an option
  235. *
  236. * @access public
  237. * @param string option to get
  238. * @return mixed value of the option
  239. */
  240. function getOption( $option )
  241. {
  242. if (!isset($this->_options[$option])) {
  243. return null;
  244. }
  245. return $this->_options[$option];
  246. }
  247. /**
  248. * sets name of directory where templates are stored
  249. *
  250. * @access public
  251. * @param string dir where templates are stored
  252. * @deprecated please use patTemplate::setRoot() instead
  253. */
  254. function setBasedir($basedir)
  255. {
  256. $this->setRoot($basedir);
  257. }
  258. /**
  259. * sets root base for the template
  260. *
  261. * The parameter depends on the reader you are using.
  262. *
  263. * @access public
  264. * @param string root base of the templates
  265. */
  266. function setRoot($root, $reader = '__default')
  267. {
  268. $this->_options['root'][$reader] = $root;
  269. }
  270. /**
  271. * gets name of root base for the templates
  272. *
  273. * @access public
  274. * @return mixed root base
  275. */
  276. function getRoot($reader = '__default')
  277. {
  278. return $this->_options['root'][$reader];
  279. }
  280. /**
  281. * sets namespace of patTemplate tags
  282. *
  283. * If you want to use more than one namespace, you may set this to
  284. * an array. All tags in these namespaces will be treated as patTemplate
  285. * tags.
  286. *
  287. * @access public
  288. * @param string|array namespace(s)
  289. */
  290. function setNamespace($ns)
  291. {
  292. $this->_options['namespace'] = $ns;
  293. }
  294. /**
  295. * gets namespace of patTemplate tags
  296. *
  297. * @access public
  298. * @return string|array namespace(s)
  299. */
  300. function getNamespace()
  301. {
  302. return $this->_options['namespace'];
  303. }
  304. /**
  305. * set default attribute
  306. *
  307. * @access public
  308. * @param string attribute name
  309. * @param mixed attribute value
  310. */
  311. function setDefaultAttribute( $name, $value )
  312. {
  313. $this->_defaultAttributes[$name] = $value;
  314. }
  315. /**
  316. * set default attributes
  317. *
  318. * @access public
  319. * @param array attributes
  320. */
  321. function setDefaultAttributes( $attributes )
  322. {
  323. $this->_defaultAttributes = array_merge( $this->_defaultAttributes, $attributes );
  324. }
  325. /**
  326. * get default attributes
  327. *
  328. * @access public
  329. * @return return default attributes
  330. */
  331. function getDefaultAttributes()
  332. {
  333. return $this->_defaultAttributes;
  334. }
  335. /**
  336. * set the type for the templates
  337. *
  338. * @access public
  339. * @param string type (html or tex)
  340. * @return boolean true on success
  341. */
  342. function setType( $type )
  343. {
  344. switch( strtolower( $type ) )
  345. {
  346. case "tex":
  347. $this->setTags( '<{', '}>' );
  348. break;
  349. case "html":
  350. $this->setTags( '{', '}' );
  351. break;
  352. default:
  353. return patErrorManager::raiseWarning(
  354. PATTEMPLATE_WARNING_UNKNOWN_TYPE,
  355. "Unknown type '$type'. Please use 'html' or 'tex'."
  356. );
  357. }
  358. return true;
  359. }
  360. /**
  361. * set the start and end tag for variables
  362. *
  363. * @access public
  364. * @param string start tag
  365. * @param string end tag
  366. * @return boolean true on success
  367. */
  368. function setTags( $startTag, $endTag )
  369. {
  370. $this->_options['startTag'] = $startTag;
  371. $this->_options['endTag'] = $endTag;
  372. $this->_startTag = $startTag;
  373. $this->_endTag = $endTag;
  374. return true;
  375. }
  376. /**
  377. * get start tag for variables
  378. *
  379. * @access public
  380. * @return string start tag
  381. */
  382. function getStartTag()
  383. {
  384. return $this->_options['startTag'];
  385. }
  386. /**
  387. * get end tag for variables
  388. *
  389. * @access public
  390. * @return string end tag
  391. */
  392. function getEndTag()
  393. {
  394. return $this->_options['endTag'];
  395. }
  396. /**
  397. * add a directory where patTemplate should search for
  398. * modules.
  399. *
  400. * You may either pass a string or an array of directories.
  401. *
  402. * patTemplate will be searching for a module in the same
  403. * order you added them. If the module cannot be found in
  404. * the custom folders, it will look in
  405. * patTemplate/$moduleType.
  406. *
  407. * @access public
  408. * @param string module type
  409. * @param string|array directory or directories to search.
  410. */
  411. function addModuleDir( $moduleType, $dir )
  412. {
  413. if( !isset( $this->_moduleDirs[$moduleType] ) )
  414. $this->_moduleDirs[$moduleType] = array();
  415. if( is_array( $dir ) )
  416. $this->_moduleDirs[$moduleType] = array_merge( $this->_moduleDirs[$moduleType], $dir );
  417. else
  418. array_push( $this->_moduleDirs[$moduleType], $dir );
  419. }
  420. /**
  421. * Sets an attribute of a template
  422. *
  423. * supported attributes: visibilty, loop, parse, unusedvars
  424. *
  425. * @param string $template name of the template
  426. * @param string $attribute name of the attribute
  427. * @param mixed $value value of the attribute
  428. * @access public
  429. * @see setAttributes(),getAttribute(), clearAttribute()
  430. */
  431. function setAttribute( $template, $attribute, $value )
  432. {
  433. $template = strtolower( $template );
  434. if( !isset( $this->_templates[$template] ) )
  435. {
  436. return patErrorManager::raiseWarning(
  437. PATTEMPLATE_WARNING_NO_TEMPLATE,
  438. "Template '$template' does not exist."
  439. );
  440. }
  441. $attribute = strtolower( $attribute );
  442. $this->_templates[$template]['attributes'][$attribute] = $value;
  443. return true;
  444. }
  445. /**
  446. * Sets several attribute of a template
  447. *
  448. * $attributes has to be a assotiative arrays containing attribute/value pairs
  449. * supported attributes: visibilty, loop, parse, unusedvars
  450. *
  451. * @param string $template name of the template
  452. * @param array $attributes attribute/value pairs
  453. * @access public
  454. * @see setAttribute(), getAttribute(), clearAttribute()
  455. */
  456. function setAttributes( $template, $attributes )
  457. {
  458. if( !is_array( $attributes ) )
  459. {
  460. return patErrorManager::raiseError( PATTEMPLATE_ERROR_EXPECTED_ARRAY, 'patTemplate::setAttributes: Expected array as second parameter, '.gettype( $attributes ).' given' );
  461. }
  462. $template = strtolower( $template );
  463. $attributes = array_change_key_case( $attributes );
  464. if( !isset( $this->_templates[$template] ) )
  465. {
  466. return patErrorManager::raiseWarning(
  467. PATTEMPLATE_WARNING_NO_TEMPLATE,
  468. "Template '$template' does not exist."
  469. );
  470. }
  471. $this->_templates[$template]['attributes'] = array_merge( $this->_templates[$template]['attributes'], $attributes );
  472. return true;
  473. }
  474. /**
  475. * Get all attributes of a template
  476. *
  477. * @param string name of the template
  478. * @return array attributes
  479. * @access public
  480. */
  481. function getAttributes( $template )
  482. {
  483. $template = strtolower( $template );
  484. if( !isset( $this->_templates[$template] ) )
  485. {
  486. return patErrorManager::raiseWarning(
  487. PATTEMPLATE_WARNING_NO_TEMPLATE,
  488. "Template '$template' does not exist."
  489. );
  490. }
  491. return $this->_templates[$template]['attributes'];
  492. }
  493. /**
  494. * Gets an attribute of a template
  495. *
  496. * supported attributes: visibilty, loop, parse, unusedvars
  497. *
  498. * @param string $template name of the template
  499. * @param string $attribute name of the attribute
  500. * @return mixed value of the attribute
  501. * @access public
  502. * @see setAttribute(), setAttributes(), clearAttribute()
  503. */
  504. function getAttribute( $template, $attribute )
  505. {
  506. $template = strtolower( $template );
  507. $attribute = strtolower( $attribute );
  508. if( !isset( $this->_templates[$template] ) )
  509. {
  510. return patErrorManager::raiseWarning(
  511. PATTEMPLATE_WARNING_NO_TEMPLATE,
  512. "Template '$template' does not exist."
  513. );
  514. }
  515. return $this->_templates[$template]['attributes'][$attribute];
  516. }
  517. /**
  518. * Clears an attribute of a template
  519. *
  520. * supported attributes: visibilty, loop, parse, unusedvars
  521. *
  522. * @param string $template name of the template
  523. * @param string $attribute name of the attribute
  524. * @access public
  525. * @see setAttribute(), setAttributes(), getAttribute()
  526. */
  527. function clearAttribute( $template, $attribute )
  528. {
  529. $template = strtolower( $template );
  530. $attribute = strtolower( $attribute );
  531. if( !isset( $this->_templates[$template] ) )
  532. {
  533. return patErrorManager::raiseWarning(
  534. PATTEMPLATE_WARNING_NO_TEMPLATE,
  535. "Template '$template' does not exist."
  536. );
  537. }
  538. $this->_templates[$template]['attributes'][$attribute] = '';;
  539. return true;
  540. }
  541. /**
  542. * Prepare a template
  543. *
  544. * This can be used if you want to add variables to
  545. * a template, that has not been loaded yet.
  546. *
  547. * @access public
  548. * @param string template name
  549. */
  550. function prepareTemplate( $name )
  551. {
  552. $name = strtolower( $name );
  553. if( !isset( $this->_vars[$name] ) )
  554. {
  555. $this->_vars[$name] = array(
  556. 'scalar' => array(),
  557. 'rows' => array()
  558. );
  559. }
  560. }
  561. /**
  562. * add a variable to a template
  563. *
  564. * A variable may also be an indexed array, but _not_
  565. * an associative array!
  566. *
  567. * @access public
  568. * @param string $template name of the template
  569. * @param string $varname name of the variable
  570. * @param mixed $value value of the variable
  571. */
  572. function addVar( $template, $varname, $value )
  573. {
  574. $template = strtolower( $template );
  575. $varname = strtoupper( $varname );
  576. if( !is_array( $value ) ) {
  577. $this->_vars[$template]['scalar'][$varname] = $value;
  578. return true;
  579. }
  580. $cnt = count( $value );
  581. for ($i = 0; $i < $cnt; $i++) {
  582. if (!isset( $this->_vars[$template]['rows'][$i] )) {
  583. $this->_vars[$template]['rows'][$i] = array();
  584. }
  585. $this->_vars[$template]['rows'][$i][$varname] = $value[$i];
  586. }
  587. return true;
  588. }
  589. /**
  590. * get the value of a variable
  591. *
  592. * @access public
  593. * @param string name of the template
  594. * @param string name of the variable
  595. * @return string value of the variable, null if the variable is not set
  596. */
  597. function getVar( $template, $varname )
  598. {
  599. $template = strtolower( $template );
  600. $varname = strtoupper( $varname );
  601. if( isset( $this->_vars[$template]['scalar'][$varname] ) )
  602. return $this->_vars[$template]['scalar'][$varname];
  603. $value = array();
  604. $cnt = count( $this->_vars[$template]['rows'] );
  605. for( $i = 0; $i < $cnt; $i++ )
  606. {
  607. if( !isset( $this->_vars[$template]['rows'][$i][$varname] ) )
  608. continue;
  609. array_push( $value, $this->_vars[$template]['rows'][$i][$varname] );
  610. }
  611. if( !empty( $value ) )
  612. return $value;
  613. return null;
  614. }
  615. /**
  616. * clear the value of a variable
  617. *
  618. * @access public
  619. * @param string name of the template
  620. * @param string name of the variable
  621. * @return boolean
  622. * @see clearVars(), clearTemplate()
  623. */
  624. function clearVar( $template, $varname )
  625. {
  626. $template = strtolower( $template );
  627. $varname = strtoupper( $varname );
  628. if (isset( $this->_vars[$template]['scalar'][$varname] )) {
  629. unset ($this->_vars[$template]['scalar'][$varname]);
  630. return true;
  631. }
  632. $result = false;
  633. $cnt = count( $this->_vars[$template]['rows'] );
  634. for ($i = 0; $i < $cnt; $i++) {
  635. if (!isset($this->_vars[$template]['rows'][$i][$varname])) {
  636. continue;
  637. }
  638. unset($this->_vars[$template]['rows'][$i][$varname]);
  639. $result = true;
  640. }
  641. return $result;
  642. }
  643. /**
  644. * Adds several variables to a template
  645. *
  646. * Each Template can have an unlimited amount of its own variables
  647. * $variables has to be an assotiative array containing variable/value pairs
  648. *
  649. * @param string $template name of the template
  650. * @param array $variables assotiative array of the variables
  651. * @param string $prefix prefix for all variable names
  652. * @access public
  653. * @see addVar(), addRows(), addGlobalVar(), addGlobalVars()
  654. */
  655. function addVars( $template, $variables, $prefix = '' )
  656. {
  657. $template = strtolower( $template );
  658. $prefix = strtoupper( $prefix );
  659. $variables = array_change_key_case( $variables, CASE_UPPER );
  660. foreach ($variables as $varname => $value) {
  661. $varname = $prefix.$varname;
  662. if (!is_array($value)) {
  663. if (!is_scalar($value)) {
  664. continue;
  665. }
  666. $this->_vars[$template]['scalar'][$varname] = $value;
  667. continue;
  668. }
  669. $cnt = count( $value );
  670. for( $i = 0; $i < $cnt; $i++ ) {
  671. if( !isset( $this->_vars[$template]['rows'][$i] ) )
  672. $this->_vars[$template]['rows'][$i] = array();
  673. $this->_vars[$template]['rows'][$i][$varname] = $value[$i];
  674. }
  675. }
  676. }
  677. /**
  678. * Clear all variables in a template
  679. *
  680. * This clears only variables, but does
  681. *
  682. * @access public
  683. * @param string $template name of the template
  684. * @return boolean
  685. * @see clearVar(), clearTemplate()
  686. */
  687. function clearVars( $template )
  688. {
  689. $template = strtolower($template);
  690. $this->_vars[$template] = array(
  691. 'scalar' => array(),
  692. 'rows' => array()
  693. );
  694. return true;
  695. }
  696. /**
  697. * Adds several rows of variables to a template
  698. *
  699. * Each Template can have an unlimited amount of its own variables
  700. * Can be used to add a database result as variables to a template
  701. *
  702. * @param string $template name of the template
  703. * @param array $rows array containing assotiative arrays with variable/value pairs
  704. * @param string $prefix prefix for all variable names
  705. * @access public
  706. * @see addVar(), addVars(), addGlobalVar(), addGlobalVars()
  707. */
  708. function addRows( $template, $rows, $prefix = '' )
  709. {
  710. $template = strtolower( $template );
  711. $prefix = strtoupper( $prefix );
  712. $cnt = count( $rows );
  713. for( $i = 0; $i < $cnt; $i++ )
  714. {
  715. if( !isset( $this->_vars[$template]['rows'][$i] ) )
  716. $this->_vars[$template]['rows'][$i] = array();
  717. $rows[$i] = array_change_key_case( $rows[$i], CASE_UPPER );
  718. foreach( $rows[$i] as $varname => $value )
  719. {
  720. $this->_vars[$template]['rows'][$i][$prefix.$varname] = $value;
  721. }
  722. }
  723. }
  724. /**
  725. * Adds an object to a template
  726. *
  727. * All properties of the object will be available as template variables.
  728. *
  729. * @access public
  730. * @param string name of the template
  731. * @param object|array object or array of objects
  732. * @param string prefix for all variable names
  733. * @param boolean ignore private properties (starting with _)
  734. * @see addVar(), addRows(), addGlobalVar(), addGlobalVars()
  735. */
  736. function addObject( $template, $object, $prefix = '', $ignorePrivate = false )
  737. {
  738. if( is_array( $object ) ) {
  739. $rows = array();
  740. foreach($object as $o) {
  741. array_push( $rows, $this->getObjectVars($o, $ignorePrivate) );
  742. }
  743. return $this->addRows( $template, $rows, $prefix );
  744. } elseif (is_object($object)) {
  745. return $this->addVars( $template, $this->getObjectVars($object, $ignorePrivate), $prefix );
  746. }
  747. return false;
  748. }
  749. /**
  750. * get the vars from an object
  751. *
  752. * @access private
  753. * @param object
  754. * @param boolean ignore private properties (starting with _)
  755. * @return array
  756. */
  757. function getObjectVars($obj, $ignorePrivate = false)
  758. {
  759. if (method_exists($obj, 'getVars')) {
  760. return $obj->getVars();
  761. }
  762. $vars = get_object_vars($obj);
  763. if ($ignorePrivate === false) {
  764. return $vars;
  765. }
  766. foreach ($vars as $var => $value) {
  767. if ($var{0} == '_') {
  768. unset($vars[$var]);
  769. }
  770. }
  771. return $vars;
  772. }
  773. /**
  774. * Adds a global variable
  775. *
  776. * Global variables are valid in all templates of this object.
  777. * A global variable has to be scalar, it will be converted to a string.
  778. *
  779. * @access public
  780. * @param string $varname name of the global variable
  781. * @param string $value value of the variable
  782. * @return boolean true on success
  783. * @see addGlobalVars(), addVar(), addVars(), addRows()
  784. */
  785. function addGlobalVar( $varname, $value )
  786. {
  787. $this->_globals[strtoupper( $varname )] = ( string )$value;
  788. return true;
  789. }
  790. /**
  791. * Clears a global variable
  792. *
  793. * @access public
  794. * @param string $varname name of the global variable
  795. * @return boolean true on success
  796. * @see clearVar(), clearVars(), clearGlobalVars()
  797. */
  798. function clearGlobalVar( $varname )
  799. {
  800. $varname = strtoupper( $varname );
  801. if (!isset($this->_globals[$varname])) {
  802. return false;
  803. }
  804. unset($this->_globals[$varname]);
  805. return true;
  806. }
  807. /**
  808. * Clears all global variables
  809. *
  810. * @access public
  811. * @return boolean true on success
  812. * @see clearVar(), clearVars(), clearGlobalVar()
  813. */
  814. function clearGlobalVars()
  815. {
  816. $this->_globals = array();
  817. return true;
  818. }
  819. /**
  820. * Adds several global variables
  821. *
  822. * Global variables are valid in all templates of this object.
  823. *
  824. * $variables is an associative array, containing name/value pairs of the variables.
  825. *
  826. * @access public
  827. * @param array $variables array containing the variables
  828. * @param string $prefix prefix for variable names
  829. * @return boolean true on success
  830. * @see addGlobalVar(), addVar(), addVars(), addRows()
  831. */
  832. function addGlobalVars( $variables, $prefix = '' )
  833. {
  834. $variables = array_change_key_case( $variables, CASE_UPPER );
  835. $prefix = strtoupper( $prefix );
  836. foreach( $variables as $varname => $value )
  837. {
  838. $this->_globals[$prefix.$varname] = ( string )$value;
  839. }
  840. return true;
  841. }
  842. /**
  843. * get all global variables
  844. *
  845. * @access public
  846. * @return array global variables
  847. */
  848. function getGlobalVars()
  849. {
  850. return $this->_globals;
  851. }
  852. /**
  853. * checks wether a template exists
  854. *
  855. * @access public
  856. * @param string name of the template
  857. * @return boolean true, if the template exists, false otherwise
  858. */
  859. function exists( $name )
  860. {
  861. return in_array( strtolower( $name ), $this->_templateList );
  862. }
  863. /**
  864. * enable a template cache
  865. *
  866. * A template cache will improve performace, as the templates
  867. * do not have to be read on each request.
  868. *
  869. * @access public
  870. * @param string name of the template cache
  871. * @param array parameters for the template cache
  872. * @return boolean true on success, patError otherwise
  873. */
  874. function useTemplateCache( $cache, $params = array() )
  875. {
  876. if( !is_object( $cache ) )
  877. {
  878. $cache = &$this->loadModule( 'TemplateCache', $cache, $params );
  879. }
  880. if( patErrorManager::isError( $cache ) )
  881. return $cache;
  882. $this->_tmplCache = &$cache;
  883. return true;
  884. }
  885. /**
  886. * enable an output filter
  887. *
  888. * Output filters are used to modify the template
  889. * result before it is sent to the browser.
  890. *
  891. * They are applied, when displayParsedTemplate() is called.
  892. *
  893. * @access public
  894. * @param string name of the output filter
  895. * @param array parameters for the output filter
  896. * @return boolean true on success, patError otherwise
  897. */
  898. function applyOutputFilter( $filter, $params = array(), $template = null )
  899. {
  900. if (!is_object($filter)) {
  901. $filter = &$this->loadModule( 'OutputFilter', $filter, $params );
  902. }
  903. if (patErrorManager::isError($filter)) {
  904. return $filter;
  905. }
  906. if ($template === null) {
  907. $this->_outputFilters[] = &$filter;
  908. return true;
  909. }
  910. $template = strtolower($template);
  911. if (!$this->exists($template)) {
  912. return patErrorManager::raiseWarning(PATTEMPLATE_WARNING_NO_TEMPLATE, 'The selected template does not exist');
  913. }
  914. $this->_templates[$template]['attributes']['outputfilter'] = &$filter;
  915. return true;
  916. }
  917. /**
  918. * enable an input filter
  919. *
  920. * input filters are used to modify the template
  921. * stream before it is split into smaller templates-
  922. *
  923. * @access public
  924. * @param string name of the input filter
  925. * @param array parameters for the input filter
  926. * @return boolean true on success, patError otherwise
  927. */
  928. function applyInputFilter( $filter, $params = array() )
  929. {
  930. if( !is_object( $filter ) )
  931. {
  932. $filter = &$this->loadModule( 'InputFilter', $filter, $params );
  933. }
  934. if( patErrorManager::isError( $filter ) )
  935. return $filter;
  936. $this->_inputFilters[] = &$filter;
  937. return true;
  938. }
  939. /**
  940. * open a file and parse for patTemplate tags
  941. *
  942. * @access public
  943. * @param name of the file
  944. * @return true, if the template could be parsed
  945. * @deprecated Use patTemplate::readTemplatesFromInput() instead, as the method name is misleading
  946. * @see readTemplatesFromInput()
  947. */
  948. function readTemplatesFromFile( $filename )
  949. {
  950. return $this->readTemplatesFromInput( $filename, 'File' );
  951. }
  952. /**
  953. * open any input and parse for patTemplate tags
  954. *
  955. * @access public
  956. * @param string name of the input (filename, shm segment, etc.)
  957. * @param string driver that is used as reader, you may also pass a Reader object
  958. * @param array additional options that will only be used for this template
  959. * @param string name of the template that should be used as a container, should not be used by public
  960. * calls.
  961. * @return boolean true, if the template could be parsed, false otherwise
  962. */
  963. function readTemplatesFromInput( $input, $reader = 'File', $options = null, $parseInto = null )
  964. {
  965. if ((string)$input === '') {
  966. return patErrorManager::raiseError(PATTEMPLATE_ERROR_NO_INPUT, 'No input to read has been passed.');
  967. }
  968. if (is_array($options)) {
  969. $options = array_merge( $this->_options, $options );
  970. } else {
  971. $options = $this->_options;
  972. }
  973. if (!is_null($parseInto)) {
  974. $parseInto = strtolower( $parseInto );
  975. }
  976. $templates = false;
  977. if ($this->_tmplCache !== null) {
  978. /**
  979. * get the unique cache key
  980. */
  981. $key = $this->_tmplCache->getKey($input, $options);
  982. $templates = $this->_loadTemplatesFromCache( $input, $reader, $options, $key );
  983. /**
  984. * check for error returned from cache
  985. */
  986. if (patErrorManager::isError($templates)) {
  987. return $templates;
  988. }
  989. }
  990. /**
  991. * templates have not been loaded from cache
  992. */
  993. if ($templates === false) {
  994. if (!is_object( $reader)) {
  995. $reader = &$this->loadModule('Reader', $reader);
  996. if (patErrorManager::isError($reader)) {
  997. return $reader;
  998. }
  999. }
  1000. if ($reader->isInUse()) {
  1001. $reader = &$this->loadModule( 'Reader', $reader->getName(), array(), true);
  1002. if( patErrorManager::isError( $reader ) ) {
  1003. return $reader;
  1004. }
  1005. }
  1006. $reader->setOptions($options);
  1007. /**
  1008. * set the root attributes
  1009. */
  1010. if( !is_null( $parseInto ) )
  1011. {
  1012. $attributes = $this->getAttributes( $parseInto );
  1013. if( !patErrorManager::isError( $attributes ) )
  1014. {
  1015. $reader->setRootAttributes( $attributes );
  1016. }
  1017. }
  1018. $templates = $reader->readTemplates( $input );
  1019. /**
  1020. * check for error returned from reader
  1021. */
  1022. if( patErrorManager::isError( $templates ) )
  1023. return $templates;
  1024. /**
  1025. * store the
  1026. */
  1027. if( $this->_tmplCache !== null )
  1028. {
  1029. $this->_tmplCache->write( $key, $templates );
  1030. }
  1031. }
  1032. /**
  1033. * traverse all templates
  1034. */
  1035. foreach( $templates as $name => $spec )
  1036. {
  1037. /**
  1038. * root template
  1039. */
  1040. if( $name == '__ptroot' )
  1041. {
  1042. if( $parseInto === false )
  1043. {
  1044. continue;
  1045. }
  1046. if( !in_array( $parseInto, $this->_templateList ) )
  1047. continue;
  1048. $spec['loaded'] = true;
  1049. $spec['attributes'] = $this->_templates[$parseInto]['attributes'];
  1050. $name = $parseInto;
  1051. }
  1052. else
  1053. {
  1054. /**
  1055. * store the name
  1056. */
  1057. array_push( $this->_templateList, $name );
  1058. }
  1059. /**
  1060. * if this is the first template that has been loaded
  1061. * set it as the root template
  1062. */
  1063. if( $this->_root === null && is_null( $parseInto ) && isset( $spec['isRoot'] ) && $spec['isRoot'] == true )
  1064. {
  1065. $this->_root = $name;
  1066. }
  1067. /**
  1068. * set some default values
  1069. */
  1070. $spec['iteration'] = 0;
  1071. $spec['lastMode'] = 'w';
  1072. $spec['result'] = '';
  1073. $spec['modifyVars'] = array();
  1074. $spec['copyVars'] = array();
  1075. $spec['defaultVars'] = array();
  1076. /**
  1077. * store the template
  1078. */
  1079. $this->_templates[$name] = $spec;
  1080. $this->prepareTemplate( $name );
  1081. /**
  1082. * store the default values of the variables
  1083. */
  1084. foreach( $spec['varspecs'] as $varname => $varspec )
  1085. {
  1086. if (isset($varspec['modifier'])) {
  1087. $this->_templates[$name]['modifyVars'][$varname] = $varspec['modifier'];
  1088. }
  1089. if( isset( $varspec['copyfrom'] ) )
  1090. {
  1091. $this->_templates[$name]['copyVars'][$varname] = $varspec['copyfrom'];
  1092. }
  1093. if( !isset( $varspec['default'] ) )
  1094. continue;
  1095. $this->_templates[$name]['defaultVars'][$varname] = $varspec['default'];
  1096. if( !is_null( $this->getVar( $name, $varname ) ) )
  1097. continue;
  1098. $this->addVar( $name, $varname, $varspec['default'] );
  1099. }
  1100. unset($this->_templates[$name]['varspecs']);
  1101. /**
  1102. * autoload the template
  1103. *
  1104. * Some error management is needed here...
  1105. */
  1106. if( isset( $this->_templates[$name]['attributes']['src'] ) && $this->_templates[$name]['attributes']['autoload'] == 'on' )
  1107. {
  1108. if( $this->_templates[$name]['loaded'] !== true )
  1109. {
  1110. if( $this->_templates[$name]['attributes']['parse'] == 'on' )
  1111. {
  1112. $this->readTemplatesFromInput( $this->_templates[$name]['attributes']['src'], $this->_templates[$name]['attributes']['reader'], $options, $name );
  1113. }
  1114. else
  1115. {
  1116. $this->loadTemplateFromInput( $this->_templates[$name]['attributes']['src'], $this->_templates[$name]['attributes']['reader'], null, $name );
  1117. }
  1118. $this->_templates[$name]['loaded'] = true;
  1119. }
  1120. }
  1121. }
  1122. return true;
  1123. }
  1124. /**
  1125. * load from template cache
  1126. *
  1127. * @access private
  1128. * @param string name of the input (filename, shm segment, etc.)
  1129. * @param string driver that is used as reader, you may also pass a Reader object
  1130. * @param array options for the reader
  1131. * @param string cache key
  1132. * @return array|boolean either an array containing the templates, or false
  1133. */
  1134. function _loadTemplatesFromCache( $input, &$reader, $options, $key )
  1135. {
  1136. if( is_object( $reader ) )
  1137. $statName = $reader->getName();
  1138. else
  1139. $statName = $reader;
  1140. $stat = &$this->loadModule( 'Stat', $statName );
  1141. $stat->setOptions( $options );
  1142. /**
  1143. * get modification time
  1144. */
  1145. $modTime = $stat->getModificationTime( $input );
  1146. $templates = $this->_tmplCache->load( $key, $modTime );
  1147. return $templates;
  1148. }
  1149. /**
  1150. * open any input and load content into template
  1151. *
  1152. * @access public
  1153. * @param string name of the input (filename, shm segment, etc.)
  1154. * @param string driver that is used as reader
  1155. * @param string name of the template that should be used as a container,
  1156. * @return boolean true, if the template could be parsed, false otherwise
  1157. */
  1158. function loadTemplateFromInput( $input, $reader = 'File', $options = null, $parseInto = false )
  1159. {
  1160. if( is_array( $options ) )
  1161. $options = array_merge( $this->_options, $options );
  1162. else
  1163. $options = $this->_options;
  1164. if( !is_null( $parseInto ) )
  1165. $parseInto = strtolower( $parseInto );
  1166. $reader = &$this->loadModule( 'Reader', $reader );
  1167. if( patErrorManager::isError( $reader ) )
  1168. {
  1169. return $reader;
  1170. }
  1171. $reader->setOptions($options);
  1172. $result = $reader->loadTemplate( $input );
  1173. if( patErrorManager::isError( $result ) )
  1174. {
  1175. return $result;
  1176. }
  1177. $this->_templates[$parseInto]['content'] .= $result;
  1178. $this->_templates[$parseInto]['loaded'] = true;
  1179. return true;
  1180. }
  1181. /**
  1182. * load a template that had autoload="off"
  1183. *
  1184. * This is needed, if you change the source of a template and want to
  1185. * load it, after changing the attribute.
  1186. *
  1187. * @access public
  1188. * @param string template name
  1189. * @return boolean true, if template could be loaded
  1190. */
  1191. function loadTemplate( $template )
  1192. {
  1193. $template = strtolower( $template );
  1194. if( !isset( $this->_templates[$template] ) )
  1195. {
  1196. return patErrorManager::raiseWarning(
  1197. PATTEMPLATE_WARNING_NO_TEMPLATE,
  1198. "Template '$template' does not exist."
  1199. );
  1200. }
  1201. if( $this->_templates[$template]['loaded'] === true )
  1202. return true;
  1203. if( $this->_templates[$template]['attributes']['parse'] == 'on' )
  1204. {
  1205. return $this->readTemplatesFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], null, $template );
  1206. }
  1207. else
  1208. {
  1209. return $this->loadTemplateFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], null, $template );
  1210. }
  1211. }
  1212. /**
  1213. * loads a patTemplate module
  1214. *
  1215. * Modules are located in the patTemplate folder and include:
  1216. * - Readers
  1217. * - Caches
  1218. * - Variable Modifiers
  1219. * - Filters
  1220. * - Functions
  1221. * - Stats
  1222. *
  1223. * @access public
  1224. * @param string moduleType (Reader|TemplateCache|Modifier|OutputFilter|InputFilter)
  1225. * @param string moduleName
  1226. * @param array parameters for the module
  1227. * @return object
  1228. */
  1229. function &loadModule( $moduleType, $moduleName, $params = array(), $new = false )
  1230. {
  1231. if( !isset( $this->_modules[$moduleType] ) )
  1232. $this->_modules[$moduleType] = array();
  1233. $sig = md5( $moduleName . serialize( $params ) );
  1234. if( isset( $this->_modules[$moduleType][$sig] ) && $new === false ) {
  1235. return $this->_modules[$moduleType][$sig];
  1236. }
  1237. if( !class_exists( 'patTemplate_Module' ) )
  1238. {
  1239. $file = sprintf( "%s/Module.php", $this->getIncludePath() );
  1240. if( !@include_once $file )
  1241. return patErrorManager::raiseError( PATTEMPLATE_ERROR_BASECLASS_NOT_FOUND, 'Could not load module base class.' );
  1242. }
  1243. $baseClass = 'patTemplate_' . $moduleType;
  1244. if( !class_exists( $baseClass ) )
  1245. {
  1246. $baseFile = sprintf( "%s/%s.php", $this->getIncludePath(), $moduleType );
  1247. if( !@include_once $baseFile )
  1248. return patErrorManager::raiseError( PATTEMPLATE_ERROR_BASECLASS_NOT_FOUND, "Could not load base class for $moduleType ($baseFile)." );
  1249. }
  1250. $moduleClass = 'patTemplate_' . $moduleType . '_' .$moduleName;
  1251. if( !class_exists( $moduleClass ) )
  1252. {
  1253. if( isset( $this->_moduleDirs[$moduleType] ) )
  1254. $dirs = $this->_moduleDirs[$moduleType];
  1255. else
  1256. $dirs = array();
  1257. array_push( $dirs, $this->getIncludePath() .'/'. $moduleType );
  1258. $found = false;
  1259. foreach( $dirs as $dir )
  1260. {
  1261. $moduleFile = sprintf( "%s/%s.php", $dir, str_replace( '_', '/', $moduleName ) );
  1262. if (@include_once $moduleFile) {
  1263. $found = true;
  1264. break;
  1265. }
  1266. }
  1267. if( !$found ) {
  1268. return patErrorManager::raiseError( PATTEMPLATE_ERROR_MODULE_NOT_FOUND, "Could not load module $moduleClass ($moduleFile)." );
  1269. }
  1270. }
  1271. if( !class_exists( $moduleClass ) )
  1272. {
  1273. return patErrorManager::raiseError( PATTEMPLATE_ERROR_MODULE_NOT_FOUND, "Module file $moduleFile does not contain class $moduleClass." );
  1274. }
  1275. $this->_modules[$moduleType][$sig] = &new $moduleClass;
  1276. if( method_exists( $this->_modules[$moduleType][$sig], 'setTemplateReference' ) )
  1277. {
  1278. $this->_modules[$moduleType][$sig]->setTemplateReference( $this );
  1279. }
  1280. $this->_modules[$moduleType][$sig]->setParams( $params );
  1281. return $this->_modules[$moduleType][$sig];
  1282. }
  1283. /**
  1284. * checks whether a module exists.
  1285. *
  1286. * Modules are located in the patTemplate folder and include:
  1287. * - Readers
  1288. * - Caches
  1289. * - Variable Modifiers
  1290. * - Filters
  1291. * - Functions
  1292. * - Stats
  1293. *
  1294. * @access public
  1295. * @param string moduleType (Reader|TemplateCache|Modifier|OutputFilter|InputFilter)
  1296. * @param string moduleName
  1297. * @return boolean
  1298. */
  1299. function moduleExists( $moduleType, $moduleName )
  1300. {
  1301. if (isset($this->_moduleDirs[$moduleType])) {
  1302. $dirs = $this->_moduleDirs[$moduleType];
  1303. } else {
  1304. $dirs = array();
  1305. }
  1306. array_push($dirs, $this->getIncludePath() .'/'. $moduleType);
  1307. foreach ($dirs as $dir) {
  1308. $moduleFile = sprintf( "%s/%s.php", $dir, str_replace( '_', '/', $moduleName ) );
  1309. if (!file_exists($moduleFile)) {
  1310. continue;
  1311. }
  1312. if (!is_readable($moduleFile)) {
  1313. continue;
  1314. }
  1315. return true;
  1316. }
  1317. return false;
  1318. }
  1319. /**
  1320. * parses a template
  1321. *
  1322. * Parses a template and stores the parsed content.
  1323. * mode can be "w" for write (delete already parsed content) or "a" for append (appends the
  1324. * new parsed content to the already parsed content)
  1325. *
  1326. * @access public
  1327. * @param string name of the template
  1328. * @param string mode for the parsing
  1329. */
  1330. function parseTemplate( $template, $mode = 'w' )
  1331. {
  1332. $template = strtolower($template);
  1333. if (!isset($this->_templates[$template])) {
  1334. return patErrorManager::raiseWarning(
  1335. PATTEMPLATE_WARNING_NO_TEMPLATE,
  1336. "Template '$template' does not exist."
  1337. );
  1338. }
  1339. /**
  1340. * template is not visible
  1341. */
  1342. if ($this->_templates[$template]['attributes']['visibility'] == 'hidden') {
  1343. $this->_templates[$template]['result'] = '';
  1344. $this->_templates[$template]['parsed'] = true;
  1345. return true;
  1346. }
  1347. /**
  1348. * check, if the template has been loaded
  1349. * and load it if necessary.
  1350. */
  1351. if ($this->_templates[$template]['loaded'] !== true) {
  1352. if ($this->_templates[$template]['attributes']['parse'] == 'on') {
  1353. $result = $this->readTemplatesFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], null, $template );
  1354. } else {
  1355. $result = $this->loadTemplateFromInput( $this->_templates[$template]['attributes']['src'], $this->_templates[$template]['attributes']['reader'], null, $template );
  1356. }
  1357. if (patErrorManager::isError($result)) {
  1358. return $result;
  1359. }
  1360. }
  1361. /**
  1362. * check for autoclear
  1363. */
  1364. if(
  1365. isset( $this->_templates[$template]['attributes']['autoclear'] ) &&
  1366. $this->_templates[$template]['attributes']['autoclear'] == 'yes' &&
  1367. $mode === 'w' &&
  1368. $this->_templates[$template]['lastMode'] != 'a'
  1369. ) {
  1370. $this->_templates[$template]['parsed'] = false;
  1371. }
  1372. /**
  1373. * template has been parsed and mode is not 'append'
  1374. */
  1375. if ($this->_templates[$template]['parsed'] === true && $mode === 'w') {
  1376. return true;
  1377. }
  1378. $this->_templates[$template]['lastMode'] = $mode;
  1379. $this->_initTemplate( $template );
  1380. if (!isset($this->_vars[$template]['rows'])) {
  1381. $this->_vars[$template]['rows'] = array();
  1382. }
  1383. $loop = count( $this->_vars[$template]['rows'] );
  1384. /**
  1385. * loop at least one times
  1386. */
  1387. if ($loop < 1) {
  1388. $loop = 1;
  1389. }
  1390. if (isset($this->_templates[$template]['attributes']['maxloop'])) {
  1391. $loop = ceil( $loop / $this->_templates[$template]['attributes']['maxloop'] ) * $this->_templates[$template]['attributes']['maxloop'];
  1392. }
  1393. $this->_templates[$template]['loop'] = max( $this->_templates[$template]['attributes']['loop'], $loop );
  1394. $start = 0;
  1395. if (isset($this->_templates[$template]['attributes']['limit'])) {
  1396. $p = strpos( $this->_templates[$template]['attributes']['limit'], ',' );
  1397. if ($p === false) {
  1398. $this->_templates[$template]['loop'] = min( $this->_templates[$template]['loop'], $this->_templates[$template]['attributes']['limit'] );
  1399. $start = 0;
  1400. } else {
  1401. $start = substr( $this->_templates[$template]['attributes']['limit'], 0, $p );
  1402. $end = substr( $this->_templates[$template]['attributes']['limit'], $p+1 )+$start;
  1403. $this->_templates[$template]['loop'] = min( $this->_templates[$template]['loop'], $end );
  1404. }
  1405. }
  1406. /**
  1407. * template should be cleared before parsing
  1408. */
  1409. if ($mode == 'w') {
  1410. $this->_templates[$template]['result'] = '';
  1411. $this->_templates[$template]['iteration'] = $start;
  1412. }
  1413. $loopCount = 0;
  1414. for ($i = $start; $i < $this->_templates[$template]['loop']; $i++) {
  1415. $finished = false;
  1416. unset( $this->_templates[$template]['vars'] );
  1417. /**
  1418. * fetch the variables
  1419. */
  1420. $this->_fetchVariables( $template );
  1421. /**
  1422. * fetch the template
  1423. */
  1424. $result = $this->_fetchTemplate($template);
  1425. if ($result === false) {
  1426. $this->_templates[$template]['iteration']++;
  1427. continue;
  1428. }
  1429. /**
  1430. * parse
  1431. */
  1432. $this->_parseVariables( $template );
  1433. $result = $this->_parseDependencies( $template );
  1434. if (patErrorManager::isError($result)) {
  1435. return $result;
  1436. }
  1437. /**
  1438. * store result
  1439. */
  1440. $this->_templates[$template]['result'] .= $this->_templates[$template]['work'];
  1441. $this->_templates[$template]['iteration']++;
  1442. ++$loopCount;
  1443. /**
  1444. * check for maximum loops
  1445. */
  1446. if (isset($this->_templates[$template]['attributes']['maxloop'])) {
  1447. if ($loopCount == $this->_templates[$template]['attributes']['maxloop'] && $i < ($loop-1)) {
  1448. $loopCount = 0;
  1449. $finished = true;
  1450. $this->_templates[$template]['parsed'] = true;
  1451. $this->parseTemplate( $this->_templates[$template]['attributes']['parent'], 'a' );
  1452. $this->_templates[$template]['parsed'] = false;
  1453. $this->_templates[$template]['result'] = '';
  1454. }
  1455. }
  1456. }
  1457. if (!$finished && isset($this->_templates[$template]['attributes']['maxloop'])) {
  1458. $this->_templates[$template]['parsed'] = true;
  1459. $this->parseTemplate( $this->_templates[$template]['attributes']['parent'], 'a', false );
  1460. $this->_templates[$template]['parsed'] = false;
  1461. $this->_templates[$template]['result'] = '';
  1462. $this->_templates[$this->_templates[$template]['attributes']['parent']]['work'] = '';
  1463. }
  1464. $this->_parseGlobals($template);
  1465. $this->_handleUnusedVars($template);
  1466. $this->_templates[$template]['parsed'] = true;
  1467. if (isset($this->_templates[$template]['attributes']['autoclear']) && $this->_templates[$template]['attributes']['autoclear'] == 'yes') {
  1468. $this->_vars[$template] = array(
  1469. 'scalar' => array(),
  1470. 'rows' => array()
  1471. );
  1472. }
  1473. if (isset($this->_templates[$template]['attributes']['outputfilter'])) {
  1474. if (is_object($this->_templates[$template]['attributes']['outputfilter'])) {
  1475. $filter = &$this->_templates[$template]['attributes']['outputfilter'];
  1476. } else {
  1477. $filter = &$this->loadModule('OutputFilter', $this->_templates[$template]['attributes']['outputfilter']);
  1478. }
  1479. if (patErrorManager::isError($filter)) {
  1480. return $filter;
  1481. }
  1482. $this->_templates[$template]['result'] = $filter->apply($this->_templates[$template]['result']);
  1483. }
  1484. return true;
  1485. }
  1486. /**
  1487. * Initialize a template
  1488. *
  1489. * This method checks the variable specifications and
  1490. * copys variables from other templates.
  1491. *
  1492. * @access private
  1493. * @param string name of the template
  1494. * @return boolean true on success
  1495. */
  1496. function _initTemplate( $template )
  1497. {
  1498. foreach( $this->_templates[$template]['copyVars'] as $dest => $src )
  1499. {
  1500. /**
  1501. * copy from the same template
  1502. */
  1503. if( !is_array( $src ) )
  1504. {
  1505. $srcTemplate = $template;
  1506. $srcVar = $src;
  1507. }
  1508. else
  1509. {
  1510. $srcTemplate = $src[0];
  1511. $srcVar = $src[1];
  1512. }
  1513. $copied = false;
  1514. /**
  1515. * copy from another template
  1516. */
  1517. if( isset( $this->_vars[$srcTemplate] ) )
  1518. {
  1519. if( isset( $this->_vars[$srcTemplate]['scalar'][$srcVar] ) )
  1520. {
  1521. $this->_vars[$template]['scalar'][$dest] = $this->_vars[$srcTemplate]['scalar'][$srcVar];
  1522. continue;
  1523. }
  1524. $rows = count( $this->_vars[$srcTemplate]['rows'] );
  1525. for( $i = 0; $i < $rows; $i++ )
  1526. {
  1527. if( !isset( $this->_vars[$srcTemplate]['rows'][$i][$srcVar] ) )
  1528. continue;
  1529. if( !isset( $this->_vars[$template]['rows'][$i] ) )
  1530. $this->_vars[$template]['rows'][$i] = array();
  1531. $this->_vars[$template]['rows'][$i][$dest] = $this->_vars[$srcTemplate]['rows'][$i][$srcVar];
  1532. $copied = true;
  1533. }
  1534. }
  1535. if( !$copied && isset( $this->_globals[$srcVar] ))
  1536. {
  1537. $this->_vars[$template]['scalar'][$dest] = $this->_globals[$srcVar];
  1538. }
  1539. }
  1540. return true;
  1541. }
  1542. /**
  1543. * parse all variables in a template
  1544. *
  1545. * @access private
  1546. * @param string
  1547. */
  1548. function _parseVariables( $template )
  1549. {
  1550. /**
  1551. * modify variables before parsing
  1552. */
  1553. $this->_applyModifers($template, $this->_templates[$template]['vars']);
  1554. foreach( $this->_templates[$template]['vars'] as $key => $value )
  1555. {
  1556. if( is_array( $value ) )
  1557. {
  1558. if( count( $this->_templates[$template]['currentDependencies'] ) == 1 )
  1559. {
  1560. $child = $this->_templates[$template]['currentDependencies'][0];
  1561. }
  1562. else
  1563. {
  1564. if( isset( $this->_templates[$template]['attributes']['child'] ) )
  1565. $child = $this->_templates[$template]['attributes']['child'];
  1566. else
  1567. continue;
  1568. }
  1569. $this->setAttribute( $child, 'autoclear', 'yes' );
  1570. $this->addVar( $child, $key, $value );
  1571. continue;
  1572. }
  1573. $var = $this->_startTag.$key.$this->_endTag;
  1574. $this->_templates[$template]['work'] = str_replace( $var, $value, $this->_templates[$template]['work'] );
  1575. }
  1576. return true;
  1577. }
  1578. /**
  1579. * parse global variables in the template
  1580. *
  1581. * @access private
  1582. * @param string name of the template
  1583. * @return boolean
  1584. */
  1585. function _parseGlobals($template)
  1586. {
  1587. $globalVars = $this->_globals;
  1588. $this->_applyModifers($template, $globalVars);
  1589. foreach( $globalVars as $key => $value )
  1590. {
  1591. if( is_array( $value ) )
  1592. {
  1593. continue;
  1594. }
  1595. $var = $this->_startTag.$key.$this->_endTag;
  1596. $this->_templates[$template]['result'] = str_replace( $var, $value, $this->_templates[$template]['result'] );
  1597. }
  1598. return true;
  1599. }
  1600. /**
  1601. * apply variable modifiers
  1602. *
  1603. * The variables will be passed by reference.
  1604. *
  1605. * @access private
  1606. * @param string name of the template (use modifiers from this template)
  1607. * @param array variables to which the modifiers should be applied
  1608. * @return boolean
  1609. */
  1610. function _applyModifers($template, &$vars)
  1611. {
  1612. foreach ($this->_templates[$template]['modifyVars'] as $varname => $modifier) {
  1613. if (!isset($vars[$varname])) {
  1614. continue;
  1615. }
  1616. if (($modifier['type'] === 'php' || $modifier['type'] === 'auto' ) && is_callable($modifier['mod'])) {
  1617. $vars[$varname] = call_user_func($modifier['mod'], $vars[$varname]);
  1618. continue;
  1619. }
  1620. if ($modifier['type'] === 'php') {
  1621. continue;
  1622. }
  1623. $mod = &$this->loadModule( 'Modifier', ucfirst( $modifier['mod'] ) );
  1624. $vars[$varname] = $mod->modify( $vars[$varname], $modifier['params'] );
  1625. }
  1626. // apply the default modifier
  1627. if (isset($this->_templates[$template]['attributes']['defaultmodifier'])) {
  1628. $defaultModifier = $this->_templates[$template]['attributes']['defaultmodifier'];
  1629. if (is_callable($defaultModifier)) {
  1630. $type = 'php';
  1631. } else {
  1632. $type = 'custom';
  1633. $defaultModifier = &$this->loadModule('Modifier', ucfirst($defaultModifier));
  1634. }
  1635. foreach (array_keys($vars) as $varname) {
  1636. if (isset($this->_templates[$template]['modifyVars'][$varname])) {
  1637. continue;
  1638. }
  1639. if ($type === 'php') {
  1640. $vars[$varname] = call_user_func($defaultModifier, $vars[$varname]);
  1641. } else {
  1642. $vars[$varname] = $defaultModifier->modify($vars[$varname], array());
  1643. }
  1644. }
  1645. }
  1646. return true;
  1647. }
  1648. /**
  1649. * parse all dependencies in a template
  1650. *
  1651. * @access private
  1652. * @param string
  1653. */
  1654. function _parseDependencies($template)
  1655. {
  1656. $countDep = count( $this->_templates[$template]['currentDependencies'] );
  1657. for ($i = 0; $i < $countDep; $i++) {
  1658. $depTemplate = $this->_templates[$template]['currentDependencies'][$i];
  1659. if ($depTemplate == $template) {
  1660. return patErrorManager::raiseError(PATTEMPLATE_ERROR_RECURSION, 'You have an error in your template "' . $template . '", which leads to recursion');
  1661. }
  1662. $this->parseTemplate($depTemplate);
  1663. $var = $this->_startTag.'TMPL:'.strtoupper( $depTemplate) .$this->_endTag;
  1664. $this->_templates[$template]['work'] = str_replace( $var, $this->_templates[$depTemplate]['result'], $this->_templates[$template]['work'] );
  1665. }
  1666. return true;
  1667. }
  1668. /**
  1669. * fetch plain template
  1670. *
  1671. * The template content will be stored in the template
  1672. * configuration so it can be used by other
  1673. * methods.
  1674. *
  1675. * @access private
  1676. * @param string template name
  1677. * @return boolean
  1678. */
  1679. function _fetchTemplate( $template )
  1680. {
  1681. switch( $this->_templates[$template]['attributes']['type'] )
  1682. {
  1683. /**
  1684. * condition template
  1685. */
  1686. case 'condition':
  1687. $value = $this->_getConditionValue($template, $this->_templates[$template]['attributes']['conditionvar']);
  1688. if ($value === false) {
  1689. $this->_templates[$template]['work'] = '';
  1690. $this->_templates[$template]['currentDependencies'] = array();
  1691. } else {
  1692. $this->_templates[$template]['work'] = $this->_templates[$template]['subtemplates'][$value]['data'];
  1693. $this->_templates[$template]['currentDependencies'] = $this->_templates[$template]['subtemplates'][$value]['dependencies'];
  1694. }
  1695. break;
  1696. /**
  1697. * condition template
  1698. */
  1699. case 'simplecondition':
  1700. foreach( $this->_templates[$template]['attributes']['requiredvars'] as $var )
  1701. {
  1702. // different template scope
  1703. if( $var[0] !== $template ) {
  1704. $this->_fetchVariables($var[0]);
  1705. }
  1706. $value = null;
  1707. // fetch the local variable
  1708. if( isset( $this->_templates[$var[0]]['vars'][$var[1]] )
  1709. && strlen( $this->_templates[$var[0]]['vars'][$var[1]] ) > 0 ) {
  1710. $value = $this->_templates[$var[0]]['vars'][$var[1]];
  1711. }
  1712. if (isset($this->_templates[$template]['attributes']['useglobals'])) {
  1713. if(isset($this->_globals[$var[1]]) && strlen($this->_globals[$var[1]]) > 1) {
  1714. $value = $this->_globals[$var[1]];
  1715. }
  1716. }
  1717. if ($value !== null) {
  1718. if ($var[2] === null) {
  1719. continue;
  1720. } else {
  1721. // Joomla! addition 23-June-2005
  1722. // value wrapped in ## uses regex for comparison
  1723. $condition = $var[2];
  1724. if (substr( $condition, 0, 1 ) == '#' && substr( $condition, -1, 1 ) == '#' ) {
  1725. if (preg_match( $condition, $value )) {
  1726. continue;
  1727. }
  1728. } else if ($condition == $value) {
  1729. continue;
  1730. }
  1731. /* Pat Original
  1732. if ($var[2] == $value) {
  1733. continue;
  1734. }
  1735. */
  1736. }
  1737. }
  1738. $this->_templates[$template]['work'] = '';
  1739. $this->_templates[$template]['currentDependencies'] = array();
  1740. break 2;
  1741. }
  1742. $this->_templates[$template]['work'] = $this->_templates[$template]['content'];
  1743. $this->_templates[$template]['currentDependencies'] = $this->_templates[$template]['dependencies'];
  1744. break;
  1745. /**
  1746. * modulo template
  1747. */
  1748. case 'modulo':
  1749. // check for empty template
  1750. if ($this->_hasVariables($template)) {
  1751. $value = (string)($this->_templates[$template]['iteration'] + 1 ) % $this->_templates[$template]['attributes']['modulo'];
  1752. } else {
  1753. $value = '__empty';
  1754. }
  1755. $value = $this->_getConditionValue($template, $value, false);
  1756. if ($value === false) {
  1757. $this->_templates[$template]['work'] = '';
  1758. $this->_templates[$template]['currentDependencies'] = array();
  1759. } else {
  1760. $this->_templates[$template]['work'] = $this->_templates[$template]['subtemplates'][$value]['data'];
  1761. $this->_templates[$template]['currentDependencies'] = $this->_templates[$template]['subtemplates'][$value]['dependencies'];
  1762. }
  1763. break;
  1764. /**
  1765. * standard template
  1766. */
  1767. default:
  1768. $this->_templates[$template]['work'] = $this->_templates[$template]['content'];
  1769. $this->_templates[$template]['currentDependencies'] = $this->_templates[$template]['dependencies'];
  1770. break;
  1771. }
  1772. return true;
  1773. }
  1774. /**
  1775. * check, whether a template contains variables
  1776. *
  1777. * @access private
  1778. * @param string template name
  1779. * @return boolean
  1780. */
  1781. function _hasVariables($template)
  1782. {
  1783. if (!empty($this->_vars[$template]['scalar'])) {
  1784. return true;
  1785. }
  1786. if (isset($this->_vars[$template]['rows'][$this->_templates[$template]['iteration']])) {
  1787. return true;
  1788. }
  1789. return false;
  1790. }
  1791. /**
  1792. * fetch the value of a condition variable
  1793. *
  1794. * _fetchVariables() has to be called before this
  1795. * method is being called.
  1796. *
  1797. * @access private
  1798. * @param string template name
  1799. * @param string condition value
  1800. * @param boolean flag that indicates whether value is the name of the variable that should be resolved
  1801. *
  1802. * @todo split this method into smaller check methods that will be called according to
  1803. * a priority list
  1804. */
  1805. function _getConditionValue( $template, $value, $isVar = true )
  1806. {
  1807. if ($isVar === true) {
  1808. if (isset($this->_templates[$template]['attributes']['conditiontmpl'])) {
  1809. $_template = $this->_templates[$template]['attributes']['conditiontmpl'];
  1810. $this->_fetchVariables($_template);
  1811. } else {
  1812. $_template = $template;
  1813. }
  1814. /**
  1815. * get the value from the template variables
  1816. */
  1817. if (!isset($this->_templates[$_template]['vars'][$value]) || strlen($this->_templates[$_template]['vars'][$value]) === 0) {
  1818. if ($this->_templates[$template]['attributes']['useglobals'] == 'yes' || $this->_templates[$template]['attributes']['useglobals'] == 'useglobals') {
  1819. if (isset( $this->_globals[$value] ) && strlen( $this->_globals[$value] ) > 0) {
  1820. $value = $this->_globals[$value];
  1821. } else {
  1822. $value = '__empty';
  1823. }
  1824. } else {
  1825. $value = '__empty';
  1826. }
  1827. } else {
  1828. $value = $this->_templates[$_template]['vars'][$value];
  1829. }
  1830. } else {
  1831. $_template = $template;
  1832. }
  1833. // if value is empty and a template for empty has been defined, this
  1834. // has priority
  1835. if ($value === '__empty' && isset($this->_templates[$template]['subtemplates']['__empty'])) {
  1836. return $value;
  1837. }
  1838. // only one iteration (but not empty), use the __single condition
  1839. if ($value !== '__empty' && $this->_templates[$_template]['loop'] === 1) {
  1840. if( isset($this->_templates[$template]['subtemplates']['__single'])) {
  1841. return '__single';
  1842. }
  1843. } else {
  1844. // is __first?
  1845. if( $this->_templates[$_template]['iteration'] == 0 ) {
  1846. if( isset( $this->_templates[$template]['subtemplates']['__first'] ) ) {
  1847. return '__first';
  1848. }
  1849. }
  1850. /**
  1851. * is __last?
  1852. */
  1853. if (isset($this->_templates[$_template]['loop'])) {
  1854. $max = $this->_templates[$_template]['loop'] - 1;
  1855. if( $this->_templates[$_template]['iteration'] == $max ) {
  1856. if( isset( $this->_templates[$template]['subtemplates']['__last'] ) ) {
  1857. return '__last';
  1858. }
  1859. }
  1860. }
  1861. }
  1862. // search for exact match
  1863. foreach (array_keys($this->_templates[$template]['subtemplates']) as $key) {
  1864. if (isset($this->_templates[$template]['subtemplates'][$key]['attributes']['var'])) {
  1865. $var = $this->_templates[$template]['subtemplates'][$key]['attributes']['var'];
  1866. if (isset($this->_templates[$template]['vars'][$var])) {
  1867. $current = $this->_templates[$template]['vars'][$var];
  1868. } else {
  1869. $current = null;
  1870. }
  1871. } else {
  1872. $current = $key;
  1873. }
  1874. if ((string)$value === (string)$current) {
  1875. return $key;
  1876. }
  1877. }
  1878. /**
  1879. * is __default?
  1880. */
  1881. if( isset( $this->_templates[$template]['subtemplates']['__default'] ) ) {
  1882. return '__default';
  1883. }
  1884. return false;
  1885. }
  1886. /**
  1887. * fetch variables for a template
  1888. *
  1889. * The variables will be stored in the template
  1890. * configuration so they can be used by other
  1891. * methods.
  1892. *
  1893. * @access private
  1894. * @param string template name
  1895. * @return boolean
  1896. */
  1897. function _fetchVariables( $template )
  1898. {
  1899. /**
  1900. * variables already have been fetched
  1901. */
  1902. if (isset($this->_templates[$template]['vars'])) {
  1903. return true;
  1904. }
  1905. $iteration = $this->_templates[$template]['iteration'];
  1906. $vars = array();
  1907. if( isset( $this->_templates[$template]['attributes']['varscope'] ) )
  1908. {
  1909. if (!is_array($this->_templates[$template]['attributes']['varscope'])) {
  1910. $this->_templates[$template]['attributes']['varscope'] = array($this->_templates[$template]['attributes']['varscope']);
  1911. }
  1912. foreach ($this->_templates[$template]['attributes']['varscope'] as $scopeTemplate) {
  1913. if ($this->exists($scopeTemplate)) {
  1914. $this->_fetchVariables( $scopeTemplate );
  1915. $vars = array_merge($this->_templates[$scopeTemplate]['vars'], $vars);
  1916. } else {
  1917. patErrorManager::raiseWarning(PATTEMPLATE_WARNING_NO_TEMPLATE, 'Template \''.$scopeTemplate.'\' does not exist, referenced in varscope attribute of template \''.$template.'\'');
  1918. }
  1919. }
  1920. } else {
  1921. $vars = array();
  1922. }
  1923. /**
  1924. * get the scalar variables
  1925. */
  1926. if( isset( $this->_vars[$template] ) && isset( $this->_vars[$template]['scalar'] ) )
  1927. {
  1928. $vars = array_merge( $vars, $this->_vars[$template]['scalar'] );
  1929. }
  1930. /**
  1931. * get the row variables
  1932. */
  1933. if( isset( $this->_vars[$template]['rows'][$iteration] ) )
  1934. {
  1935. $vars = array_merge( $vars, $this->_vars[$template]['rows'][$iteration] );
  1936. }
  1937. /**
  1938. * add some system variables
  1939. */
  1940. $currentRow = $iteration + $this->_templates[$template]['attributes']['rowoffset'];
  1941. $vars['PAT_ROW_VAR'] = $currentRow;
  1942. if( $this->_templates[$template]['attributes']['type'] == 'modulo' )
  1943. {
  1944. $vars['PAT_MODULO_REP'] = ceil( $currentRow / $this->_templates[$template]['attributes']['modulo'] );
  1945. $vars['PAT_MODULO'] = ( $this->_templates[$template]['iteration'] + 1 ) % $this->_templates[$template]['attributes']['modulo'];
  1946. }
  1947. if( $this->_templates[$template]['attributes']['addsystemvars'] !== false )
  1948. {
  1949. $vars['PATTEMPLATE_VERSION'] = $this->_systemVars['appVersion'];
  1950. $vars['PAT_LOOPS'] = $this->_templates[$template]['loop'];
  1951. switch ($this->_templates[$template]['attributes']['addsystemvars'])
  1952. {
  1953. case 'boolean':
  1954. $trueValue = 'true';
  1955. $falseValue = 'false';
  1956. break;
  1957. case 'integer':
  1958. $trueValue = '1';
  1959. $falseValue = '0';
  1960. break;
  1961. default:
  1962. $trueValue = $this->_templates[$template]['attributes']['addsystemvars'];
  1963. $falseValue = '';
  1964. break;
  1965. }
  1966. $vars['PAT_IS_ODD'] = ( $currentRow % 2 == 1 ) ? $trueValue : $falseValue;
  1967. $vars['PAT_IS_EVEN'] = ( $currentRow % 2 == 0 ) ? $trueValue : $falseValue;
  1968. $vars['PAT_IS_FIRST'] = ( $currentRow == 1 ) ? $trueValue : $falseValue;
  1969. $vars['PAT_IS_LAST'] = ( $currentRow == $this->_templates[$template]['loop'] ) ? $trueValue : $falseValue;
  1970. $vars['PAT_ROW_TYPE'] = ( $currentRow % 2 == 1 ) ? 'odd' : 'even';
  1971. }
  1972. $this->_templates[$template]['vars'] = $vars;
  1973. return true;
  1974. }
  1975. /**
  1976. * handle all unused variables in a template
  1977. *
  1978. * This is influenced by the 'unusedvars' attribute of the
  1979. * template
  1980. *
  1981. * @access private
  1982. * @param string
  1983. */
  1984. function _handleUnusedVars( $template )
  1985. {
  1986. $regexp = '/([^\\\])('.$this->_startTag.'[^a-z]+[^\\\]'.$this->_endTag.')/U';
  1987. switch( $this->_templates[$template]['attributes']['unusedvars'] )
  1988. {
  1989. case 'comment':
  1990. $this->_templates[$template]['result'] = preg_replace( $regexp, '<!-- \\1\\2 -->', $this->_templates[$template]['result'] );
  1991. break;
  1992. case 'strip':
  1993. $this->_templates[$template]['result'] = preg_replace( $regexp, '\\1', $this->_templates[$template]['result'] );
  1994. break;
  1995. case 'nbsp':
  1996. $this->_templates[$template]['result'] = preg_replace( $regexp, '\\1&nbsp;', $this->_templates[$template]['result'] );
  1997. break;
  1998. case 'ignore':
  1999. break;
  2000. default:
  2001. $this->_templates[$template]['result'] = preg_replace( $regexp, '\\1'.$this->_templates[$template]['attributes']['unusedvars'], $this->_templates[$template]['result'] );
  2002. break;
  2003. }
  2004. // replace quoted variables
  2005. $regexp = '/[\\\]'.$this->_startTag.'([^a-z]+)[\\\]'.$this->_endTag.'/U';
  2006. $this->_templates[$template]['result'] = preg_replace( $regexp, $this->_startTag.'\\1'.$this->_endTag, $this->_templates[$template]['result'] );
  2007. return true;
  2008. }
  2009. /**
  2010. * returns a parsed Template
  2011. *
  2012. * If the template already has been parsed, it just returns the parsed template.
  2013. * If the template has not been loaded, it will be loaded.
  2014. *
  2015. * @access public
  2016. * @param string name of the template
  2017. * @param boolean whether to apply output filters
  2018. * @return string Content of the parsed template
  2019. * @see displayParsedTemplate()
  2020. */
  2021. function getParsedTemplate( $name = null, $applyFilters = false )
  2022. {
  2023. if (is_null($name)) {
  2024. $name = $this->_root;
  2025. }
  2026. $name = strtolower( $name );
  2027. $result = $this->parseTemplate( $name );
  2028. if (patErrorManager::isError( $result )) {
  2029. return $result;
  2030. }
  2031. if ($applyFilters === false) {
  2032. return $this->_templates[$name]['result'];
  2033. }
  2034. $result = $this->_templates[$name]['result'];
  2035. $cnt = count ($this->_outputFilters);
  2036. for ($i = 0; $i < $cnt; $i++) {
  2037. $result = $this->_outputFilters[$i]->apply( $result );
  2038. }
  2039. return $result;
  2040. }
  2041. /**
  2042. * displays a parsed Template
  2043. *
  2044. * If the template has not been loaded, it will be loaded.
  2045. *
  2046. * @see getParsedTemplate()
  2047. * @param string name of the template
  2048. * @param boolean whether to apply output filters
  2049. * @return boolean true on success
  2050. * @access public
  2051. */
  2052. function displayParsedTemplate($name = null, $applyFilters = true)
  2053. {
  2054. $result = $this->getParsedTemplate($name, $applyFilters);
  2055. /**
  2056. * error happened
  2057. */
  2058. if (patErrorManager::isError($result)) {
  2059. return $result;
  2060. }
  2061. echo $result;
  2062. return true;
  2063. }
  2064. /**
  2065. * parse a template and push the result into a variable of any other
  2066. * template
  2067. *
  2068. * If the template already has been parsed, it will just be pushed into the variable.
  2069. * If the template has not been loaded, it will be loaded.
  2070. *
  2071. * @access public
  2072. * @param string name of the template
  2073. * @return string Content of the parsed template
  2074. * @param boolean if set to true, the value will be appended to the value already stored.
  2075. * @see getParsedTemplate()
  2076. * @see addVar()
  2077. */
  2078. function parseIntoVar( $srcTmpl, $destTmpl, $var, $append = false )
  2079. {
  2080. $srcTmpl = strtolower( $srcTmpl );
  2081. $destTmpl = strtolower( $destTmpl );
  2082. $var = strtoupper($var);
  2083. $result = $this->parseTemplate( $srcTmpl );
  2084. if( patErrorManager::isError( $result ) )
  2085. return $result;
  2086. if( $append !== true || !isset( $this->_vars[$destTmpl]['scalar'][$var] ) )
  2087. $this->_vars[$destTmpl]['scalar'][$var] = '';
  2088. $this->_vars[$destTmpl]['scalar'][$var] .= $this->_templates[$srcTmpl]['result'];
  2089. return true;
  2090. }
  2091. /**
  2092. * clears a parsed Template
  2093. *
  2094. * Parsed Content, variables and the loop attribute are cleared
  2095. *
  2096. * If you will not be using this template anymore, then you should
  2097. * call freeTemplate()
  2098. *
  2099. * @access public
  2100. * @param string name of the template
  2101. * @param boolean set this to true to clear all child templates, too
  2102. * @see clearAllTemplates()
  2103. * @see freeTemplate()
  2104. */
  2105. function clearTemplate( $name, $recursive = false )
  2106. {
  2107. $name = strtolower( $name );
  2108. $this->_templates[$name]['parsed'] = false;
  2109. $this->_templates[$name]['work'] = '';
  2110. $this->_templates[$name]['iteration'] = 0;
  2111. $this->_templates[$name]['result'] = '';
  2112. $this->_vars[$name] = array(
  2113. 'scalar' => array(),
  2114. 'rows' => array()
  2115. );
  2116. if (!empty($this->_templates[$name]['defaultVars'])) {
  2117. foreach ($this->_templates[$name]['defaultVars'] as $varname => $value) {
  2118. $this->addVar($name, $varname, $value);
  2119. }
  2120. }
  2121. /**
  2122. * clear child templates as well
  2123. */
  2124. if( $recursive === true )
  2125. {
  2126. $deps = $this->_getDependencies( $name );
  2127. foreach( $deps as $dep )
  2128. {
  2129. $this->clearTemplate( $dep, true );
  2130. }
  2131. }
  2132. return true;
  2133. }
  2134. /**
  2135. * clears all templates
  2136. *
  2137. * @access public
  2138. * @uses clearTemplate()
  2139. */
  2140. function clearAllTemplates()
  2141. {
  2142. $templates = array_keys( $this->_templates );
  2143. $cnt = count( $templates );
  2144. for( $i = 0; $i < $cnt; $i++ )
  2145. {
  2146. $this->clearTemplate( $templates[$i] );
  2147. }
  2148. return true;
  2149. }
  2150. /**
  2151. * frees a template
  2152. *
  2153. * All memory consumed by the template
  2154. * will be freed.
  2155. *
  2156. * @access public
  2157. * @param string name of the template
  2158. * @param boolean clear dependencies of the template
  2159. * @see freeAllTemplates()
  2160. */
  2161. function freeTemplate( $name, $recursive = false )
  2162. {
  2163. $name = strtolower( $name );
  2164. $key = array_search( $name, $this->_templateList );
  2165. if( $key === false )
  2166. {
  2167. return patErrorManager::raiseWarning(
  2168. PATTEMPLATE_WARNING_NO_TEMPLATE,
  2169. "Template '$name' does not exist."
  2170. );
  2171. }
  2172. unset( $this->_templateList[$key] );
  2173. $this->_templateList = array_values( $this->_templateList );
  2174. /**
  2175. * free child templates as well
  2176. */
  2177. if( $recursive === true )
  2178. {
  2179. $deps = $this->_getDependencies( $name );
  2180. foreach( $deps as $dep )
  2181. {
  2182. $this->freeTemplate( $dep, true );
  2183. }
  2184. }
  2185. unset( $this->_templates[$name] );
  2186. unset( $this->_vars[$name] );
  2187. if (isset($this->_discoveredPlaceholders[$name])) {
  2188. unset($this->_discoveredPlaceholders[$name]);
  2189. }
  2190. return true;
  2191. }
  2192. /**
  2193. * frees all templates
  2194. *
  2195. * All memory consumed by the templates
  2196. * will be freed.
  2197. *
  2198. * @access public
  2199. * @see freeTemplate()
  2200. */
  2201. function freeAllTemplates()
  2202. {
  2203. $this->_templates = array();
  2204. $this->_vars = array();
  2205. $this->_templateList = array();
  2206. }
  2207. /**
  2208. * get _all_ dependencies of a template,
  2209. * regardless of the subtemplates
  2210. *
  2211. * @access private
  2212. * @param string template name
  2213. * @return array list of all subtemplates
  2214. */
  2215. function _getDependencies( $template )
  2216. {
  2217. $deps = array();
  2218. if( isset( $this->_templates[$template]['dependencies'] ) )
  2219. $deps = $this->_templates[$template]['dependencies'];
  2220. if( isset( $this->_templates[$template]['subtemplates'] ) )
  2221. {
  2222. foreach( $this->_templates[$template]['subtemplates'] as $sub )
  2223. {
  2224. if( isset( $sub['dependencies'] ) )
  2225. $deps = array_merge( $deps, $sub['dependencies'] );
  2226. }
  2227. }
  2228. $deps = array_unique( $deps );
  2229. return $deps;
  2230. }
  2231. /**
  2232. * Displays useful information about all or named templates
  2233. *
  2234. * This method breaks BC, as it now awaits an array instead of
  2235. * unlimited parameters.
  2236. *
  2237. * @param mixed array of templates that should be dumped, or null if you
  2238. * want all templates to be dumped
  2239. * @param string dumper
  2240. * @access public
  2241. */
  2242. function dump( $restrict = null, $dumper = 'Html' )
  2243. {
  2244. if( is_string( $restrict ) )
  2245. $restrict = array( $restrict );
  2246. $dumper = &$this->loadModule( 'Dump', $dumper );
  2247. if( patErrorManager::isError( $dumper ) )
  2248. {
  2249. return $dumper;
  2250. }
  2251. if( is_null( $restrict ) )
  2252. {
  2253. $templates = $this->_templates;
  2254. $vars = $this->_vars;
  2255. }
  2256. else
  2257. {
  2258. $restrict = array_map( 'strtolower', $restrict );
  2259. $templates = array();
  2260. $vars = array();
  2261. foreach( $this->_templates as $name => $spec )
  2262. {
  2263. if( !in_array( $name, $restrict ) )
  2264. continue;
  2265. $templates[$name] = $spec;
  2266. $vars[$name] = $this->_vars[$name];
  2267. }
  2268. }
  2269. $dumper->displayHeader();
  2270. $dumper->dumpGlobals( $this->_globals );
  2271. $dumper->dumpTemplates( $templates, $vars );
  2272. $dumper->displayFooter();
  2273. return true;
  2274. }
  2275. /**
  2276. * get the include path
  2277. *
  2278. * @access public
  2279. * @return string
  2280. */
  2281. function getIncludePath()
  2282. {
  2283. return PATTEMPLATE_INCLUDE_PATH;
  2284. }
  2285. /**
  2286. * apply input filters that have been set
  2287. *
  2288. * This is being called by the readers.
  2289. *
  2290. * @access public
  2291. * @param string template
  2292. * @return string filtered templeta
  2293. */
  2294. function applyInputFilters( $template )
  2295. {
  2296. $cnt = count( $this->_inputFilters );
  2297. for( $i = 0; $i < $cnt; $i++ )
  2298. {
  2299. $template = $this->_inputFilters[$i]->apply( $template );
  2300. }
  2301. return $template;
  2302. }
  2303. /**
  2304. * checks, whether a placeholder exists in a template
  2305. *
  2306. * @access public
  2307. * @param string name of the placeholder
  2308. * @param string name of the template
  2309. * @param boolean whether to use the cached result of a previous call
  2310. */
  2311. function placeholderExists($placeholder, $tmpl, $cached = true)
  2312. {
  2313. $tmpl = strtolower($tmpl);
  2314. $placeholder = strtoupper($placeholder);
  2315. if (!$this->exists($tmpl)) {
  2316. return false;
  2317. }
  2318. if ($cached === true) {
  2319. if (isset($this->_discoveredPlaceholders[$tmpl]) && isset($this->_discoveredPlaceholders[$tmpl][$placeholder])) {
  2320. return $this->_discoveredPlaceholders[$tmpl][$placeholder];
  2321. }
  2322. }
  2323. if (isset($this->_templates[$tmpl]['subtemplates'])) {
  2324. $content = '';
  2325. foreach ($this->_templates[$tmpl]['subtemplates'] as $temp) {
  2326. if (!isset($temp['data'])) {
  2327. continue;
  2328. }
  2329. $content .= $temp['data'];
  2330. }
  2331. } else {
  2332. $content = $this->_templates[$tmpl]['content'];
  2333. }
  2334. $search = $this->_startTag . $placeholder . $this->_endTag;
  2335. if (strstr($content, $search) !== false) {
  2336. $this->_discoveredPlaceholders[$tmpl][$placeholder] = true;
  2337. return true;
  2338. }
  2339. $this->_discoveredPlaceholders[$tmpl][$placeholder] = false;
  2340. return false;
  2341. }
  2342. /**
  2343. * Convert the template to its string representation.
  2344. *
  2345. * This method allows you to just echo the patTemplate
  2346. * object in order to display the template.
  2347. *
  2348. * Requires PHP5
  2349. *
  2350. * <code>
  2351. * $tmpl = new patTemplate();
  2352. * $tmpl->readTemplatesFromFile( 'myfile.tmpl' );
  2353. * echo $tmpl;
  2354. * </code>
  2355. *
  2356. * @access private
  2357. * @return string
  2358. */
  2359. function __toString()
  2360. {
  2361. return $this->getParsedTemplate();
  2362. }
  2363. }
  2364. /**
  2365. * @package Joomla
  2366. */
  2367. class patFactory {
  2368. /**
  2369. * @param array An array of additional files to include from the root folder
  2370. * @return object
  2371. */
  2372. function &createTemplate( $files=null ) {
  2373. global $mainframe;
  2374. $tmpl = new patTemplate;
  2375. // patTemplate
  2376. if ($GLOBALS['mosConfig_caching']) {
  2377. $tmpl->useTemplateCache( 'File', array(
  2378. 'cacheFolder' => $GLOBALS['mosConfig_cachepath'], 'lifetime' => 20 ));
  2379. }
  2380. $tmpl->setNamespace( 'mos' );
  2381. // load the wrapper and common templates
  2382. $tmpl->setRoot( dirname( __FILE__ ) . '/tmpl' );
  2383. $tmpl->readTemplatesFromFile( 'page.html' );
  2384. $tmpl->applyInputFilter('ShortModifiers');
  2385. if (is_array( $files )) {
  2386. foreach ($files as $file) {
  2387. $tmpl->readTemplatesFromInput( $file );
  2388. }
  2389. }
  2390. //echo $this->basePath() . '/components/' . $option . '/tmpl';
  2391. $tmpl->addGlobalVar( 'option', $GLOBALS['option'] );
  2392. $tmpl->addGlobalVar( 'self', $_SERVER['PHP_SELF'] );
  2393. $tmpl->addGlobalVar( 'itemid', $GLOBALS['Itemid'] );
  2394. $tmpl->addGlobalVar( 'siteurl', $GLOBALS['mosConfig_live_site'] );
  2395. $tmpl->addGlobalVar( 'adminurl', $GLOBALS['mosConfig_live_site'] . '/administrator' );
  2396. $tmpl->addGlobalVar( 'templateurl', $GLOBALS['mosConfig_live_site'] . '/templates/' . $mainframe->getTemplate() );
  2397. $tmpl->addGlobalVar( 'admintemplateurl', $GLOBALS['mosConfig_live_site'] . '/administrator/templates/' . $mainframe->getTemplate() );
  2398. $tmpl->addGlobalVar( 'sitename', $GLOBALS['mosConfig_sitename'] );
  2399. $tmpl->addGlobalVar('treecss', 'dtree.css');
  2400. $tmpl->addGlobalVar('treeimgfolder', 'img');
  2401. $iso = split( '=', _ISO );
  2402. $tmpl->addGlobalVar( 'page_encoding', $iso[1] );
  2403. $tmpl->addGlobalVar( 'version_copyright', $GLOBALS['_VERSION']->COPYRIGHT );
  2404. $tmpl->addGlobalVar( 'version_url', $GLOBALS['_VERSION']->URL );
  2405. $tmpl->addVar( 'form', 'formAction', $_SERVER['PHP_SELF'] );
  2406. $tmpl->addVar( 'form', 'formName', 'adminForm' );
  2407. // tabs
  2408. $turl = $GLOBALS['mosConfig_live_site'] .'/includes/js/tabs/';
  2409. $tmpl->addVar( 'includeTabs', 'taburl', $turl );
  2410. return $tmpl;
  2411. }
  2412. }
  2413. ?>