1 | <?php
|
---|
2 | //
|
---|
3 | // +----------------------------------------------------------------------+
|
---|
4 | // | Copyright (c) 1997-2005 Ulf Wendel, Pierre-Alain Joye |
|
---|
5 | // +----------------------------------------------------------------------+
|
---|
6 | // | This source file is subject to the New BSD license, That is bundled |
|
---|
7 | // | with this package in the file LICENSE, and is available through |
|
---|
8 | // | the world-wide-web at |
|
---|
9 | // | http://www.opensource.org/licenses/bsd-license.php |
|
---|
10 | // | If you did not receive a copy of the new BSDlicense and are unable |
|
---|
11 | // | to obtain it through the world-wide-web, please send a note to |
|
---|
12 | // | pajoye@php.net so we can mail you a copy immediately. |
|
---|
13 | // +----------------------------------------------------------------------+
|
---|
14 | // | Author: Ulf Wendel <ulf.wendel@phpdoc.de> |
|
---|
15 | // | Pierre-Alain Joye <pajoye@php.net> |
|
---|
16 | // +----------------------------------------------------------------------+
|
---|
17 | //
|
---|
18 | // $Id: IT.php,v 1.20 2006/08/17 15:47:22 dsp Exp $
|
---|
19 | //
|
---|
20 |
|
---|
21 | function_exists('tubepress_load_classes')
|
---|
22 | || require(dirname(__FILE__) . '/../../../../../tubepress_classloader.php');
|
---|
23 | tubepress_load_classes(array('net_php_pear_PEAR'));
|
---|
24 |
|
---|
25 | define('IT_OK', 1);
|
---|
26 | define('IT_ERROR', -1);
|
---|
27 | define('IT_TPL_NOT_FOUND', -2);
|
---|
28 | define('IT_BLOCK_NOT_FOUND', -3);
|
---|
29 | define('IT_BLOCK_DUPLICATE', -4);
|
---|
30 | define('IT_UNKNOWN_OPTION', -6);
|
---|
31 | /**
|
---|
32 | * Integrated Template - IT
|
---|
33 | *
|
---|
34 | * Well there's not much to say about it. I needed a template class that
|
---|
35 | * supports a single template file with multiple (nested) blocks inside and
|
---|
36 | * a simple block API.
|
---|
37 | *
|
---|
38 | * The Isotemplate API is somewhat tricky for a beginner although it is the best
|
---|
39 | * one you can build. template::parse() [phplib template = Isotemplate] requests
|
---|
40 | * you to name a source and a target where the current block gets parsed into.
|
---|
41 | * Source and target can be block names or even handler names. This API gives you
|
---|
42 | * a maximum of fexibility but you always have to know what you do which is
|
---|
43 | * quite unusual for php skripter like me.
|
---|
44 | *
|
---|
45 | * I noticed that I do not any control on which block gets parsed into which one.
|
---|
46 | * If all blocks are within one file, the script knows how they are nested and in
|
---|
47 | * which way you have to parse them. IT knows that inner1 is a child of block2, there's
|
---|
48 | * no need to tell him about this.
|
---|
49 | *
|
---|
50 | * <table border>
|
---|
51 | * <tr>
|
---|
52 | * <td colspan=2>
|
---|
53 | * __global__
|
---|
54 | * <p>
|
---|
55 | * (hidden and automatically added)
|
---|
56 | * </td>
|
---|
57 | * </tr>
|
---|
58 | * <tr>
|
---|
59 | * <td>block1</td>
|
---|
60 | * <td>
|
---|
61 | * <table border>
|
---|
62 | * <tr>
|
---|
63 | * <td colspan=2>block2</td>
|
---|
64 | * </tr>
|
---|
65 | * <tr>
|
---|
66 | * <td>inner1</td>
|
---|
67 | * <td>inner2</td>
|
---|
68 | * </tr>
|
---|
69 | * </table>
|
---|
70 | * </td>
|
---|
71 | * </tr>
|
---|
72 | * </table>
|
---|
73 | *
|
---|
74 | * To add content to block1 you simply type:
|
---|
75 | * <code>$tpl->setCurrentBlock("block1");</code>
|
---|
76 | * and repeat this as often as needed:
|
---|
77 | * <code>
|
---|
78 | * $tpl->setVariable(...);
|
---|
79 | * $tpl->parseCurrentBlock();
|
---|
80 | * </code>
|
---|
81 | *
|
---|
82 | * To add content to block2 you would type something like:
|
---|
83 | * <code>
|
---|
84 | * $tpl->setCurrentBlock("inner1");
|
---|
85 | * $tpl->setVariable(...);
|
---|
86 | * $tpl->parseCurrentBlock();
|
---|
87 | *
|
---|
88 | * $tpl->setVariable(...);
|
---|
89 | * $tpl->parseCurrentBlock();
|
---|
90 | *
|
---|
91 | * $tpl->parse("block1");
|
---|
92 | * </code>
|
---|
93 | *
|
---|
94 | * This will result in one repition of block1 which contains two repitions
|
---|
95 | * of inner1. inner2 will be removed if $removeEmptyBlock is set to true which is the default.
|
---|
96 | *
|
---|
97 | * Usage:
|
---|
98 | * <code>
|
---|
99 | * $tpl = new HTML_Template_IT( [string filerootdir] );
|
---|
100 | *
|
---|
101 | * // load a template or set it with setTemplate()
|
---|
102 | * $tpl->loadTemplatefile( string filename [, boolean removeUnknownVariables, boolean removeEmptyBlocks] )
|
---|
103 | *
|
---|
104 | * // set "global" Variables meaning variables not beeing within a (inner) block
|
---|
105 | * $tpl->setVariable( string variablename, mixed value );
|
---|
106 | *
|
---|
107 | * // like with the Isotemplates there's a second way to use setVariable()
|
---|
108 | * $tpl->setVariable( array ( string varname => mixed value ) );
|
---|
109 | *
|
---|
110 | * // Let's use any block, even a deeply nested one
|
---|
111 | * $tpl->setCurrentBlock( string blockname );
|
---|
112 | *
|
---|
113 | * // repeat this as often as you need it.
|
---|
114 | * $tpl->setVariable( array ( string varname => mixed value ) );
|
---|
115 | * $tpl->parseCurrentBlock();
|
---|
116 | *
|
---|
117 | * // get the parsed template or print it: $tpl->show()
|
---|
118 | * $tpl->get();
|
---|
119 | * </code>
|
---|
120 | *
|
---|
121 | * @author Ulf Wendel <uw@netuse.de>
|
---|
122 | * @version $Id: IT.php,v 1.20 2006/08/17 15:47:22 dsp Exp $
|
---|
123 | * @access public
|
---|
124 | * @package HTML_Template_IT
|
---|
125 | */
|
---|
126 | class net_php_pear_HTML_Template_IT
|
---|
127 | {
|
---|
128 | /**
|
---|
129 | * Contains the error objects
|
---|
130 | * @var array
|
---|
131 | * @access public
|
---|
132 | * @see halt(), $printError, $haltOnError
|
---|
133 | */
|
---|
134 | var $err = array();
|
---|
135 |
|
---|
136 | /**
|
---|
137 | * Clear cache on get()?
|
---|
138 | * @var boolean
|
---|
139 | */
|
---|
140 | var $clearCache = false;
|
---|
141 |
|
---|
142 | /**
|
---|
143 | * First character of a variable placeholder ( _{_VARIABLE} ).
|
---|
144 | * @var string
|
---|
145 | * @access public
|
---|
146 | * @see $closingDelimiter, $blocknameRegExp, $variablenameRegExp
|
---|
147 | */
|
---|
148 | var $openingDelimiter = '{';
|
---|
149 |
|
---|
150 | /**
|
---|
151 | * Last character of a variable placeholder ( {VARIABLE_}_ ).
|
---|
152 | * @var string
|
---|
153 | * @access public
|
---|
154 | * @see $openingDelimiter, $blocknameRegExp, $variablenameRegExp
|
---|
155 | */
|
---|
156 | var $closingDelimiter = '}';
|
---|
157 |
|
---|
158 | /**
|
---|
159 | * RegExp matching a block in the template.
|
---|
160 | * Per default "sm" is used as the regexp modifier, "i" is missing.
|
---|
161 | * That means a case sensitive search is done.
|
---|
162 | * @var string
|
---|
163 | * @access public
|
---|
164 | * @see $variablenameRegExp, $openingDelimiter, $closingDelimiter
|
---|
165 | */
|
---|
166 | var $blocknameRegExp = '[\.0-9A-Za-z_-]+';
|
---|
167 |
|
---|
168 | /**
|
---|
169 | * RegExp matching a variable placeholder in the template.
|
---|
170 | * Per default "sm" is used as the regexp modifier, "i" is missing.
|
---|
171 | * That means a case sensitive search is done.
|
---|
172 | * @var string
|
---|
173 | * @access public
|
---|
174 | * @see $blocknameRegExp, $openingDelimiter, $closingDelimiter
|
---|
175 | */
|
---|
176 | var $variablenameRegExp = '[\.0-9A-Za-z_-]+';
|
---|
177 |
|
---|
178 | /**
|
---|
179 | * RegExp used to find variable placeholder, filled by the constructor.
|
---|
180 | * @var string Looks somewhat like @(delimiter varname delimiter)@
|
---|
181 | * @access public
|
---|
182 | * @see IntegratedTemplate()
|
---|
183 | */
|
---|
184 | var $variablesRegExp = '';
|
---|
185 |
|
---|
186 | /**
|
---|
187 | * RegExp used to strip unused variable placeholder.
|
---|
188 | * @brother $variablesRegExp
|
---|
189 | */
|
---|
190 | var $removeVariablesRegExp = '';
|
---|
191 |
|
---|
192 | /**
|
---|
193 | * Controls the handling of unknown variables, default is remove.
|
---|
194 | * @var boolean
|
---|
195 | * @access public
|
---|
196 | */
|
---|
197 | var $removeUnknownVariables = true;
|
---|
198 |
|
---|
199 | /**
|
---|
200 | * Controls the handling of empty blocks, default is remove.
|
---|
201 | * @var boolean
|
---|
202 | * @access public
|
---|
203 | */
|
---|
204 | var $removeEmptyBlocks = true;
|
---|
205 |
|
---|
206 | /**
|
---|
207 | * RegExp used to find blocks an their content, filled by the constructor.
|
---|
208 | * @var string
|
---|
209 | * @see IntegratedTemplate()
|
---|
210 | */
|
---|
211 | var $blockRegExp = '';
|
---|
212 |
|
---|
213 | /**
|
---|
214 | * Name of the current block.
|
---|
215 | * @var string
|
---|
216 | */
|
---|
217 | var $currentBlock = '__global__';
|
---|
218 |
|
---|
219 | /**
|
---|
220 | * Content of the template.
|
---|
221 | * @var string
|
---|
222 | */
|
---|
223 | var $template = '';
|
---|
224 |
|
---|
225 | /**
|
---|
226 | * Array of all blocks and their content.
|
---|
227 | *
|
---|
228 | * @var array
|
---|
229 | * @see findBlocks()
|
---|
230 | */
|
---|
231 | var $blocklist = array();
|
---|
232 |
|
---|
233 | /**
|
---|
234 | * Array with the parsed content of a block.
|
---|
235 | *
|
---|
236 | * @var array
|
---|
237 | */
|
---|
238 | var $blockdata = array();
|
---|
239 |
|
---|
240 | /**
|
---|
241 | * Array of variables in a block.
|
---|
242 | * @var array
|
---|
243 | */
|
---|
244 | var $blockvariables = array();
|
---|
245 |
|
---|
246 | /**
|
---|
247 | * Array of inner blocks of a block.
|
---|
248 | * @var array
|
---|
249 | */
|
---|
250 | var $blockinner = array();
|
---|
251 |
|
---|
252 | /**
|
---|
253 | * List of blocks to preverse even if they are "empty".
|
---|
254 | *
|
---|
255 | * This is something special. Sometimes you have blocks that
|
---|
256 | * should be preserved although they are empty (no placeholder replaced).
|
---|
257 | * Think of a shopping basket. If it's empty you have to drop a message to
|
---|
258 | * the user. If it's filled you have to show the contents of
|
---|
259 | * the shopping baseket. Now where do you place the message that the basket
|
---|
260 | * is empty? It's no good idea to place it in you applications as customers
|
---|
261 | * tend to like unecessary minor text changes. Having another template file
|
---|
262 | * for an empty basket means that it's very likely that one fine day
|
---|
263 | * the filled and empty basket templates have different layout. I decided
|
---|
264 | * to introduce blocks that to not contain any placeholder but only
|
---|
265 | * text such as the message "Your shopping basked is empty".
|
---|
266 | *
|
---|
267 | * Now if there is no replacement done in such a block the block will
|
---|
268 | * be recognized as "empty" and by default ($removeEmptyBlocks = true) be
|
---|
269 | * stripped off. To avoid thisyou can now call touchBlock() to avoid this.
|
---|
270 | *
|
---|
271 | * The array $touchedBlocks stores a list of touched block which must not
|
---|
272 | * be removed even if they are empty.
|
---|
273 | *
|
---|
274 | * @var array $touchedBlocks
|
---|
275 | * @see touchBlock(), $removeEmptyBlocks
|
---|
276 | */
|
---|
277 | var $touchedBlocks = array();
|
---|
278 |
|
---|
279 | /**
|
---|
280 | * List of blocks which should not be shown even if not "empty"
|
---|
281 | * @var array $_hiddenBlocks
|
---|
282 | * @see hideBlock(), $removeEmptyBlocks
|
---|
283 | */
|
---|
284 | var $_hiddenBlocks = array();
|
---|
285 |
|
---|
286 | /**
|
---|
287 | * Variable cache.
|
---|
288 | *
|
---|
289 | * Variables get cached before any replacement is done.
|
---|
290 | * Advantage: empty blocks can be removed automatically.
|
---|
291 | * Disadvantage: might take some more memory
|
---|
292 | *
|
---|
293 | * @var array
|
---|
294 | * @see setVariable(), $clearCacheOnParse
|
---|
295 | */
|
---|
296 | var $variableCache = array();
|
---|
297 |
|
---|
298 | /**
|
---|
299 | * Clear the variable cache on parse?
|
---|
300 | *
|
---|
301 | * If you're not an expert just leave the default false.
|
---|
302 | * True reduces memory consumption somewhat if you tend to
|
---|
303 | * add lots of values for unknown placeholder.
|
---|
304 | *
|
---|
305 | * @var boolean
|
---|
306 | */
|
---|
307 | var $clearCacheOnParse = false;
|
---|
308 |
|
---|
309 | /**
|
---|
310 | * Root directory for all file operations.
|
---|
311 | * The string gets prefixed to all filenames given.
|
---|
312 | * @var string
|
---|
313 | * @see HTML_Template_IT(), setRoot()
|
---|
314 | */
|
---|
315 | var $fileRoot = '';
|
---|
316 |
|
---|
317 | /**
|
---|
318 | * Internal flag indicating that a blockname was used multiple times.
|
---|
319 | * @var boolean
|
---|
320 | */
|
---|
321 | var $flagBlocktrouble = false;
|
---|
322 |
|
---|
323 | /**
|
---|
324 | * Flag indicating that the global block was parsed.
|
---|
325 | * @var boolean
|
---|
326 | */
|
---|
327 | var $flagGlobalParsed = false;
|
---|
328 |
|
---|
329 | /**
|
---|
330 | * EXPERIMENTAL! FIXME!
|
---|
331 | * Flag indication that a template gets cached.
|
---|
332 | *
|
---|
333 | * Complex templates require some times to be preparsed
|
---|
334 | * before the replacement can take place. Often I use
|
---|
335 | * one template file over and over again but I don't know
|
---|
336 | * before that I will use the same template file again.
|
---|
337 | * Now IT could notice this and skip the preparse.
|
---|
338 | *
|
---|
339 | * @var boolean
|
---|
340 | */
|
---|
341 | var $flagCacheTemplatefile = true;
|
---|
342 |
|
---|
343 | /**
|
---|
344 | * EXPERIMENTAL! FIXME!
|
---|
345 | */
|
---|
346 | var $lastTemplatefile = '';
|
---|
347 |
|
---|
348 | /**
|
---|
349 | * $_options['preserve_data'] Whether to substitute variables and remove
|
---|
350 | * empty placeholders in data passed through setVariable
|
---|
351 | * (see also bugs #20199, #21951).
|
---|
352 | * $_options['use_preg'] Whether to use preg_replace instead of
|
---|
353 | * str_replace in parse()
|
---|
354 | * (this is a backwards compatibility feature, see also bugs #21951, #20392)
|
---|
355 | */
|
---|
356 | var $_options = array(
|
---|
357 | 'preserve_data' => false,
|
---|
358 | 'use_preg' => true
|
---|
359 | );
|
---|
360 |
|
---|
361 | /**
|
---|
362 | * Builds some complex regular expressions and optinally sets the
|
---|
363 | * file root directory.
|
---|
364 | *
|
---|
365 | * Make sure that you call this constructor if you derive your template
|
---|
366 | * class from this one.
|
---|
367 | *
|
---|
368 | * @param string File root directory, prefix for all filenames
|
---|
369 | * given to the object.
|
---|
370 | * @see setRoot()
|
---|
371 | */
|
---|
372 | function net_php_pear_HTML_Template_IT($root = '', $options = null)
|
---|
373 | {
|
---|
374 | if (!is_null($options)) {
|
---|
375 | $this->setOptions($options);
|
---|
376 | }
|
---|
377 | $this->variablesRegExp = '@' . $this->openingDelimiter .
|
---|
378 | '(' . $this->variablenameRegExp . ')' .
|
---|
379 | $this->closingDelimiter . '@sm';
|
---|
380 | $this->removeVariablesRegExp = '@' . $this->openingDelimiter .
|
---|
381 | "\s*(" . $this->variablenameRegExp .
|
---|
382 | ")\s*" . $this->closingDelimiter .'@sm';
|
---|
383 |
|
---|
384 | $this->blockRegExp = '@<!--\s+BEGIN\s+(' . $this->blocknameRegExp .
|
---|
385 | ')\s+-->(.*)<!--\s+END\s+\1\s+-->@sm';
|
---|
386 |
|
---|
387 | $this->setRoot($root);
|
---|
388 | } // end constructor
|
---|
389 |
|
---|
390 |
|
---|
391 | /**
|
---|
392 | * Sets the option for the template class
|
---|
393 | *
|
---|
394 | * @access public
|
---|
395 | * @param string option name
|
---|
396 | * @param mixed option value
|
---|
397 | * @return mixed IT_OK on success, error object on failure
|
---|
398 | */
|
---|
399 | function setOption($option, $value)
|
---|
400 | {
|
---|
401 | if (array_key_exists($option, $this->_options)) {
|
---|
402 | $this->_options[$option] = $value;
|
---|
403 | return IT_OK;
|
---|
404 | }
|
---|
405 |
|
---|
406 | throw new Exception(
|
---|
407 | $this->errorMessage(IT_UNKNOWN_OPTION) . ": '{$option}'",
|
---|
408 | IT_UNKNOWN_OPTION
|
---|
409 | );
|
---|
410 | }
|
---|
411 |
|
---|
412 | /**
|
---|
413 | * Sets the options for the template class
|
---|
414 | *
|
---|
415 | * @access public
|
---|
416 | * @param string options array of options
|
---|
417 | * default value:
|
---|
418 | * 'preserve_data' => false,
|
---|
419 | * 'use_preg' => true
|
---|
420 | * @param mixed option value
|
---|
421 | * @return mixed IT_OK on success, error object on failure
|
---|
422 | * @see $options
|
---|
423 | */
|
---|
424 | function setOptions($options)
|
---|
425 | {
|
---|
426 | if (is_array($options)) {
|
---|
427 | foreach ($options as $option => $value) {
|
---|
428 | $error = $this->setOption($option, $value);
|
---|
429 | if (net_php_pear_PEAR::isError($error)) {
|
---|
430 | return $error;
|
---|
431 | }
|
---|
432 | }
|
---|
433 | }
|
---|
434 |
|
---|
435 | return IT_OK;
|
---|
436 | }
|
---|
437 |
|
---|
438 | /**
|
---|
439 | * Print a certain block with all replacements done.
|
---|
440 | * @brother get()
|
---|
441 | */
|
---|
442 | function show($block = '__global__')
|
---|
443 | {
|
---|
444 | print $this->get($block);
|
---|
445 | } // end func show
|
---|
446 |
|
---|
447 | /**
|
---|
448 | * Returns a block with all replacements done.
|
---|
449 | *
|
---|
450 | * @param string name of the block
|
---|
451 | * @return string
|
---|
452 | * @throws PEAR_Error
|
---|
453 | * @access public
|
---|
454 | * @see show()
|
---|
455 | */
|
---|
456 | function get($block = '__global__')
|
---|
457 | {
|
---|
458 | if ($block == '__global__' && !$this->flagGlobalParsed) {
|
---|
459 | $this->parse('__global__');
|
---|
460 | }
|
---|
461 |
|
---|
462 | if (!isset($this->blocklist[$block])) {
|
---|
463 | $this->err[] = net_php_pear_PEAR::raiseError(
|
---|
464 | $this->errorMessage(IT_BLOCK_NOT_FOUND) .
|
---|
465 | '"' . $block . "'",
|
---|
466 | IT_BLOCK_NOT_FOUND
|
---|
467 | );
|
---|
468 | return '';
|
---|
469 | }
|
---|
470 |
|
---|
471 | if (isset($this->blockdata[$block])) {
|
---|
472 | $ret = $this->blockdata[$block];
|
---|
473 | if ($this->clearCache) {
|
---|
474 | unset($this->blockdata[$block]);
|
---|
475 | }
|
---|
476 | if ($this->_options['preserve_data']) {
|
---|
477 | $ret = str_replace(
|
---|
478 | $this->openingDelimiter .
|
---|
479 | '%preserved%' . $this->closingDelimiter,
|
---|
480 | $this->openingDelimiter,
|
---|
481 | $ret
|
---|
482 | );
|
---|
483 | }
|
---|
484 | return $ret;
|
---|
485 | }
|
---|
486 |
|
---|
487 | return '';
|
---|
488 | } // end func get()
|
---|
489 |
|
---|
490 | /**
|
---|
491 | * Parses the given block.
|
---|
492 | *
|
---|
493 | * @param string name of the block to be parsed
|
---|
494 | * @access public
|
---|
495 | * @see parseCurrentBlock()
|
---|
496 | * @throws PEAR_Error
|
---|
497 | */
|
---|
498 | function parse($block = '__global__', $flag_recursion = false)
|
---|
499 | {
|
---|
500 | static $regs, $values;
|
---|
501 |
|
---|
502 | if (!isset($this->blocklist[$block])) {
|
---|
503 | throw new Exception(
|
---|
504 | $this->errorMessage( IT_BLOCK_NOT_FOUND ) . '"' . $block . "'",
|
---|
505 | IT_BLOCK_NOT_FOUND
|
---|
506 | );
|
---|
507 | }
|
---|
508 |
|
---|
509 | if ($block == '__global__') {
|
---|
510 | $this->flagGlobalParsed = true;
|
---|
511 | }
|
---|
512 |
|
---|
513 | if (!$flag_recursion) {
|
---|
514 | $regs = array();
|
---|
515 | $values = array();
|
---|
516 | }
|
---|
517 | $outer = $this->blocklist[$block];
|
---|
518 | $empty = true;
|
---|
519 |
|
---|
520 | if ($this->clearCacheOnParse) {
|
---|
521 | foreach ($this->variableCache as $name => $value) {
|
---|
522 | $regs[] = $this->openingDelimiter .
|
---|
523 | $name . $this->closingDelimiter;
|
---|
524 | $values[] = $value;
|
---|
525 | $empty = false;
|
---|
526 | }
|
---|
527 | $this->variableCache = array();
|
---|
528 | } else {
|
---|
529 | foreach ($this->blockvariables[$block] as $allowedvar => $v) {
|
---|
530 |
|
---|
531 | if (isset($this->variableCache[$allowedvar])) {
|
---|
532 | $regs[] = $this->openingDelimiter .
|
---|
533 | $allowedvar . $this->closingDelimiter;
|
---|
534 | $values[] = $this->variableCache[$allowedvar];
|
---|
535 | unset($this->variableCache[$allowedvar]);
|
---|
536 | $empty = false;
|
---|
537 | }
|
---|
538 | }
|
---|
539 | }
|
---|
540 |
|
---|
541 | if (isset($this->blockinner[$block])) {
|
---|
542 | foreach ($this->blockinner[$block] as $k => $innerblock) {
|
---|
543 |
|
---|
544 | $this->parse($innerblock, true);
|
---|
545 | if ($this->blockdata[$innerblock] != '') {
|
---|
546 | $empty = false;
|
---|
547 | }
|
---|
548 |
|
---|
549 | $placeholder = $this->openingDelimiter . "__" .
|
---|
550 | $innerblock . "__" . $this->closingDelimiter;
|
---|
551 | $outer = str_replace(
|
---|
552 | $placeholder,
|
---|
553 | $this->blockdata[$innerblock], $outer
|
---|
554 | );
|
---|
555 | $this->blockdata[$innerblock] = "";
|
---|
556 | }
|
---|
557 |
|
---|
558 | }
|
---|
559 |
|
---|
560 | if (!$flag_recursion && 0 != count($values)) {
|
---|
561 | if ($this->_options['use_preg']) {
|
---|
562 | $regs = array_map(array(
|
---|
563 | &$this, '_addPregDelimiters'),
|
---|
564 | $regs
|
---|
565 | );
|
---|
566 | $funcReplace = 'preg_replace';
|
---|
567 | } else {
|
---|
568 | $funcReplace = 'str_replace';
|
---|
569 | }
|
---|
570 |
|
---|
571 | if ($this->_options['preserve_data']) {
|
---|
572 | $values = array_map(
|
---|
573 | array(&$this, '_preserveOpeningDelimiter'), $values
|
---|
574 | );
|
---|
575 | }
|
---|
576 |
|
---|
577 | $outer = $funcReplace($regs, $values, $outer);
|
---|
578 |
|
---|
579 | if ($this->removeUnknownVariables) {
|
---|
580 | $outer = preg_replace($this->removeVariablesRegExp, "", $outer);
|
---|
581 | }
|
---|
582 | }
|
---|
583 |
|
---|
584 | if ($empty) {
|
---|
585 | if (!$this->removeEmptyBlocks) {
|
---|
586 | $this->blockdata[$block ].= $outer;
|
---|
587 | } else {
|
---|
588 | if (isset($this->touchedBlocks[$block])) {
|
---|
589 | $this->blockdata[$block] .= $outer;
|
---|
590 | unset($this->touchedBlocks[$block]);
|
---|
591 | }
|
---|
592 | }
|
---|
593 | } else {
|
---|
594 | if (empty($this->blockdata[$block])) {
|
---|
595 | $this->blockdata[$block] = $outer;
|
---|
596 | } else {
|
---|
597 | $this->blockdata[$block] .= $outer;
|
---|
598 | }
|
---|
599 | }
|
---|
600 |
|
---|
601 | return $empty;
|
---|
602 | } // end func parse
|
---|
603 |
|
---|
604 | /**
|
---|
605 | * Parses the current block
|
---|
606 | * @see parse(), setCurrentBlock(), $currentBlock
|
---|
607 | * @access public
|
---|
608 | */
|
---|
609 | function parseCurrentBlock()
|
---|
610 | {
|
---|
611 | return $this->parse($this->currentBlock);
|
---|
612 | } // end func parseCurrentBlock
|
---|
613 |
|
---|
614 | /**
|
---|
615 | * Sets a variable value.
|
---|
616 | *
|
---|
617 | * The function can be used eighter like setVariable( "varname", "value")
|
---|
618 | * or with one array $variables["varname"] = "value"
|
---|
619 | * given setVariable($variables) quite like phplib templates set_var().
|
---|
620 | *
|
---|
621 | * @param mixed string with the variable name or an array
|
---|
622 | * %variables["varname"] = "value"
|
---|
623 | * @param string value of the variable or empty if $variable
|
---|
624 | * is an array.
|
---|
625 | * @param string prefix for variable names
|
---|
626 | * @access public
|
---|
627 | */
|
---|
628 | function setVariable($variable, $value = '')
|
---|
629 | {
|
---|
630 | if (is_array($variable)) {
|
---|
631 | $this->variableCache = array_merge(
|
---|
632 | $this->variableCache, $variable
|
---|
633 | );
|
---|
634 | } else {
|
---|
635 | $this->variableCache[$variable] = $value;
|
---|
636 | }
|
---|
637 | } // end func setVariable
|
---|
638 |
|
---|
639 | /**
|
---|
640 | * Sets the name of the current block that is the block where variables
|
---|
641 | * are added.
|
---|
642 | *
|
---|
643 | * @param string name of the block
|
---|
644 | * @return boolean false on failure, otherwise true
|
---|
645 | * @throws PEAR_Error
|
---|
646 | * @access public
|
---|
647 | */
|
---|
648 | function setCurrentBlock($block = '__global__')
|
---|
649 | {
|
---|
650 |
|
---|
651 | if (!isset($this->blocklist[$block])) {
|
---|
652 | throw new Exception(
|
---|
653 | $this->errorMessage( IT_BLOCK_NOT_FOUND ) .
|
---|
654 | '"' . $block . "'", IT_BLOCK_NOT_FOUND
|
---|
655 | );
|
---|
656 | }
|
---|
657 |
|
---|
658 | $this->currentBlock = $block;
|
---|
659 |
|
---|
660 | return true;
|
---|
661 | } // end func setCurrentBlock
|
---|
662 |
|
---|
663 | /**
|
---|
664 | * Preserves an empty block even if removeEmptyBlocks is true.
|
---|
665 | *
|
---|
666 | * @param string name of the block
|
---|
667 | * @return boolean false on false, otherwise true
|
---|
668 | * @throws PEAR_Error
|
---|
669 | * @access public
|
---|
670 | * @see $removeEmptyBlocks
|
---|
671 | */
|
---|
672 | function touchBlock($block)
|
---|
673 | {
|
---|
674 | if (!isset($this->blocklist[$block])) {
|
---|
675 | throw new Exception(
|
---|
676 | $this->errorMessage(IT_BLOCK_NOT_FOUND) .
|
---|
677 | '"' . $block . "'", IT_BLOCK_NOT_FOUND);
|
---|
678 | }
|
---|
679 |
|
---|
680 | $this->touchedBlocks[$block] = true;
|
---|
681 |
|
---|
682 | return true;
|
---|
683 | } // end func touchBlock
|
---|
684 |
|
---|
685 | /**
|
---|
686 | * Clears all datafields of the object and rebuild the internal blocklist
|
---|
687 | *
|
---|
688 | * LoadTemplatefile() and setTemplate() automatically call this function
|
---|
689 | * when a new template is given. Don't use this function
|
---|
690 | * unless you know what you're doing.
|
---|
691 | *
|
---|
692 | * @access public
|
---|
693 | * @see free()
|
---|
694 | */
|
---|
695 | function init()
|
---|
696 | {
|
---|
697 | $this->free();
|
---|
698 | $this->findBlocks($this->template);
|
---|
699 | // we don't need it any more
|
---|
700 | $this->template = '';
|
---|
701 | $this->buildBlockvariablelist();
|
---|
702 | } // end func init
|
---|
703 |
|
---|
704 | /**
|
---|
705 | * Clears all datafields of the object.
|
---|
706 | *
|
---|
707 | * Don't use this function unless you know what you're doing.
|
---|
708 | *
|
---|
709 | * @access public
|
---|
710 | * @see init()
|
---|
711 | */
|
---|
712 | function free()
|
---|
713 | {
|
---|
714 | $this->err = array();
|
---|
715 |
|
---|
716 | $this->currentBlock = '__global__';
|
---|
717 |
|
---|
718 | $this->variableCache = array();
|
---|
719 | $this->blocklist = array();
|
---|
720 | $this->touchedBlocks = array();
|
---|
721 |
|
---|
722 | $this->flagBlocktrouble = false;
|
---|
723 | $this->flagGlobalParsed = false;
|
---|
724 | } // end func free
|
---|
725 |
|
---|
726 | /**
|
---|
727 | * Sets the template.
|
---|
728 | *
|
---|
729 | * You can eighter load a template file from disk with
|
---|
730 | * LoadTemplatefile() or set the template manually using this function.
|
---|
731 | *
|
---|
732 | * @param string template content
|
---|
733 | * @param boolean remove unknown/unused variables?
|
---|
734 | * @param boolean remove empty blocks?
|
---|
735 | * @see LoadTemplatefile(), $template
|
---|
736 | * @access public
|
---|
737 | * @return boolean
|
---|
738 | */
|
---|
739 | function setTemplate( $template, $removeUnknownVariables = true,
|
---|
740 | $removeEmptyBlocks = true)
|
---|
741 | {
|
---|
742 | $this->removeUnknownVariables = $removeUnknownVariables;
|
---|
743 | $this->removeEmptyBlocks = $removeEmptyBlocks;
|
---|
744 |
|
---|
745 | if ($template == '' && $this->flagCacheTemplatefile) {
|
---|
746 | $this->variableCache = array();
|
---|
747 | $this->blockdata = array();
|
---|
748 | $this->touchedBlocks = array();
|
---|
749 | $this->currentBlock = '__global__';
|
---|
750 | } else {
|
---|
751 | $this->template = '<!-- BEGIN __global__ -->' . $template .
|
---|
752 | '<!-- END __global__ -->';
|
---|
753 | $this->init();
|
---|
754 | }
|
---|
755 |
|
---|
756 | if ($this->flagBlocktrouble) {
|
---|
757 | return false;
|
---|
758 | }
|
---|
759 |
|
---|
760 | return true;
|
---|
761 | } // end func setTemplate
|
---|
762 |
|
---|
763 | /**
|
---|
764 | * Reads a template file from the disk.
|
---|
765 | *
|
---|
766 | * @param string name of the template file
|
---|
767 | * @param bool how to handle unknown variables.
|
---|
768 | * @param bool how to handle empty blocks.
|
---|
769 | * @access public
|
---|
770 | * @return boolean false on failure, otherwise true
|
---|
771 | * @see $template, setTemplate(), $removeUnknownVariables,
|
---|
772 | * $removeEmptyBlocks
|
---|
773 | */
|
---|
774 | function loadTemplatefile( $filename,
|
---|
775 | $removeUnknownVariables = true,
|
---|
776 | $removeEmptyBlocks = true )
|
---|
777 | {
|
---|
778 | $template = '';
|
---|
779 | if (!$this->flagCacheTemplatefile ||
|
---|
780 | $this->lastTemplatefile != $filename
|
---|
781 | ) {
|
---|
782 | $template = $this->getFile($filename);
|
---|
783 | }
|
---|
784 | $this->lastTemplatefile = $filename;
|
---|
785 |
|
---|
786 | return $template != '' ?
|
---|
787 | $this->setTemplate(
|
---|
788 | $template,$removeUnknownVariables, $removeEmptyBlocks
|
---|
789 | ) : false;
|
---|
790 | } // end func LoadTemplatefile
|
---|
791 |
|
---|
792 | /**
|
---|
793 | * Sets the file root. The file root gets prefixed to all filenames passed
|
---|
794 | * to the object.
|
---|
795 | *
|
---|
796 | * Make sure that you override this function when using the class
|
---|
797 | * on windows.
|
---|
798 | *
|
---|
799 | * @param string
|
---|
800 | * @see HTML_Template_IT()
|
---|
801 | * @access public
|
---|
802 | */
|
---|
803 | function setRoot($root)
|
---|
804 | {
|
---|
805 | if ($root != '' && substr($root, -1) != '/') {
|
---|
806 | $root .= '/';
|
---|
807 | }
|
---|
808 |
|
---|
809 | $this->fileRoot = $root;
|
---|
810 | } // end func setRoot
|
---|
811 |
|
---|
812 | /**
|
---|
813 | * Build a list of all variables within of a block
|
---|
814 | */
|
---|
815 | function buildBlockvariablelist()
|
---|
816 | {
|
---|
817 | foreach ($this->blocklist as $name => $content) {
|
---|
818 | preg_match_all($this->variablesRegExp, $content, $regs);
|
---|
819 |
|
---|
820 | if (count($regs[1]) != 0) {
|
---|
821 | foreach ($regs[1] as $k => $var) {
|
---|
822 | $this->blockvariables[$name][$var] = true;
|
---|
823 | }
|
---|
824 | } else {
|
---|
825 | $this->blockvariables[$name] = array();
|
---|
826 | }
|
---|
827 | }
|
---|
828 | } // end func buildBlockvariablelist
|
---|
829 |
|
---|
830 | /**
|
---|
831 | * Returns a list of all global variables
|
---|
832 | */
|
---|
833 | function getGlobalvariables()
|
---|
834 | {
|
---|
835 | $regs = array();
|
---|
836 | $values = array();
|
---|
837 |
|
---|
838 | foreach ($this->blockvariables['__global__'] as $allowedvar => $v) {
|
---|
839 | if (isset($this->variableCache[$allowedvar])) {
|
---|
840 | $regs[] = '@' . $this->openingDelimiter .
|
---|
841 | $allowedvar . $this->closingDelimiter . '@';
|
---|
842 | $values[] = $this->variableCache[$allowedvar];
|
---|
843 | unset($this->variableCache[$allowedvar]);
|
---|
844 | }
|
---|
845 | }
|
---|
846 |
|
---|
847 | return array($regs, $values);
|
---|
848 | } // end func getGlobalvariables
|
---|
849 |
|
---|
850 | /**
|
---|
851 | * Recusively builds a list of all blocks within the template.
|
---|
852 | *
|
---|
853 | * @param string string that gets scanned
|
---|
854 | * @see $blocklist
|
---|
855 | */
|
---|
856 | function findBlocks($string)
|
---|
857 | {
|
---|
858 | $blocklist = array();
|
---|
859 |
|
---|
860 | if (preg_match_all($this->blockRegExp, $string, $regs, PREG_SET_ORDER)) {
|
---|
861 | foreach ($regs as $k => $match) {
|
---|
862 | $blockname = $match[1];
|
---|
863 | $blockcontent = $match[2];
|
---|
864 |
|
---|
865 | if (isset($this->blocklist[$blockname])) {
|
---|
866 | $this->err[] = net_php_pear_PEAR::raiseError(
|
---|
867 | $this->errorMessage(
|
---|
868 | IT_BLOCK_DUPLICATE, $blockname),
|
---|
869 | IT_BLOCK_DUPLICATE
|
---|
870 | );
|
---|
871 | $this->flagBlocktrouble = true;
|
---|
872 | }
|
---|
873 |
|
---|
874 | $this->blocklist[$blockname] = $blockcontent;
|
---|
875 | $this->blockdata[$blockname] = "";
|
---|
876 |
|
---|
877 | $blocklist[] = $blockname;
|
---|
878 |
|
---|
879 | $inner = $this->findBlocks($blockcontent);
|
---|
880 | foreach ($inner as $k => $name) {
|
---|
881 | $pattern = sprintf(
|
---|
882 | '@<!--\s+BEGIN\s+%s\s+-->(.*)<!--\s+END\s+%s\s+-->@sm',
|
---|
883 | $name,
|
---|
884 | $name
|
---|
885 | );
|
---|
886 |
|
---|
887 | $this->blocklist[$blockname] = preg_replace(
|
---|
888 | $pattern,
|
---|
889 | $this->openingDelimiter .
|
---|
890 | '__' . $name . '__' .
|
---|
891 | $this->closingDelimiter,
|
---|
892 | $this->blocklist[$blockname]
|
---|
893 | );
|
---|
894 | $this->blockinner[$blockname][] = $name;
|
---|
895 | $this->blockparents[$name] = $blockname;
|
---|
896 | }
|
---|
897 | }
|
---|
898 | }
|
---|
899 |
|
---|
900 | return $blocklist;
|
---|
901 | } // end func findBlocks
|
---|
902 |
|
---|
903 | /**
|
---|
904 | * Reads a file from disk and returns its content.
|
---|
905 | * @param string Filename
|
---|
906 | * @return string Filecontent
|
---|
907 | */
|
---|
908 | function getFile($filename)
|
---|
909 | {
|
---|
910 | if ($filename{0} == '/' && substr($this->fileRoot, -1) == '/') {
|
---|
911 | $filename = substr($filename, 1);
|
---|
912 | }
|
---|
913 |
|
---|
914 | $filename = $this->fileRoot . $filename;
|
---|
915 |
|
---|
916 | if (!($fh = @fopen($filename, 'r'))) {
|
---|
917 | $this->err[] = net_php_pear_PEAR::raiseError(
|
---|
918 | $this->errorMessage(IT_TPL_NOT_FOUND) .
|
---|
919 | ': "' .$filename .'"',
|
---|
920 | IT_TPL_NOT_FOUND
|
---|
921 | );
|
---|
922 | return "";
|
---|
923 | }
|
---|
924 |
|
---|
925 | $fsize = filesize($filename);
|
---|
926 | if ($fsize < 1) {
|
---|
927 | fclose($fh);
|
---|
928 | return '';
|
---|
929 | }
|
---|
930 |
|
---|
931 | $content = fread($fh, $fsize);
|
---|
932 | fclose($fh);
|
---|
933 |
|
---|
934 | return preg_replace(
|
---|
935 | "#<!-- INCLUDE (.*) -->#ime", "\$this->getFile('\\1')", $content
|
---|
936 | );
|
---|
937 | } // end func getFile
|
---|
938 |
|
---|
939 | /**
|
---|
940 | * Adds delimiters to a string, so it can be used as a pattern
|
---|
941 | * in preg_* functions
|
---|
942 | *
|
---|
943 | * @param string
|
---|
944 | * @return string
|
---|
945 | */
|
---|
946 | function _addPregDelimiters($str)
|
---|
947 | {
|
---|
948 | return '@' . $str . '@';
|
---|
949 | }
|
---|
950 |
|
---|
951 | /**
|
---|
952 | * Replaces an opening delimiter by a special string
|
---|
953 | *
|
---|
954 | * @param string
|
---|
955 | * @return string
|
---|
956 | */
|
---|
957 | function _preserveOpeningDelimiter($str)
|
---|
958 | {
|
---|
959 | return (false === strpos($str, $this->openingDelimiter))?
|
---|
960 | $str:
|
---|
961 | str_replace(
|
---|
962 | $this->openingDelimiter,
|
---|
963 | $this->openingDelimiter .
|
---|
964 | '%preserved%' . $this->closingDelimiter,
|
---|
965 | $str
|
---|
966 | );
|
---|
967 | }
|
---|
968 |
|
---|
969 | /**
|
---|
970 | * Return a textual error message for a IT error code
|
---|
971 | *
|
---|
972 | * @param integer $value error code
|
---|
973 | *
|
---|
974 | * @return string error message, or false if the error code was
|
---|
975 | * not recognized
|
---|
976 | */
|
---|
977 | function errorMessage($value, $blockname = '')
|
---|
978 | {
|
---|
979 | static $errorMessages;
|
---|
980 | if (!isset($errorMessages)) {
|
---|
981 | $errorMessages = array(
|
---|
982 | IT_OK => '',
|
---|
983 | IT_ERROR => 'unknown error',
|
---|
984 | IT_TPL_NOT_FOUND => 'Cannot read the template file',
|
---|
985 | IT_BLOCK_NOT_FOUND => 'Cannot find this block',
|
---|
986 | IT_BLOCK_DUPLICATE => 'The name of a block must be'.
|
---|
987 | ' uniquewithin a template.'.
|
---|
988 | ' Found "' . $blockname . '" twice.'.
|
---|
989 | 'Unpredictable results '.
|
---|
990 | 'may appear.',
|
---|
991 | IT_UNKNOWN_OPTION => 'Unknown option'
|
---|
992 | );
|
---|
993 | }
|
---|
994 |
|
---|
995 | if (net_php_pear_PEAR::isError($value)) {
|
---|
996 | $value = $value->getCode();
|
---|
997 | }
|
---|
998 |
|
---|
999 | return isset($errorMessages[$value]) ?
|
---|
1000 | $errorMessages[$value] : $errorMessages[IT_ERROR];
|
---|
1001 | }
|
---|
1002 | } // end class IntegratedTemplate
|
---|
1003 | ?>
|
---|