[44] | 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 | ?>
|
---|