patTemplate.php 59 KB

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