From 91526147d9c8e2e039c56e0401cf5631027d8d8c Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Thu, 8 Mar 2018 14:15:34 +0100 Subject: [PATCH] Imported Upstream version 1.3.0 --- HTML_Template_IT-1.3.0/HTML/Template/IT.php | 1186 +++++++++++++++++ HTML_Template_IT-1.3.0/HTML/Template/ITX.php | 889 ++++++++++++ .../HTML/Template/IT_Error.php | 65 + HTML_Template_IT-1.3.0/LICENSE | 22 + HTML_Template_IT-1.3.0/examples/sample_it.php | 27 + .../examples/sample_itx_addblockfile.php | 58 + .../templates/addblockfile_list.tpl.htm | 6 + .../templates/addblockfile_main.tpl.htm | 12 + .../examples/templates/main.tpl.htm | 13 + HTML_Template_IT-1.3.0/tests/AllTests.php | 36 + HTML_Template_IT-1.3.0/tests/ITTest.php | 416 ++++++ HTML_Template_IT-1.3.0/tests/ITXTest.php | 171 +++ .../tests/templates/__include.html | 1 + .../tests/templates/addblock.html | 1 + .../tests/templates/blockiteration.html | 7 + .../tests/templates/blocks.html | 8 + .../tests/templates/bug_9853_01.tpl | 20 + .../tests/templates/bug_9853_02.tpl | 20 + .../tests/templates/globals.html | 13 + .../tests/templates/include.html | 1 + .../tests/templates/loadtemplatefile.html | 1 + .../placeholderreplacementscope.html | 8 + .../tests/templates/replaceblock.html | 5 + package.xml | 335 +++++ 24 files changed, 3321 insertions(+) create mode 100644 HTML_Template_IT-1.3.0/HTML/Template/IT.php create mode 100644 HTML_Template_IT-1.3.0/HTML/Template/ITX.php create mode 100644 HTML_Template_IT-1.3.0/HTML/Template/IT_Error.php create mode 100644 HTML_Template_IT-1.3.0/LICENSE create mode 100644 HTML_Template_IT-1.3.0/examples/sample_it.php create mode 100644 HTML_Template_IT-1.3.0/examples/sample_itx_addblockfile.php create mode 100644 HTML_Template_IT-1.3.0/examples/templates/addblockfile_list.tpl.htm create mode 100644 HTML_Template_IT-1.3.0/examples/templates/addblockfile_main.tpl.htm create mode 100644 HTML_Template_IT-1.3.0/examples/templates/main.tpl.htm create mode 100644 HTML_Template_IT-1.3.0/tests/AllTests.php create mode 100644 HTML_Template_IT-1.3.0/tests/ITTest.php create mode 100644 HTML_Template_IT-1.3.0/tests/ITXTest.php create mode 100644 HTML_Template_IT-1.3.0/tests/templates/__include.html create mode 100644 HTML_Template_IT-1.3.0/tests/templates/addblock.html create mode 100644 HTML_Template_IT-1.3.0/tests/templates/blockiteration.html create mode 100644 HTML_Template_IT-1.3.0/tests/templates/blocks.html create mode 100644 HTML_Template_IT-1.3.0/tests/templates/bug_9853_01.tpl create mode 100644 HTML_Template_IT-1.3.0/tests/templates/bug_9853_02.tpl create mode 100644 HTML_Template_IT-1.3.0/tests/templates/globals.html create mode 100644 HTML_Template_IT-1.3.0/tests/templates/include.html create mode 100644 HTML_Template_IT-1.3.0/tests/templates/loadtemplatefile.html create mode 100644 HTML_Template_IT-1.3.0/tests/templates/placeholderreplacementscope.html create mode 100644 HTML_Template_IT-1.3.0/tests/templates/replaceblock.html create mode 100644 package.xml diff --git a/HTML_Template_IT-1.3.0/HTML/Template/IT.php b/HTML_Template_IT-1.3.0/HTML/Template/IT.php new file mode 100644 index 0000000..c32f1b3 --- /dev/null +++ b/HTML_Template_IT-1.3.0/HTML/Template/IT.php @@ -0,0 +1,1186 @@ + + * Pierre-Alain Joye + * David Soria Parra + * + * @category HTML + * @package HTML_Template_IT + * @author Ulf Wendel + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @version CVS: $Id: IT.php 295605 2010-02-28 22:48:07Z gregorycu $ + * @link http://pear.php.net/packages/HTML_Template_IT + * @access public + */ + +require_once 'PEAR.php'; + +define('IT_OK', 1); +define('IT_ERROR', -1); +define('IT_TPL_NOT_FOUND', -2); +define('IT_BLOCK_NOT_FOUND', -3); +define('IT_BLOCK_DUPLICATE', -4); +define('IT_UNKNOWN_OPTION', -6); + +/** + * Integrated Template - IT + * + * Well there's not much to say about it. I needed a template class that + * supports a single template file with multiple (nested) blocks inside and + * a simple block API. + * + * The Isotemplate API is somewhat tricky for a beginner although it is the best + * one you can build. template::parse() [phplib template = Isotemplate] requests + * you to name a source and a target where the current block gets parsed into. + * Source and target can be block names or even handler names. This API gives you + * a maximum of fexibility but you always have to know what you do which is + * quite unusual for php skripter like me. + * + * I noticed that I do not any control on which block gets parsed into which one. + * If all blocks are within one file, the script knows how they are nested and in + * which way you have to parse them. IT knows that inner1 is a child of block2, + * there's no need to tell him about this. + * + * + * + * + * + * + * + * + * + *
+ * __global__ + *

+ * (hidden and automatically added) + *

block1 + * + * + * + * + * + * + * + * + *
block2
inner1inner2
+ *
+ * + * To add content to block1 you simply type: + * $tpl->setCurrentBlock("block1"); + * and repeat this as often as needed: + * + * $tpl->setVariable(...); + * $tpl->parseCurrentBlock(); + * + * + * To add content to block2 you would type something like: + * + * $tpl->setCurrentBlock("inner1"); + * $tpl->setVariable(...); + * $tpl->parseCurrentBlock(); + * + * $tpl->setVariable(...); + * $tpl->parseCurrentBlock(); + * + * $tpl->parse("block1"); + * + * + * This will result in one repition of block1 which contains two repitions + * of inner1. inner2 will be removed if $removeEmptyBlock is set to true + * which is the default. + * + * Usage: + * + * $tpl = new HTML_Template_IT( [string filerootdir] ); + * + * // load a template or set it with setTemplate() + * $tpl->loadTemplatefile( string filename [, boolean removeUnknownVariables, boolean removeEmptyBlocks] ) + * + * // set "global" Variables meaning variables not beeing within a (inner) block + * $tpl->setVariable( string variablename, mixed value ); + * + * // like with the Isotemplates there's a second way to use setVariable() + * $tpl->setVariable( array ( string varname => mixed value ) ); + * + * // Let's use any block, even a deeply nested one + * $tpl->setCurrentBlock( string blockname ); + * + * // repeat this as often as you need it. + * $tpl->setVariable( array ( string varname => mixed value ) ); + * $tpl->parseCurrentBlock(); + * + * // get the parsed template or print it: $tpl->show() + * $tpl->get(); + * + * + * @category HTML + * @package HTML_Template_IT + * @author Ulf Wendel + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/packages/HTML_Template_IT + * @access public + */ +class HTML_Template_IT +{ + /** + * Contains the error objects + * @var array + * @access public + * @see halt(), $printError, $haltOnError + */ + var $err = array(); + + /** + * Clear cache on get()? + + * @var boolean + * @acces public + */ + var $clearCache = false; + + /** + * First character of a variable placeholder ( _{_VARIABLE} ). + * @var string + * @access public + * @see $closingDelimiter, $blocknameRegExp, $variablenameRegExp + */ + var $openingDelimiter = '{'; + + /** + * Last character of a variable placeholder ( {VARIABLE_}_ ). + * @var string + * @access public + * @see $openingDelimiter, $blocknameRegExp, $variablenameRegExp + */ + var $closingDelimiter = '}'; + + /** + * RegExp matching a block in the template. + * Per default "sm" is used as the regexp modifier, "i" is missing. + * That means a case sensitive search is done. + * @var string + * @access public + * @see $variablenameRegExp, $openingDelimiter, $closingDelimiter + */ + var $blocknameRegExp = '[\.0-9A-Za-z_-]+'; + + /** + * RegExp matching a variable placeholder in the template. + * Per default "sm" is used as the regexp modifier, "i" is missing. + * That means a case sensitive search is done. + * @var string + * @access public + * @see $blocknameRegExp, $openingDelimiter, $closingDelimiter + */ + var $variablenameRegExp = '[\.0-9A-Za-z_-]+'; + + /** + * RegExp used to find variable placeholder, filled by the constructor. + * @var string Looks somewhat like @(delimiter varname delimiter)@ + * @access private + * @see IntegratedTemplate() + */ + var $variablesRegExp = ''; + + /** + * RegExp used to strip unused variable placeholder. + * @access private + * @brother $variablesRegExp + */ + var $removeVariablesRegExp = ''; + + /** + * Controls the handling of unknown variables, default is remove. + * @var boolean + * @access public + */ + var $removeUnknownVariables = true; + + /** + * Controls the handling of empty blocks, default is remove. + * @var boolean + * @access public + */ + var $removeEmptyBlocks = true; + + /** + * RegExp used to find blocks an their content, filled by the constructor. + * @var string + * @see IntegratedTemplate() + * @access private + */ + var $blockRegExp = ''; + + /** + * Name of the current block. + * @var string + * @access private + */ + var $currentBlock = '__global__'; + + /** + * Content of the template. + * @var string + * @access private + */ + var $template = ''; + + /** + * Array of all blocks and their content. + * + * @var array + * @see findBlocks() + * @access private + */ + var $blocklist = array(); + + /** + * Array with the parsed content of a block. + * + * @var array + * @access private + */ + var $blockdata = array(); + + /** + * Array of variables in a block. + * @var array + * @access private + */ + var $blockvariables = array(); + + /** + * Array of inner blocks of a block. + * @var array + * @access private + */ + var $blockinner = array(); + + /** + * List of blocks to preverse even if they are "empty". + * + * This is something special. Sometimes you have blocks that + * should be preserved although they are empty (no placeholder replaced). + * Think of a shopping basket. If it's empty you have to drop a message to + * the user. If it's filled you have to show the contents of + * the shopping baseket. Now where do you place the message that the basket + * is empty? It's no good idea to place it in you applications as customers + * tend to like unecessary minor text changes. Having another template file + * for an empty basket means that it's very likely that one fine day + * the filled and empty basket templates have different layout. I decided + * to introduce blocks that to not contain any placeholder but only + * text such as the message "Your shopping basked is empty". + * + * Now if there is no replacement done in such a block the block will + * be recognized as "empty" and by default ($removeEmptyBlocks = true) be + * stripped off. To avoid thisyou can now call touchBlock() to avoid this. + * + * The array $touchedBlocks stores a list of touched block which must not + * be removed even if they are empty. + * + * @var array $touchedBlocks + * @see touchBlock(), $removeEmptyBlocks + * @access private + */ + var $touchedBlocks = array(); + + /** + * List of blocks which should not be shown even if not "empty" + * @var array $_hiddenBlocks + * @see hideBlock(), $removeEmptyBlocks + * @access private + */ + var $_hiddenBlocks = array(); + + /** + * Variable cache. + * + * Variables get cached before any replacement is done. + * Advantage: empty blocks can be removed automatically. + * Disadvantage: might take some more memory + * + * @var array + * @see setVariable(), $clearCacheOnParse + * @access private + */ + var $variableCache = array(); + + /** + * Clear the variable cache on parse? + * + * If you're not an expert just leave the default false. + * True reduces memory consumption somewhat if you tend to + * add lots of values for unknown placeholder. + * + * @var boolean + * @access public + */ + var $clearCacheOnParse = false; + + /** + * Root directory for all file operations. + * The string gets prefixed to all filenames given. + * @var string + * @see HTML_Template_IT(), setRoot() + * @access private + */ + var $fileRoot = ''; + + /** + * Internal flag indicating that a blockname was used multiple times. + * @var boolean + * @access private + */ + var $flagBlocktrouble = false; + + /** + * Flag indicating that the global block was parsed. + * @var boolean + * @access private + */ + var $flagGlobalParsed = false; + + /** + * EXPERIMENTAL! FIXME! + * Flag indication that a template gets cached. + * + * Complex templates require some times to be preparsed + * before the replacement can take place. Often I use + * one template file over and over again but I don't know + * before that I will use the same template file again. + * Now IT could notice this and skip the preparse. + * + * @var boolean + * @access private + */ + var $flagCacheTemplatefile = true; + + /** + * EXPERIMENTAL! FIXME! + * @access private + */ + var $lastTemplatefile = ''; + + /** + * $_options['preserve_data'] Whether to substitute variables and remove + * empty placeholders in data passed through setVariable + * (see also bugs #20199, #21951). + * $_options['use_preg'] Whether to use preg_replace instead of + * str_replace in parse() + * (this is a backwards compatibility feature, see also bugs #21951, #20392) + * + * @var array + * @access private + */ + var $_options = array( + 'preserve_data' => false, + 'use_preg' => true, + 'preserve_input'=> true + ); + + /** + * Builds some complex regular expressions and optinally sets the + * file root directory. + * + * Make sure that you call this constructor if you derive your template + * class from this one. + * + * @param string $root File root directory, prefix for all filenames + * given to the object. + * @param mixed $options Unknown + * + * @see setRoot() + * @access public + */ + function HTML_Template_IT($root = '', $options = null) + { + if (!is_null($options)) { + $this->setOptions($options); + } + + $this->variablesRegExp = '@' . $this->openingDelimiter . + '(' . $this->variablenameRegExp . ')' . + $this->closingDelimiter . '@sm'; + + $this->removeVariablesRegExp = '@' . $this->openingDelimiter . + "\s*(" . $this->variablenameRegExp . + ")\s*" . $this->closingDelimiter .'@sm'; + + $this->blockRegExp = '@(.*)@sm'; + + $this->setRoot($root); + } // end constructor + + + /** + * Sets the option for the template class + * + * @param string $option option name + * @param mixed $value option value + * + * @access public + * @return mixed IT_OK on success, error object on failure + */ + function setOption($option, $value) + { + switch ($option) { + case 'removeEmptyBlocks': + $this->removeEmptyBlocks = $value; + return IT_OK; + } + + if (array_key_exists($option, $this->_options)) { + $this->_options[$option] = $value; + return IT_OK; + } + + return PEAR::raiseError( + $this->errorMessage(IT_UNKNOWN_OPTION) . ": '{$option}'", + IT_UNKNOWN_OPTION + ); + } + + /** + * Sets the options for the template class + * + * @param string[] $options options array of options + * default value: + * 'preserve_data' => false, + * 'use_preg' => true + * + * @access public + * @return mixed IT_OK on success, error object on failure + * @see $options + */ + function setOptions($options) + { + if (is_array($options)) { + foreach ($options as $option => $value) { + $error = $this->setOption($option, $value); + if (PEAR::isError($error)) { + return $error; + } + } + } + + return IT_OK; + } + + /** + * Print a certain block with all replacements done. + * + * @param string $block block + * + * @brother get() + * @access public + * @return null + */ + function show($block = '__global__') + { + print $this->get($block); + } // end func show + + /** + * Returns a block with all replacements done. + * + * @param string $block name of the block + * + * @return string + * @throws PEAR_Error + * @access public + * @see show() + */ + function get($block = '__global__') + { + if ($block == '__global__' && !$this->flagGlobalParsed) { + $this->parse('__global__'); + } + + if (!isset($this->blocklist[$block])) { + $this->err[] = PEAR::raiseError( + $this->errorMessage(IT_BLOCK_NOT_FOUND) . '"' . $block . "'", + IT_BLOCK_NOT_FOUND + ); + return ''; + } + + if (isset($this->blockdata[$block])) { + $ret = $this->blockdata[$block]; + + if ($this->clearCache) { + unset($this->blockdata[$block]); + if ($block == '__global__') { + $this->flagGlobalParsed = false; + } + } + + if ($this->_options['preserve_data']) { + $ret = str_replace( + $this->openingDelimiter . + '%preserved%' . $this->closingDelimiter, + $this->openingDelimiter, + $ret + ); + } + return $ret; + } + + return ''; + } // end func get() + + /** + * Parses the given block. + * + * @param string $block name of the block to be parsed + * @param bool $flag_recursion unknown + * + * @access public + * @see parseCurrentBlock() + * @throws PEAR_Error + * @return null + */ + function parse($block = '__global__', $flag_recursion = false) + { + static $regs, $values; + + if (!isset($this->blocklist[$block])) { + return PEAR::raiseError( + $this->errorMessage(IT_BLOCK_NOT_FOUND) . '"' . $block . "'", + IT_BLOCK_NOT_FOUND + ); + } + + if ($block == '__global__') { + $this->flagGlobalParsed = true; + } + + if (!$flag_recursion) { + $regs = array(); + $values = array(); + } + $outer = $this->blocklist[$block]; + $empty = true; + + $variablelist = array(); + if ($this->clearCacheOnParse) { + foreach ($this->variableCache as $name => $value) { + $regs[] = $this->openingDelimiter . + $name . $this->closingDelimiter; + + $values[] = $value; + + $empty = false; + + $variablelist[] = $name; + } + $this->variableCache = array(); + } else { + foreach ($this->blockvariables[$block] as $allowedvar => $v) { + + if (isset($this->variableCache[$allowedvar])) { + $regs[] = $this->openingDelimiter . + $allowedvar . $this->closingDelimiter; + $values[] = $this->variableCache[$allowedvar]; + + unset($this->variableCache[$allowedvar]); + + $empty = false; + + $variablelist[] = $allowedvar; + } + } + } + + if (isset($this->blockinner[$block])) { + foreach ($this->blockinner[$block] as $k => $innerblock) { + + $this->parse($innerblock, true); + if ($this->blockdata[$innerblock] != '') { + $empty = false; + } + + $placeholder = $this->openingDelimiter . "__" . + $innerblock . "__" . $this->closingDelimiter; + + $outer = str_replace( + $placeholder, + $this->blockdata[$innerblock], $outer + ); + + $this->blockdata[$innerblock] = ""; + } + + } + + if (!$flag_recursion && 0 != count($values)) { + if ($this->_options['use_preg']) { + $regs = array_map(array(&$this, '_addPregDelimiters'), $regs); + $values = array_map(array(&$this, '_escapeBackreferences'), $values); + + $funcReplace = 'preg_replace'; + } else { + $funcReplace = 'str_replace'; + } + + if ($this->_options['preserve_data']) { + $values = array_map( + array(&$this, '_preserveOpeningDelimiter'), + $values + ); + } + + $outer = $funcReplace($regs, $values, $outer); + } + + if ($this->removeUnknownVariables) { + $outer = $this->removeUnknownVariablesFromBlock( + $block, + $outer, + $variablelist + ); + } + + if ($empty) { + if (!$this->removeEmptyBlocks) { + $this->blockdata[$block ] .= $outer; + } else { + if (isset($this->touchedBlocks[$block])) { + $this->blockdata[$block] .= $outer; + unset($this->touchedBlocks[$block]); + } + } + } else { + if (empty($this->blockdata[$block])) { + $this->blockdata[$block] = $outer; + } else { + $this->blockdata[$block] .= $outer; + } + } + + return $empty; + } // end func parse + + /** + * Removes unknown variables from block. If preserve_input is set to true + * only unknown variables that were present during setTemplate or + * loadTemplatefile are removed. Thus you can set a variable to + * "{SOMEINPUTDATA}" which is preserved. + * + * @param string $blockname block + * @param string $blockinner unknown + * @param string $variableList unknown + * + * @see parse() + * @access private + * @return null + */ + function removeUnknownVariablesFromBlock ($blockname, $blockinner, $variableList) + { + if ($this->_options['preserve_input']) { + foreach ($this->blockvariables[$blockname] as $var => $setted) { + if (!in_array($var, $variableList)) { + $blockinner = str_replace( + $this->openingDelimiter . $var . $this->closingDelimiter, + '', + $blockinner + ); + } + } + } else { + $blockinner = preg_replace( + $this->removeVariablesRegExp, + '', + $blockinner + ); + } + + return $blockinner; + } + + /** + * Parses the current block + * + * @see parse(), setCurrentBlock(), $currentBlock + * @access public + * @return null + */ + function parseCurrentBlock() + { + return $this->parse($this->currentBlock); + } // end func parseCurrentBlock + + /** + * Checks to see if a placeholder exists within a block (and its children) + * + * @access public + * @return bool + */ + function checkPlaceholderExists($blockname, $placeholder) { + if (isset($this->blockvariables[$blockname][$placeholder])) { + return true; + } + if (isset($this->blockinner[$blockname])) { + foreach ($this->blockinner[$blockname] as $block) { + if ($this->checkPlaceholderExists($block, $placeholder)) { + return true; + } + } + } + return false; + } // end func checkPlaceholderExists + + /** + * Sets a variable value. + * + * The function can be used eighter like setVariable( "varname", "value") + * or with one array $variables["varname"] = "value" + * given setVariable($variables) quite like phplib templates set_var(). + * + * @param mixed $variable string with the variable name or an array + * %variables["varname"] = "value" + * @param string $value value of the variable or empty if $variable + * is an array. + * + * @access public + * @return null + */ + function setVariable($variable, $value = '') + { + if (is_array($variable)) { + foreach ($variable as $key => $value) { + $this->setVariable($key, $value); + } + } else { + if ($this->checkPlaceholderExists($this->currentBlock, $variable)) { + $this->variableCache[$variable] = $value; + } + } + } // end func setVariable + + /** + * Sets the name of the current block that is the block where variables + * are added. + * + * @param string $block name of the block + * + * @return boolean false on failure, otherwise true + * @throws PEAR_Error + * @access public + */ + function setCurrentBlock($block = '__global__') + { + + if (!isset($this->blocklist[$block])) { + return PEAR::raiseError( + $this->errorMessage(IT_BLOCK_NOT_FOUND) + . '"' . $block . "'", + IT_BLOCK_NOT_FOUND + ); + } + + $this->currentBlock = $block; + + return true; + } // end func setCurrentBlock + + /** + * Preserves an empty block even if removeEmptyBlocks is true. + * + * @param string $block name of the block + * + * @return boolean false on false, otherwise true + * @throws PEAR_Error + * @access public + * @see $removeEmptyBlocks + */ + function touchBlock($block) + { + if (!isset($this->blocklist[$block])) { + return PEAR::raiseError( + $this->errorMessage(IT_BLOCK_NOT_FOUND) . '"' . $block . "'", + IT_BLOCK_NOT_FOUND + ); + } + + $this->touchedBlocks[$block] = true; + + return true; + } // end func touchBlock + + /** + * Clears all datafields of the object and rebuild the internal blocklist + * + * LoadTemplatefile() and setTemplate() automatically call this function + * when a new template is given. Don't use this function + * unless you know what you're doing. + * + * @access private + * @see free() + * @return null + */ + function init() + { + $this->free(); + $this->findBlocks($this->template); + // we don't need it any more + $this->template = ''; + $this->buildBlockvariablelist(); + } // end func init + + /** + * Clears all datafields of the object. + * + * Don't use this function unless you know what you're doing. + * + * @access private + * @see init() + * @return null + */ + function free() + { + $this->err = array(); + + $this->currentBlock = '__global__'; + + $this->variableCache = array(); + $this->blocklist = array(); + $this->touchedBlocks = array(); + + $this->flagBlocktrouble = false; + $this->flagGlobalParsed = false; + } // end func free + + /** + * Sets the template. + * + * You can eighter load a template file from disk with + * LoadTemplatefile() or set the template manually using this function. + * + * @param string $template template content + * @param bool $removeUnknownVariables how to handle unknown variables. + * @param bool $removeEmptyBlocks how to handle empty blocks. + * + * @see LoadTemplatefile(), $template + * @access public + * @return boolean + */ + function setTemplate( $template, + $removeUnknownVariables = true, + $removeEmptyBlocks = true) { + $this->removeUnknownVariables = $removeUnknownVariables; + + $this->removeEmptyBlocks = $removeEmptyBlocks; + + if ($template == '' && $this->flagCacheTemplatefile) { + $this->variableCache = array(); + $this->blockdata = array(); + $this->touchedBlocks = array(); + $this->currentBlock = '__global__'; + } else { + $this->template = '' . $template . + ''; + $this->init(); + } + + if ($this->flagBlocktrouble) { + return false; + } + + return true; + } // end func setTemplate + + /** + * Reads a template file from the disk. + * + * @param string $filename name of the template file + * @param bool $removeUnknownVariables how to handle unknown variables. + * @param bool $removeEmptyBlocks how to handle empty blocks. + * + * @access public + * @return boolean false on failure, otherwise true + * @see $template, setTemplate(), $removeUnknownVariables, + * $removeEmptyBlocks + */ + function loadTemplatefile( $filename, + $removeUnknownVariables = true, + $removeEmptyBlocks = true ) {; + $template = ''; + if (!$this->flagCacheTemplatefile + || $this->lastTemplatefile != $filename + ) { + $template = $this->getFile($filename); + } + $this->lastTemplatefile = $filename; + + return $template != '' ? + $this->setTemplate( + $template, + $removeUnknownVariables, + $removeEmptyBlocks) : false; + } // end func LoadTemplatefile + + /** + * Sets the file root. The file root gets prefixed to all filenames passed + * to the object. + * + * Make sure that you override this function when using the class + * on windows. + * + * @param string $root File root + * + * @see HTML_Template_IT() + * @access public + * @return null + */ + function setRoot($root) + { + if ($root != '' && substr($root, -1) != '/') { + $root .= '/'; + } + + $this->fileRoot = $root; + } // end func setRoot + + /** + * Build a list of all variables within of a block + * + * @access private + * @return null + */ + function buildBlockvariablelist() + { + foreach ($this->blocklist as $name => $content) { + preg_match_all($this->variablesRegExp, $content, $regs); + + if (count($regs[1]) != 0) { + foreach ($regs[1] as $k => $var) { + $this->blockvariables[$name][$var] = true; + } + } else { + $this->blockvariables[$name] = array(); + } + } + } // end func buildBlockvariablelist + + /** + * Returns a list of all global variables + * + * @access public + * @return array + */ + function getGlobalvariables() + { + $regs = array(); + $values = array(); + + foreach ($this->blockvariables['__global__'] as $allowedvar => $v) { + if (isset($this->variableCache[$allowedvar])) { + $regs[] = '@' . $this->openingDelimiter . + $allowedvar . $this->closingDelimiter . '@'; + $values[] = $this->variableCache[$allowedvar]; + unset($this->variableCache[$allowedvar]); + } + } + + return array($regs, $values); + } // end func getGlobalvariables + + /** + * Recusively builds a list of all blocks within the template. + * + * @param string $string string that gets scanned + * + * @access private + * @see $blocklist + * @return array + */ + function findBlocks($string) + { + $blocklist = array(); + + if (preg_match_all($this->blockRegExp, $string, $regs, PREG_SET_ORDER)) { + foreach ($regs as $k => $match) { + $blockname = $match[1]; + $blockcontent = $match[2]; + + if (isset($this->blocklist[$blockname])) { + $msg = $this->errorMessage(IT_BLOCK_DUPLICATE, $blockname); + + $this->err[] = PEAR::raiseError($msg, IT_BLOCK_DUPLICATE); + + $this->flagBlocktrouble = true; + } + + $this->blocklist[$blockname] = $blockcontent; + $this->blockdata[$blockname] = ""; + + $blocklist[] = $blockname; + + $inner = $this->findBlocks($blockcontent); + $regex = '@(.*)@sm'; + foreach ($inner as $k => $name) { + $pattern = sprintf($regex, preg_quote($name), preg_quote($name)); + + $this->blocklist[$blockname] = preg_replace( + $pattern, + $this->openingDelimiter . + '__' . $name . '__' . + $this->closingDelimiter, + $this->blocklist[$blockname] + ); + + $this->blockinner[$blockname][] = $name; + + $this->blockparents[$name] = $blockname; + } + } + } + + return $blocklist; + } // end func findBlocks + + /** + * Reads a file from disk and returns its content. + * + * @param string $filename Filename + * + * @return string Filecontent + * @access private + */ + function getFile($filename) + { + if ($filename{0} == '/' && substr($this->fileRoot, -1) == '/') { + $filename = substr($filename, 1); + } + + $filename = $this->fileRoot . $filename; + + if (!($fh = @fopen($filename, 'r'))) { + $this->err[] = PEAR::raiseError( + $this->errorMessage(IT_TPL_NOT_FOUND) . ': "' .$filename .'"', + IT_TPL_NOT_FOUND + ); + return ""; + } + + $fsize = filesize($filename); + if ($fsize < 1) { + fclose($fh); + return ''; + } + + $content = fread($fh, $fsize); + fclose($fh); + + return preg_replace( + "##ime", + "\$this->getFile('\\1')", + $content + ); + } // end func getFile + + /** + * Adds delimiters to a string, so it can be used as a pattern + * in preg_* functions + * + * @param string $str input + * + * @return string + * @access private + */ + function _addPregDelimiters($str) + { + return '@' . preg_quote($str) . '@'; + } + + /** + * Escapes $ and \ as preg_replace will treat + * them as a backreference and not literal. + * See bug #9501 + * + * @param string $str String to escape + * + * @since 1.2.2 + * @return string + * @access private + */ + function _escapeBackreferences($str) + { + $str = str_replace('\\', '\\\\', $str); + $str = preg_replace('@\$([0-9]{1,2})@', '\\\$${1}', $str); + return $str; + } + + /** + * Replaces an opening delimiter by a special string + * + * @param string $str special string + * + * @return string + * @access private + */ + function _preserveOpeningDelimiter($str) + { + return (false === strpos($str, $this->openingDelimiter))? + $str: + str_replace( + $this->openingDelimiter, + $this->openingDelimiter . + '%preserved%' . $this->closingDelimiter, + $str + ); + } + + /** + * Return a textual error message for a IT error code + * + * @param integer $value error code + * @param string $blockname unknown + * + * @access private + * @return string error message, or false if the error code was + * not recognized + */ + function errorMessage($value, $blockname = '') + { + static $errorMessages; + if (!isset($errorMessages)) { + $errorMessages = array( + IT_OK => '', + IT_ERROR => 'unknown error', + IT_TPL_NOT_FOUND => 'Cannot read the template file', + IT_BLOCK_NOT_FOUND => 'Cannot find this block', + IT_BLOCK_DUPLICATE => 'The name of a block must be'. + ' uniquewithin a template.'. + ' Found "' . $blockname . '" twice.'. + 'Unpredictable results '. + 'may appear.', + IT_UNKNOWN_OPTION => 'Unknown option' + ); + } + + if (PEAR::isError($value)) { + $value = $value->getCode(); + } + + return isset($errorMessages[$value]) ? + $errorMessages[$value] : $errorMessages[IT_ERROR]; + } +} // end class IntegratedTemplate +?> diff --git a/HTML_Template_IT-1.3.0/HTML/Template/ITX.php b/HTML_Template_IT-1.3.0/HTML/Template/ITX.php new file mode 100644 index 0000000..b8ec37c --- /dev/null +++ b/HTML_Template_IT-1.3.0/HTML/Template/ITX.php @@ -0,0 +1,889 @@ + + * Pierre-Alain Joye + * David Soria Parra + * + * @category HTML + * @package HTML_Template_IT + * @author Ulf Wendel + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @version CVS: $Id: ITX.php 295086 2010-02-15 06:31:36Z clockwerx $ + * @link http://pear.php.net/packages/HTML_Template_IT + * @access public + */ + +require_once 'HTML/Template/IT.php'; +require_once 'HTML/Template/IT_Error.php'; + +/** +* Integrated Template Extension - ITX +* +* With this class you get the full power of the phplib template class. +* You may have one file with blocks in it but you have as well one main file +* and multiple files one for each block. This is quite usefull when you have +* user configurable websites. Using blocks not in the main template allows +* you to modify some parts of your layout easily. +* +* Note that you can replace an existing block and add new blocks at runtime. +* Adding new blocks means changing a variable placeholder to a block. +* + * @category HTML + * @package HTML_Template_IT + * @author Ulf Wendel + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/packages/HTML_Template_IT + * @access public +*/ +class HTML_Template_ITX extends HTML_Template_IT +{ + /** + * Array with all warnings. + * @var array + * @access public + * @see $printWarning, $haltOnWarning, warning() + */ + var $warn = array(); + + /** + * Print warnings? + * @var array + * @access public + * @see $haltOnWarning, $warn, warning() + */ + var $printWarning = false; + + /** + * Call die() on warning? + * @var boolean + * @access public + * @see $warn, $printWarning, warning() + */ + var $haltOnWarning = false; + + /** + * RegExp used to test for a valid blockname. + * @var string + * @access private + */ + var $checkblocknameRegExp = ''; + + /** + * Functionnameprefix used when searching function calls in the template. + * @var string + * @access public + */ + var $functionPrefix = 'func_'; + + /** + * Functionname RegExp. + * @var string + * @access public + */ + var $functionnameRegExp = '[_a-zA-Z]+[A-Za-z_0-9]*'; + + /** + * RegExp used to grep function calls in the template. + * + * The variable gets set by the constructor. + * + * @access private + * @var string + * @see HTML_Template_IT() + */ + var $functionRegExp = ''; + + /** + * List of functions found in the template. + * + * @access private + * @var array + */ + var $functions = array(); + + /** + * List of callback functions specified by the user. + * + * @access private + * @var array + */ + var $callback = array(); + + /** + * Builds some complex regexps and calls the constructor + * of the parent class. + * + * Make sure that you call this constructor if you derive your own + * template class from this one. + * + * @param string $root Root node? + * + * @access public + * @see HTML_Template_IT() + */ + function HTML_Template_ITX($root = '') + { + + $this->checkblocknameRegExp = '@' . $this->blocknameRegExp . '@'; + + $this->functionRegExp = '@' . $this->functionPrefix . '(' . + $this->functionnameRegExp . ')\s*\(@sm'; + + $this->HTML_Template_IT($root); + } // end func constructor + + /** + * Clears all datafields of the object and rebuild the internal blocklist + * + * LoadTemplatefile() and setTemplate() automatically call this function + * when a new template is given. Don't use this function + * unless you know what you're doing. + * + * @access private + * @return null + */ + function init() + { + $this->free(); + $this->buildFunctionlist(); + $this->findBlocks($this->template); + + // we don't need it any more + $this->template = ''; + $this->buildBlockvariablelist(); + + } // end func init + + /** + * Replaces an existing block with new content. + * + * This function will replace a block of the template and all blocks + * contained in the replaced block and add a new block insted, means + * you can dynamically change your template. + * + * Note that changing the template structure violates one of the IT[X] + * development goals. I've tried to write a simple to use template engine + * supporting blocks. In contrast to other systems IT[X] analyses the way + * you've nested blocks and knows which block belongs into another block. + * The nesting information helps to make the API short and simple. Replacing + * blocks does not only mean that IT[X] has to update the nesting + * information (relatively time consumpting task) but you have to make sure + * that you do not get confused due to the template change itself. + * + * @param string $block Blockname + * @param string $template Blockcontent + * @param boolean $keep_content true if the new block inherits the content + * of the old block + * + * @return boolean + * @throws IT_Error + * @see replaceBlockfile(), addBlock(), addBlockfile() + * @access public + */ + function replaceBlock($block, $template, $keep_content = false) + { + if (!isset($this->blocklist[$block])) { + return new IT_Error("The block "."'$block'". + " does not exist in the template and thus it can't be replaced.", + __FILE__, __LINE__); + } + + if ($template == '') { + return new IT_Error('No block content given.', __FILE__, __LINE__); + } + + if ($keep_content) { + $blockdata = $this->blockdata[$block]; + } + + // remove all kinds of links to the block / data of the block + $this->removeBlockData($block); + + $template = "" . $template . ""; + $parents = $this->blockparents[$block]; + + $this->findBlocks($template); + $this->blockparents[$block] = $parents; + + // KLUDGE: rebuild the list for all block - could be done faster + $this->buildBlockvariablelist(); + + if ($keep_content) { + $this->blockdata[$block] = $blockdata; + } + + // old TODO - I'm not sure if we need this + // update caches + + return true; + } // end func replaceBlock + + /** + * Replaces an existing block with new content from a file. + * + * @param string $block Blockname + * @param string $filename Name of the file that contains the blockcontent + * @param boolean $keep_content true if the new block inherits the content of + * the old block + * + * @brother replaceBlock() + * @access public + * @return null + */ + function replaceBlockfile($block, $filename, $keep_content = false) + { + return $this->replaceBlock($block, $this->getFile($filename), $keep_content); + } // end func replaceBlockfile + + /** + * Adds a block to the template changing a variable placeholder + * to a block placeholder. + * + * Add means "replace a variable placeholder by a new block". + * This is different to PHPLibs templates. The function loads a + * block, creates a handle for it and assigns it to a certain + * variable placeholder. To to the same with PHPLibs templates you would + * call set_file() to create the handle and parse() to assign the + * parsed block to a variable. By this PHPLibs templates assume + * that you tend to assign a block to more than one one placeholder. + * To assign a parsed block to more than only the placeholder you specify + * in this function you have to use a combination of getBlock() + * and setVariable(). + * + * As no updates to cached data is necessary addBlock() and addBlockfile() + * are rather "cheap" meaning quick operations. + * + * The block content must not start with + * and end with this would cause overhead and + * produce an error. + * + * @param string $placeholder Name of the variable placeholder, the name + * must be unique within the template. + * @param string $blockname Name of the block to be added + * @param string $template Content of the block + * + * @return boolean + * @throws IT_Error + * @see addBlockfile() + * @access public + */ + function addBlock($placeholder, $blockname, $template) + { + // Don't trust any user even if it's a programmer or yourself... + if ($placeholder == '') { + return new IT_Error('No variable placeholder given.', + __FILE__, __LINE__); + } elseif ($blockname == '' || + !preg_match($this->checkblocknameRegExp, $blockname) + ) { + return new IT_Error("No or invalid blockname '$blockname' given.", + __FILE__, __LINE__); + } elseif ($template == '') { + return new IT_Error('No block content given.', __FILE__, __LINE__); + } elseif (isset($this->blocklist[$blockname])) { + return new IT_Error('The block already exists.', + __FILE__, __LINE__); + } + + // find out where to insert the new block + $parents = $this->findPlaceholderBlocks($placeholder); + if (count($parents) == 0) { + + return new IT_Error("The variable placeholder". + " '$placeholder' was not found in the template.", + __FILE__, __LINE__); + + } elseif (count($parents) > 1) { + + reset($parents); + while (list($k, $parent) = each($parents)) { + $msg .= "$parent, "; + } + $msg = substr($parent, -2); + + return new IT_Error("The variable placeholder "."'$placeholder'". + " must be unique, found in multiple blocks '$msg'.", + __FILE__, __LINE__); + } + + $template = "" + . $template + . ""; + $this->findBlocks($template); + if ($this->flagBlocktrouble) { + return false; // findBlocks() already throws an exception + } + + $this->blockinner[$parents[0]][] = $blockname; + + $escblockname = '__' . $blockname . '__'; + + $this->blocklist[$parents[0]] = preg_replace( + '@' . $this->openingDelimiter . $placeholder . + $this->closingDelimiter . '@', + $this->openingDelimiter . $escblockname . $this->closingDelimiter, + $this->blocklist[$parents[0]] + ); + + $this->deleteFromBlockvariablelist($parents[0], $placeholder); + $this->updateBlockvariablelist($blockname); + + return true; + } // end func addBlock + + /** + * Adds a block taken from a file to the template changing a variable + * placeholder to a block placeholder. + * + * @param string $placeholder Name of the variable placeholder to be converted + * @param string $blockname Name of the block to be added + * @param string $filename File that contains the block + * + * @brother addBlock() + * @access public + * @return null + */ + function addBlockfile($placeholder, $blockname, $filename) + { + return $this->addBlock($placeholder, $blockname, $this->getFile($filename)); + } // end func addBlockfile + + /** + * Returns the name of the (first) block that contains + * the specified placeholder. + * + * @param string $placeholder Name of the placeholder you're searching + * @param string $block Name of the block to scan. If left out (default) + * all blocks are scanned. + * + * @return string Name of the (first) block that contains + * the specified placeholder. + * If the placeholder was not found or an error occured + * an empty string is returned. + * @throws IT_Error + * @access public + */ + function placeholderExists($placeholder, $block = '') + { + if ($placeholder == '') { + new IT_Error('No placeholder name given.', __FILE__, __LINE__); + return ''; + } + + if ($block != '' && !isset($this->blocklist[$block])) { + new IT_Error("Unknown block '$block'.", __FILE__, __LINE__); + return ''; + } + + // name of the block where the given placeholder was found + $found = ''; + + if ($block != '') { + if (is_array($variables = $this->blockvariables[$block])) { + // search the value in the list of blockvariables + reset($variables); + while (list($k, $variable) = each($variables)) { + if ($k == $placeholder) { + $found = $block; + break; + } + } + } + } else { + + // search all blocks and return the name of the first block that + // contains the placeholder + reset($this->blockvariables); + while (list($blockname, $variables) = each($this->blockvariables)) { + if (is_array($variables) && isset($variables[$placeholder])) { + $found = $blockname; + break; + } + } + } + + return $found; + } // end func placeholderExists + + /** + * Checks the list of function calls in the template and + * calls their callback function. + * + * @access public + * @return null + */ + function performCallback() + { + reset($this->functions); + while (list($func_id, $function) = each($this->functions)) { + if (isset($this->callback[$function['name']])) { + if ($this->callback[$function['name']]['expandParameters']) { + $callFunction = 'call_user_func_array'; + } else { + $callFunction = 'call_user_func'; + } + + if ($this->callback[$function['name']]['object'] != '') { + $call = $callFunction( + array( + &$GLOBALS[$this->callback[$function['name']]['object']], + $this->callback[$function['name']]['function']), + $function['args']); + + } else { + $call = $callFunction( + $this->callback[$function['name']]['function'], + $function['args']); + } + $this->variableCache['__function' . $func_id . '__'] = $call; + } + } + + } // end func performCallback + + /** + * Returns a list of all function calls in the current template. + * + * @return array + * @access public + */ + function getFunctioncalls() + { + return $this->functions; + } // end func getFunctioncalls + + /** + * Replaces a function call with the given replacement. + * + * @param int $functionID Function ID + * @param string $replacement Replacement + * + * @access public + * @deprecated + * @return null + */ + function setFunctioncontent($functionID, $replacement) + { + $this->variableCache['__function' . $functionID . '__'] = $replacement; + } // end func setFunctioncontent + + /** + * Sets a callback function. + * + * IT[X] templates (note the X) can contain simple function calls. + * "function call" means that the editor of the template can add + * special placeholder to the template like 'func_h1("embedded in h1")'. + * IT[X] will grab this function calls and allow you to define a callback + * function for them. + * + * This is an absolutely evil feature. If your application makes heavy + * use of such callbacks and you're even implementing if-then etc. on + * the level of a template engine you're reiventing the wheel... - that's + * actually how PHP came into life. Anyway, sometimes it's handy. + * + * Consider also using XML/XSLT or native PHP. And please do not push + * IT[X] any further into this direction of adding logics to the template + * engine. + * + * For those of you ready for the X in IT[X]: + * + * %s', $args[0]); + * } + * + * ... + * $itx = new HTML_Template_ITX(...); + * ... + * $itx->setCallbackFunction('h1', 'h_one'); + * $itx->performCallback(); + * ?> + * + * template: + * func_h1('H1 Headline'); + * + * @param string $tplfunction Function name in the template + * @param string $callbackfunction Name of the callback function + * @param string $callbackobject Name of the callback object + * @param boolean $expandCallbackParameters If the callback is called with + * a list of parameters or with an + * array holding the parameters + * + * @return boolean False on failure. + * @throws IT_Error + * @access public + * @deprecated The $callbackobject parameter is depricated since + * version 1.2 and might be dropped in further versions. + */ + function setCallbackFunction($tplfunction, $callbackfunction, + $callbackobject = '', + $expandCallbackParameters = false) { + if ($tplfunction == '' || $callbackfunction == '') { + return new IT_Error("No template function "."('$tplfunction')". + " and/or no callback function ('$callback') given.", + __FILE__, __LINE__); + } + $this->callback[$tplfunction] = array( + 'function' => $callbackfunction, + 'object' => $callbackobject, + 'expandParameters' => (boolean) + $expandCallbackParameters); + + return true; + } // end func setCallbackFunction + + /** + * Sets the Callback function lookup table + * + * @param array $functions function table + * array[templatefunction] = + * array( + * "function" => userfunction, + * "object" => userobject + * ) + * + * @access public + * @return null + */ + function setCallbackFuntiontable($functions) + { + $this->callback = $functions; + } // end func setCallbackFunctiontable + + /** + * Recursively removes all data assiciated with a block, including + * all inner blocks + * + * @param string $block block to be removed + * + * @return null + * @access private + */ + function removeBlockData($block) + { + if (isset($this->blockinner[$block])) { + foreach ($this->blockinner[$block] as $k => $inner) { + $this->removeBlockData($inner); + } + + unset($this->blockinner[$block]); + } + + unset($this->blocklist[$block]); + unset($this->blockdata[$block]); + unset($this->blockvariables[$block]); + unset($this->touchedBlocks[$block]); + + } // end func removeBlockinner + + /** + * Returns a list of blocknames in the template. + * + * @return array [blockname => blockname] + * @access public + * @see blockExists() + */ + function getBlocklist() + { + $blocklist = array(); + foreach ($this->blocklist as $block => $content) { + $blocklist[$block] = $block; + } + + return $blocklist; + } // end func getBlocklist + + /** + * Checks wheter a block exists. + * + * @param string $blockname Blockname + * + * @return boolean + * @access public + * @see getBlocklist() + */ + function blockExists($blockname) + { + return isset($this->blocklist[$blockname]); + } // end func blockExists + + /** + * Returns a list of variables of a block. + * + * @param string $block Blockname + * + * @return array [varname => varname] + * @access public + * @see BlockvariableExists() + */ + function getBlockvariables($block) + { + if (!isset($this->blockvariables[$block])) { + return array(); + } + + $variables = array(); + foreach ($this->blockvariables[$block] as $variable => $v) { + $variables[$variable] = $variable; + } + + return $variables; + } // end func getBlockvariables + + /** + * Checks wheter a block variable exists. + * + * @param string $block Blockname + * @param string $variable Variablename + * + * @return boolean + * @access public + * @see getBlockvariables() + */ + function BlockvariableExists($block, $variable) + { + return isset($this->blockvariables[$block][$variable]); + } // end func BlockvariableExists + + /** + * Builds a functionlist from the template. + * + * @access private + * @return null + */ + function buildFunctionlist() + { + $this->functions = array(); + + $template = $this->template; + + $num = 0; + + while (preg_match($this->functionRegExp, $template, $regs)) { + + $pos = strpos($template, $regs[0]); + + $template = substr($template, $pos + strlen($regs[0])); + + $head = $this->getValue($template, ')'); + $args = array(); + + $search = $regs[0] . $head . ')'; + + $replace = $this->openingDelimiter . + '__function' . $num . '__' . + $this->closingDelimiter; + + $this->template = str_replace($search, $replace, $this->template); + $template = str_replace($search, $replace, $template); + + while ($head != '' && $args2 = $this->getValue($head, ',')) { + $arg2 = trim($args2); + + $args[] = ('"' == $arg2{0} || "'" == $arg2{0}) ? + substr($arg2, 1, -1) : $arg2; + + if ($arg2 == $head) { + break; + } + $head = substr($head, strlen($arg2) + 1); + } + + $this->functions[$num++] = array('name' => $regs[1], + 'args' => $args); + } + + } // end func buildFunctionlist + + /** + * Truncates the given code from the first occurence of + * $delimiter but ignores $delimiter enclosed by " or '. + * + * @param string $code The code which should be parsed + * @param string $delimiter The delimiter char + * + * @access private + * @return string + * @see buildFunctionList() + */ + function getValue($code, $delimiter) + { + if ($code == '') { + return ''; + } + + if (!is_array($delimiter)) { + $delimiter = array($delimiter => true); + } + + $len = strlen($code); + $enclosed = false; + $enclosed_by = ''; + + if (isset($delimiter[$code[0]])) { + $i = 1; + } else { + for ($i = 0; $i < $len; ++$i) { + $char = $code[$i]; + + if (($char == '"' || $char == "'") + && ($char == $enclosed_by || '' == $enclosed_by) + && (0 == $i || ($i > 0 && '\\' != $code[$i - 1])) + ) { + + if (!$enclosed) { + $enclosed_by = $char; + } else { + $enclosed_by = ""; + } + $enclosed = !$enclosed; + + } + + if (!$enclosed && isset($delimiter[$char])) { + break; + } + } + } + + return substr($code, 0, $i); + } // end func getValue + + /** + * Deletes one or many variables from the block variable list. + * + * @param string $block Blockname + * @param mixed $variables Name of one variable or array of variables + * (array (name => true ) ) to be stripped. + * + * @access private + * @return null + */ + function deleteFromBlockvariablelist($block, $variables) + { + if (!is_array($variables)) { + $variables = array($variables => true); + } + + reset($this->blockvariables[$block]); + while (list($varname, $val) = each($this->blockvariables[$block])) { + if (isset($variables[$varname])) { + unset($this->blockvariables[$block][$varname]); + } + } + } // end deleteFromBlockvariablelist + + /** + * Updates the variable list of a block. + * + * @param string $block Blockname + * + * @access private + * @return null + */ + function updateBlockvariablelist($block) + { + preg_match_all( + $this->variablesRegExp, + $this->blocklist[$block], $regs + ); + + if (count($regs[1]) != 0) { + foreach ($regs[1] as $k => $var) { + $this->blockvariables[$block][$var] = true; + } + } else { + $this->blockvariables[$block] = array(); + } + + // check if any inner blocks were found + if (isset($this->blockinner[$block]) + && is_array($this->blockinner[$block]) + && count($this->blockinner[$block]) > 0 + ) { + /* + * loop through inner blocks, registering the variable + * placeholders in each + */ + foreach ($this->blockinner[$block] as $childBlock) { + $this->updateBlockvariablelist($childBlock); + } + } + } // end func updateBlockvariablelist + + /** + * Returns an array of blocknames where the given variable + * placeholder is used. + * + * @param string $variable Variable placeholder + * + * @return array $parents parents[0..n] = blockname + * @access public + */ + function findPlaceholderBlocks($variable) + { + $parents = array(); + reset($this->blocklist); + while (list($blockname, $content) = each($this->blocklist)) { + reset($this->blockvariables[$blockname]); + + while (list($varname, $val) = each($this->blockvariables[$blockname])) { + if ($variable == $varname) { + $parents[] = $blockname; + } + } + } + + return $parents; + } // end func findPlaceholderBlocks + + /** + * Handles warnings, saves them to $warn and prints them or + * calls die() depending on the flags + * + * @param string $message Warning + * @param string $file File where the warning occured + * @param int $line Linenumber where the warning occured + * + * @see $warn, $printWarning, $haltOnWarning + * @access private + * @return null + */ + function warning($message, $file = '', $line = 0) + { + $message = sprintf( + 'HTML_Template_ITX Warning: %s [File: %s, Line: %d]', + $message, + $file, + $line + ); + + $this->warn[] = $message; + + if ($this->printWarning) { + print $message; + } + + if ($this->haltOnWarning) { + die($message); + } + } // end func warning + +} // end class HTML_Template_ITX +?> diff --git a/HTML_Template_IT-1.3.0/HTML/Template/IT_Error.php b/HTML_Template_IT-1.3.0/HTML/Template/IT_Error.php new file mode 100644 index 0000000..20e250c --- /dev/null +++ b/HTML_Template_IT-1.3.0/HTML/Template/IT_Error.php @@ -0,0 +1,65 @@ + + * Pierre-Alain Joye + * David Soria Parra + * + * @category HTML + * @package HTML_Template_IT + * @author Ulf Wendel + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @version CVS: $Id: IT_Error.php 295117 2010-02-15 23:25:21Z clockwerx $ + * @link http://pear.php.net/packages/HTML_Template_IT + * @access public + */ + +require_once "PEAR.php"; + +/** +* IT[X] Error class +* + * @category HTML + * @package HTML_Template_IT + * @author Ulf Wendel + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/packages/HTML_Template_IT + * @access public +*/ +class IT_Error extends PEAR_Error +{ + /** + * Prefix of all error messages. + * + * @var string + */ + var $error_message_prefix = "IntegratedTemplate Error: "; + + /** + * Creates an cache error object. + * + * @param string $msg error message + * @param string $file file where the error occured + * @param string $line linenumber where the error occured + */ + function IT_Error($msg, $file = __FILE__, $line = __LINE__) + { + $this->PEAR_Error(sprintf("%s [%s on line %d].", $msg, $file, $line)); + } // end func IT_Error + +} // end class IT_Error +?> diff --git a/HTML_Template_IT-1.3.0/LICENSE b/HTML_Template_IT-1.3.0/LICENSE new file mode 100644 index 0000000..db25e88 --- /dev/null +++ b/HTML_Template_IT-1.3.0/LICENSE @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without modification +, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, th + is list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/ + or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WA +RRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABIL +ITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR C +ONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOW +EVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILI +TY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE U +SE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/HTML_Template_IT-1.3.0/examples/sample_it.php b/HTML_Template_IT-1.3.0/examples/sample_it.php new file mode 100644 index 0000000..1afcc61 --- /dev/null +++ b/HTML_Template_IT-1.3.0/examples/sample_it.php @@ -0,0 +1,27 @@ + array('Stig', 'Bakken'), + '1' => array('Martin', 'Jansen'), + '2' => array('Alexander', 'Merz') +); + +$tpl = new HTML_Template_IT('./templates'); +$tpl->loadTemplatefile('main.tpl.htm', true, true); + +foreach ($data as $name) { + foreach ($name as $cell) { + // Assign data to the inner block + $tpl->setCurrentBlock('cell'); + $tpl->setVariable('DATA', $cell); + $tpl->parseCurrentBlock(); + } + // Assign data and the inner block to the + // outer block + $tpl->setCurrentBlock('row'); + $tpl->parseCurrentBlock(); +} +// print the output +$tpl->show(); +?> diff --git a/HTML_Template_IT-1.3.0/examples/sample_itx_addblockfile.php b/HTML_Template_IT-1.3.0/examples/sample_itx_addblockfile.php new file mode 100644 index 0000000..8bf7295 --- /dev/null +++ b/HTML_Template_IT-1.3.0/examples/sample_itx_addblockfile.php @@ -0,0 +1,58 @@ +'mypackage', + 'version' =>'1.0', + 'changelog' => array ('fix bug #002', + 'add author FOO to AUTHORS') + ), + array ('packagename'=>'mypackage', + 'version' =>'1.0 RC 1', + 'changelog' => array ('fix bug #002', + 'added method foo()') + ) + ); + +$tpl = new HTML_Template_ITX('./templates'); +$tpl->loadTemplatefile('addblockfile_main.tpl.htm', true, true); + +// The complete content of "addblockfile_main.tpl.htm" will be loaded into a block +// called "list_template". The placeholder {DESCRIPTION} will be replaced +// with the added block "list_template". +$tpl->addBlockfile('DESCRIPTION', 'list_template', 'addblockfile_list.tpl.htm'); + + +// we now have the following blocks loaded: +// __global__, row, list_template and listelement +// lets assign the data. +foreach ($data as $entry) { + // assign data to the inner block (listelement) of list_template. + $tpl->setCurrentBlock('listelement'); + foreach ($entry['changelog'] as $changelogentry) { + $tpl->setVariable('ENTRY', $changelogentry); + $tpl->parseCurrentBlock(); + } + + // assign data to the added list_template block + $tpl->setCurrentBlock('list_template'); + $tpl->setVariable('LISTNAME', $entry['version']); + $tpl->parseCurrentBlock(); + + // back in the original templatefile we assign data to the row block + // notice: + // {DESCRIPTION} is not longer available, because it was replaced by the + // list_template block + $tpl->setCurrentBlock('row'); + $tpl->setVariable('NAME', $entry['packagename']); + $tpl->parseCurrentBlock(); +} + +$tpl->show(); +?> diff --git a/HTML_Template_IT-1.3.0/examples/templates/addblockfile_list.tpl.htm b/HTML_Template_IT-1.3.0/examples/templates/addblockfile_list.tpl.htm new file mode 100644 index 0000000..879ba7a --- /dev/null +++ b/HTML_Template_IT-1.3.0/examples/templates/addblockfile_list.tpl.htm @@ -0,0 +1,6 @@ +{LISTNAME} +
    + +
  • {ENTRY}
  • + +
\ No newline at end of file diff --git a/HTML_Template_IT-1.3.0/examples/templates/addblockfile_main.tpl.htm b/HTML_Template_IT-1.3.0/examples/templates/addblockfile_main.tpl.htm new file mode 100644 index 0000000..07992d1 --- /dev/null +++ b/HTML_Template_IT-1.3.0/examples/templates/addblockfile_main.tpl.htm @@ -0,0 +1,12 @@ + + + + + + + + + +
{NAME}{DESCRIPTION}
+ + \ No newline at end of file diff --git a/HTML_Template_IT-1.3.0/examples/templates/main.tpl.htm b/HTML_Template_IT-1.3.0/examples/templates/main.tpl.htm new file mode 100644 index 0000000..d2da340 --- /dev/null +++ b/HTML_Template_IT-1.3.0/examples/templates/main.tpl.htm @@ -0,0 +1,13 @@ + + + + + + + + + +
+ {DATA} +
+ diff --git a/HTML_Template_IT-1.3.0/tests/AllTests.php b/HTML_Template_IT-1.3.0/tests/AllTests.php new file mode 100644 index 0000000..60c53eb --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/AllTests.php @@ -0,0 +1,36 @@ +addTestSuite('ITTest'); + $suite->addTestSuite('ITXTest'); + + return $suite; + } +} + +if (PHPUnit_MAIN_METHOD == 'HTML_Template_IT_AllTests::main') { + HTML_Template_IT_AllTests::main(); +} +?> diff --git a/HTML_Template_IT-1.3.0/tests/ITTest.php b/HTML_Template_IT-1.3.0/tests/ITTest.php new file mode 100644 index 0000000..808ef0e --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/ITTest.php @@ -0,0 +1,416 @@ +tpl = new HTML_Template_IT(dirname(__FILE__) . '/templates'); + } + + function tearDown() + { + unset($this->tpl); + } + + function _stripWhitespace($str) + { + return preg_replace('/\\s+/', '', $str); + } + + function _methodExists($name) + { + if (in_array(strtolower($name), get_class_methods($this->tpl))) { + return true; + } + $this->assertTrue(false, 'method '. $name . ' not implemented in ' . get_class($this->tpl)); + return false; + } + + /** + * Tests a setTemplate method + * + */ + function testSetTemplate() + { + $result = $this->tpl->setTemplate('A template', false, false); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error setting template: '. $result->getMessage()); + } + $this->assertEquals('A template', $this->tpl->get()); + } + + /** + * Tests a loadTemplatefile method + * + */ + function testLoadTemplatefile() + { + $result = $this->tpl->loadTemplatefile('loadtemplatefile.html', false, false); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $this->assertEquals('A template', trim($this->tpl->get())); + } + + /** + * Tests a setVariable method + * + */ + function testSetVariable() + { + $result = $this->tpl->setTemplate('{placeholder1} {placeholder2} {placeholder3}', true, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error setting template: '. $result->getMessage()); + } + // "scalar" call + $this->tpl->setVariable('placeholder1', 'var1'); + // array call + $this->tpl->setVariable(array( + 'placeholder2' => 'var2', + 'placeholder3' => 'var3' + )); + $this->assertEquals('var1 var2 var3', $this->tpl->get()); + } + + /** + * Tests the functionality + * + */ + function testInclude() + { + $result = $this->tpl->loadTemplateFile('include.html', false, false); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $this->assertEquals('Master file; Included file', trim($this->tpl->get())); + } + + /** + * + */ + function testCurrentBlock() + { + $result = $this->tpl->loadTemplateFile('blockiteration.html', true, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $this->tpl->setVariable('outer', 'a'); + $this->tpl->setCurrentBlock('inner_block'); + for ($i = 0; $i < 5; $i++) { + $this->tpl->setVariable('inner', $i + 1); + $this->tpl->parseCurrentBlock(); + } // for + $this->assertEquals('a|1|2|3|4|5#', $this->_stripWhitespace($this->tpl->get())); + } + + /** + * + */ + function testRemovePlaceholders() + { + $result = $this->tpl->setTemplate('{placeholder1},{placeholder2},{placeholder3}', true, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error setting template: '. $result->getMessage()); + } + // we do not set {placeholder3} + $this->tpl->setVariable(array( + 'placeholder1' => 'var1', + 'placeholder2' => 'var2' + )); + $this->assertEquals('var1,var2,', $this->tpl->get()); + + // Now, we should really add a switch for keeping {stuff} in + // data supplied to setVariable() safe. Until then, removing it should + // be expected behaviour + $result = $this->tpl->setTemplate('{placeholder1},{placeholder2},{placeholder3}', true, true); + $this->tpl->setOption('preserve_input', false); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error setting template: '. $result->getMessage()); + } + $this->tpl->setVariable(array( + 'placeholder1' => 'var1', + 'placeholder2' => 'var2', + 'placeholder3' => 'var3{stuff}' + )); + $this->assertEquals('var1,var2,var3', $this->tpl->get()); + + $result = $this->tpl->setTemplate('{placeholder1},{placeholder2},{placeholder3}', true, true); + $this->tpl->setOption('preserve_input', true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error setting template: '. $result->getMessage()); + } + $this->tpl->setVariable(array( + 'placeholder1' => 'var1', + 'placeholder2' => 'var2', + 'placeholder3' => 'var3{stuff}' + )); + $this->assertEquals('var1,var2,var3{stuff}', $this->tpl->get()); + + } + + /** + * + */ + function testTouchBlock() + { + $result = $this->tpl->loadTemplateFile('blockiteration.html', false, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $this->tpl->setVariable('outer', 'data'); + // inner_block should be preserved in output, even if empty + $this->tpl->touchBlock('inner_block'); + $this->assertEquals('data|{inner}#', $this->_stripWhitespace($this->tpl->get())); + } + + // Not available in stock class + + /** + * + */ + /* + function testHideBlock() + { + if (!$this->_methodExists('hideBlock')) { + return; + } + $result = $this->tpl->loadTemplateFile('blockiteration.html', false, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $this->tpl->setVariable(array( + 'outer' => 'data', + 'inner' => 'stuff' + )); + // inner_block is not empty, but should be removed nonetheless + $this->tpl->hideBlock('inner_block'); + $this->assertEquals('data#', $this->_stripWhitespace($this->tpl->get())); + } + */ + /** + * + */ + /* + function testSetGlobalVariable() + { + if (!$this->_methodExists('setGlobalVariable')) { + return; + } + $result = $this->tpl->loadTemplateFile('globals.html', false, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $this->tpl->setGlobalVariable('glob', 'glob'); + // {var2} is not, block_two should be removed + $this->tpl->setVariable(array( + 'var1' => 'one', + 'var3' => 'three' + )); + for ($i = 0; $i < 3; $i++) { + $this->tpl->setVariable('var4', $i + 1); + $this->tpl->parse('block_four'); + } // for + $this->assertEquals('glob:one#glob:three|glob:1|glob:2|glob:3#', $this->_stripWhitespace($this->tpl->get())); + } + */ + + + /** + * Test for bug #9501. preg_replace treat $ and \ as + * backreferences. IT escapes them. + * + */ + function testBug9501() + { + $this->tpl->setTemplate("Test: {VALUE}"); + $this->tpl->clearCache = true; + + $this->tpl->setVariable("VALUE", '$12.34'); + $this->assertEquals('Test: $12.34', $this->tpl->get()); + + $this->tpl->setVariable("VALUE", '$1256.34'); + $this->assertEquals('Test: $1256.34', $this->tpl->get()); + + $this->tpl->setVariable("VALUE", '^1.34'); + $this->assertEquals('Test: ^1.34', $this->tpl->get()); + + $this->tpl->setVariable("VALUE", '$1.34'); + $this->assertEquals('Test: $1.34', $this->tpl->get()); + + $this->tpl->setVariable("VALUE", '\$12.34'); + $this->assertEquals('Test: \$12.34', $this->tpl->get()); + + $this->tpl->setVariable("VALUE", "\$12.34"); + $this->assertEquals('Test: $12.34', $this->tpl->get()); + + $this->tpl->setVariable("VALUE", "\$12.34"); + $this->assertEquals('Test: $12.34', $this->tpl->get()); + + // $12 is not parsed as a variable as it starts with a number + $this->tpl->setVariable("VALUE", "$12.34"); + $this->assertEquals('Test: $12.34', $this->tpl->get()); + + $this->tpl->setVariable("VALUE", "\\$12.34"); + $this->assertEquals('Test: \$12.34', $this->tpl->get()); + + // taken from the bugreport + $word = 'Cost is $456.98'; + $this->tpl->setVariable("VALUE", $word); + $this->assertEquals('Test: Cost is $456.98', $this->tpl->get()); + + $word = "Cost is \$" . '183.22'; + $this->tpl->setVariable("VALUE", $word); + $this->assertEquals('Test: Cost is $183.22', $this->tpl->get()); + } + + function testBug9783 () + { + $this->tpl->setTemplate("{DATA} ", true, true); + $data = array ('{Bakken}', 'Soria', 'Joye'); + foreach ($data as $name) { + $this->tpl->setCurrentBlock('entry'); + $this->tpl->setVariable('DATA', $name); + $this->tpl->parseCurrentBlock(); + } + + $this->assertEquals('{Bakken} Soria Joye', trim($this->tpl->get())); + + } + + function testBug9853 () + { + $this->tpl->loadTemplatefile("bug_9853_01.tpl", true, true); + + $this->tpl->setVariable("VAR" , "Ok !"); + $this->tpl->parse("foo1"); + + $this->tpl->setVariable("VAR" , "Ok !"); + $this->tpl->parse("foo2"); + + $this->tpl->setVariable("VAR." , "Ok !"); + $this->tpl->setVariable("VAR2" , "Okay"); + $this->tpl->parse("bar"); + + $this->tpl->parse(); + $output01 = $this->tpl->get(); + + $this->tpl->loadTemplatefile("bug_9853_02.tpl", true, true); + + $this->tpl->setVariable("VAR" , "Ok !"); + $this->tpl->parse("foo."); + + $this->tpl->setVariable("VAR" , "Ok !"); + $this->tpl->parse("foo2"); + + $this->tpl->setVariable("VAR." , "Ok !"); + $this->tpl->setVariable("VAR2" , "Okay"); + $this->tpl->parse("bar"); + + $this->tpl->parse(); + $output02 = $this->tpl->get(); + + $this->assertEquals($output01, $output02); + } + + + /** + * Tests iterations over two blocks + * + */ + function testBlockIteration() + { + $data = array( + 'a', + array('b', array('1', '2', '3', '4')), + 'c', + array('d', array('5', '6', '7')) + ); + + $result = $this->tpl->loadTemplateFile('blockiteration.html', true, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + foreach ($data as $value) { + if (is_array($value)) { + $this->tpl->setVariable('outer', $value[0]); + foreach ($value[1] as $v) { + $this->tpl->setVariable('inner', $v); + $this->tpl->parse('inner_block'); + } + } else { + $this->tpl->setVariable('outer', $value); + } + $this->tpl->parse('outer_block'); + } + $this->assertEquals('a#b|1|2|3|4#c#d|5|6|7#', $this->_stripWhitespace($this->tpl->get())); + } + + /** + * + * + */ + function testTouchBlockIteration() + { + $data = array('a','b','c','d','e'); + $result = $this->tpl->loadTemplateFile('blockiteration.html', true, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + for ($i = 0; $i < count($data); $i++) { + $this->tpl->setVariable('outer', $data[$i]); + // the inner_block is empty and should be removed + if (0 == $i % 2) { + $this->tpl->touchBlock('inner_block'); + } + $this->tpl->parse('outer_block'); + } + $this->assertEquals('a|#b#c|#d#e|#', $this->_stripWhitespace($this->tpl->get())); + } + + public function testShouldSetOptionsCorrectly() { + $result = $this->tpl->setOption('removeEmptyBlocks', false); + + $this->assertFalse(PEAR::isError($result)); + + $this->assertFalse($this->tpl->removeEmptyBlocks); + + $result = $this->tpl->setOption('removeEmptyBlocks', true); + + $this->assertFalse(PEAR::isError($result)); + + $this->assertTrue($this->tpl->removeEmptyBlocks); + + } + + + public function testPlaceholderReplacementScope() { + $result = $this->tpl->loadTemplateFile('placeholderreplacementscope.html', true, true); + + if (PEAR::isError($result)) { + $this->fail('Error loading template file: ' . $result->getMessage()); + } + + + $this->tpl->setCurrentBlock('foo'); + $this->tpl->setVariable('var1','test'); + $this->tpl->parseCurrentBlock(); + $this->tpl->setCurrentBlock('bar'); + $this->tpl->setVariable('var1','not'); + $this->tpl->setVariable('var2','good'); + $this->tpl->parseCurrentBlock(); + + $actual = $this->_stripWhitespace($this->tpl->get()); + $this->assertEquals('testgood', $actual); + } + +} + +?> diff --git a/HTML_Template_IT-1.3.0/tests/ITXTest.php b/HTML_Template_IT-1.3.0/tests/ITXTest.php new file mode 100644 index 0000000..f481dfc --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/ITXTest.php @@ -0,0 +1,171 @@ +tpl = new HTML_Template_ITX(dirname(__FILE__) . '/templates'); + } + + function testPlaceholderExists() + { + $this->tpl->setTemplate('{var}'); + $this->assertSame("__global__", $this->tpl->placeholderExists('var'), 'Existing placeholder \'var\' reported as nonexistant'); + $this->assertSame("", $this->tpl->placeholderExists('foobar'), 'Nonexistant placeholder \'foobar\' reported as existing'); + $this->assertSame("__global__", $this->tpl->placeholderExists('var', '__global__'), 'Existing in block \'__global__\' placeholder \'var\' reported as nonexistant'); + $this->assertSame("", $this->tpl->placeholderExists('foobar', '__global__'), 'Nonexistant in block \'__global__\' placeholder \'foobar\' reported as existing'); + } + + function testBlockExists() + { + $this->tpl->setTemplate('{var}'); + $this->assertTrue($this->tpl->blockExists('__global__'), 'Existing block \'__global__\' reported as nonexistant'); + $this->assertTrue(!$this->tpl->blockExists('foobar'), 'Nonexistant block \'foobar\' reported as existing'); + } + + function testAddBlock() + { + $result = $this->tpl->loadTemplatefile('blocks.html', true, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $this->tpl->addBlock('var', 'added', 'added:{new_var}'); + $this->assertTrue($this->tpl->blockExists('added'), 'The new block seems to be missing'); + $this->assertTrue(!$this->tpl->placeholderExists('var'), 'The old variable seems to be still present in the template'); + $this->tpl->setVariable('new_var', 'new_value'); + $this->assertEquals('added:new_value', $this->_stripWhitespace($this->tpl->get())); + } + + function testAddBlockfile() + { + $result = $this->tpl->loadTemplatefile('blocks.html', true, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $result = $this->tpl->addBlockfile('var', 'added', 'addblock.html'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error adding block from file: '. $result->getMessage()); + } + $this->assertTrue($this->tpl->blockExists('added'), 'The new block seems to be missing'); + $this->assertTrue(!$this->tpl->placeholderExists('var'), 'The old variable seems to be still present in the template'); + $this->tpl->setVariable('new_var', 'new_value'); + $this->assertEquals('added:new_value', $this->_stripWhitespace($this->tpl->get())); + } + + function testReplaceBlock() + { + $result = $this->tpl->loadTemplatefile('blocks.html', true, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $this->tpl->setVariable('old_var', 'old_value'); + $this->tpl->parse('old_block'); + // old_block's contents should be discarded + $this->tpl->replaceBlock('old_block', 'replaced:{replaced_var}#', false); + $this->assertTrue(!$this->tpl->blockExists('old_inner_block') && !$this->tpl->placeholderExists('old_var'), + 'The replaced block\'s contents seem to be still present'); + $this->tpl->setVariable('replaced_var', 'replaced_value'); + $this->tpl->parse('old_block'); + // this time old_block's contents should be preserved + $this->tpl->replaceBlock('old_block', 'replaced_again:{brand_new_var}', true); + $this->tpl->setVariable('brand_new_var', 'brand_new_value'); + $this->assertEquals('replaced:replaced_value#replaced_again:brand_new_value', $this->_stripWhitespace($this->tpl->get())); + } + + function testReplaceBlockfile() + { + $result = $this->tpl->loadTemplatefile('blocks.html', true, true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading template file: '. $result->getMessage()); + } + $this->tpl->setVariable('old_var', 'old_value'); + $this->tpl->parse('old_block'); + // old_block's contents should be discarded + $result = $this->tpl->replaceBlockfile('old_block', 'replaceblock.html', false); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error replacing block from file: '. $result->getMessage()); + } + $this->assertTrue(!$this->tpl->blockExists('old_inner_block') && !$this->tpl->placeholderExists('old_var'), + 'The replaced block\'s contents seem to be still present'); + $this->tpl->setVariable(array( + 'replaced_var' => 'replaced_value', + 'replaced_inner_var' => 'inner_value' + )); + $this->tpl->parse('old_block'); + // this time old_block's contents should be preserved + $result = $this->tpl->replaceBlockfile('old_block', 'addblock.html', true); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error replacing block from file: '. $result->getMessage()); + } + $this->tpl->setVariable('new_var', 'again'); + $this->assertEquals('replaced:replaced_value|inner_value#added:again', $this->_stripWhitespace($this->tpl->get())); + } + + function testCallback() + { + $this->tpl->setTemplate('callback:func_uppercase(word)'); + $this->tpl->setCallbackFunction('uppercase', '_uppercaseCallback'); + $res = $this->tpl->performCallback(); + if (PEAR::isError($res)) { + $this->assertTrue(false, 'Error performing callback: '. $res->getMessage()); + } + $this->assertEquals('callback:WORD', $this->tpl->get()); + + $this->tpl->setTemplate('callback:func_lowercase(Word)'); + $this->tpl->setCallbackFunction('lowercase', array('Callbacks','_lowercaseCallback')); + $res = $this->tpl->performCallback(); + if (PEAR::isError($res)) { + $this->assertTrue(false, 'Error performing callback: '. $res->getMessage()); + } + $this->assertEquals('callback:word', $this->tpl->get()); + + $this->tpl->setTemplate('callback:func_lowercase(Word)'); + $this->tpl->setCallbackFunction('lowercase', array(new Callbacks,'_lowercaseCallback')); + $res = $this->tpl->performCallback(); + if (PEAR::isError($res)) { + $this->assertTrue(false, 'Error performing callback: '. $res->getMessage()); + } + $this->assertEquals('callback:word', $this->tpl->get()); + + $this->tpl->setTemplate('callback:func_numberFormat(1.5, 2)'); + $this->tpl->setCallbackFunction('numberFormat', array('Callbacks', '_numberFormatCallback'), '', true); + $res = $this->tpl->performCallback(); + if (PEAR::isError($res)) { + $this->assertTrue(false, 'Error performing callback: '. $res->getMessage()); + } + $this->assertEquals('callback:1.50', $this->tpl->get()); + + $this->tpl->setTemplate('callback:func_numberFormat(1.5, 2)'); + $GLOBALS['obj'] = new Callbacks; + $this->tpl->setCallbackFunction('numberFormat', '_numberFormatCallback', 'obj', true); + $res = $this->tpl->performCallback(); + if (PEAR::isError($res)) { + $this->assertTrue(false, 'Error performing callback: '. $res->getMessage()); + } + $this->assertEquals('callback:1.50', $this->tpl->get()); + } +} + +?> diff --git a/HTML_Template_IT-1.3.0/tests/templates/__include.html b/HTML_Template_IT-1.3.0/tests/templates/__include.html new file mode 100644 index 0000000..d5dc31c --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/__include.html @@ -0,0 +1 @@ +Included file diff --git a/HTML_Template_IT-1.3.0/tests/templates/addblock.html b/HTML_Template_IT-1.3.0/tests/templates/addblock.html new file mode 100644 index 0000000..9e19c4f --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/addblock.html @@ -0,0 +1 @@ +added:{new_var} diff --git a/HTML_Template_IT-1.3.0/tests/templates/blockiteration.html b/HTML_Template_IT-1.3.0/tests/templates/blockiteration.html new file mode 100644 index 0000000..111e823 --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/blockiteration.html @@ -0,0 +1,7 @@ + +{outer} + + |{inner} + +# + \ No newline at end of file diff --git a/HTML_Template_IT-1.3.0/tests/templates/blocks.html b/HTML_Template_IT-1.3.0/tests/templates/blocks.html new file mode 100644 index 0000000..f3110f2 --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/blocks.html @@ -0,0 +1,8 @@ +{var} + +old:{old_var} + + |{old_inner_var} + +# + diff --git a/HTML_Template_IT-1.3.0/tests/templates/bug_9853_01.tpl b/HTML_Template_IT-1.3.0/tests/templates/bug_9853_01.tpl new file mode 100644 index 0000000..cb4482c --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/bug_9853_01.tpl @@ -0,0 +1,20 @@ +############ TEST ################ + +before foo1 bloc + +In foo1...{VAR} + +after foo1 bloc + +before foo2 bloc + +In foo2...{VAR} + +after foo2 bloc + +before bar bloc + +In bar...{VAR.} +In bar...{VAR2} + +after bar bloc \ No newline at end of file diff --git a/HTML_Template_IT-1.3.0/tests/templates/bug_9853_02.tpl b/HTML_Template_IT-1.3.0/tests/templates/bug_9853_02.tpl new file mode 100644 index 0000000..93d7f60 --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/bug_9853_02.tpl @@ -0,0 +1,20 @@ +############ TEST ################ + +before foo1 bloc + +In foo1...{VAR} + +after foo1 bloc + +before foo2 bloc + +In foo2...{VAR} + +after foo2 bloc + +before bar bloc + +In bar...{VAR.} +In bar...{VAR2} + +after bar bloc \ No newline at end of file diff --git a/HTML_Template_IT-1.3.0/tests/templates/globals.html b/HTML_Template_IT-1.3.0/tests/templates/globals.html new file mode 100644 index 0000000..dc3e3b9 --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/globals.html @@ -0,0 +1,13 @@ + +{glob}:{var1}# + + +{glob}:{var2}# + + +{glob}:{var3} + + |{glob}:{var4} + +# + diff --git a/HTML_Template_IT-1.3.0/tests/templates/include.html b/HTML_Template_IT-1.3.0/tests/templates/include.html new file mode 100644 index 0000000..827cbf5 --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/include.html @@ -0,0 +1 @@ +Master file; diff --git a/HTML_Template_IT-1.3.0/tests/templates/loadtemplatefile.html b/HTML_Template_IT-1.3.0/tests/templates/loadtemplatefile.html new file mode 100644 index 0000000..7093929 --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/loadtemplatefile.html @@ -0,0 +1 @@ +A template diff --git a/HTML_Template_IT-1.3.0/tests/templates/placeholderreplacementscope.html b/HTML_Template_IT-1.3.0/tests/templates/placeholderreplacementscope.html new file mode 100644 index 0000000..7965b92 --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/placeholderreplacementscope.html @@ -0,0 +1,8 @@ + +{var1} + + +{var2} + + + diff --git a/HTML_Template_IT-1.3.0/tests/templates/replaceblock.html b/HTML_Template_IT-1.3.0/tests/templates/replaceblock.html new file mode 100644 index 0000000..03fcf77 --- /dev/null +++ b/HTML_Template_IT-1.3.0/tests/templates/replaceblock.html @@ -0,0 +1,5 @@ +replaced:{replaced_var} + + |{replaced_inner_var} + +# diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..e589163 --- /dev/null +++ b/package.xml @@ -0,0 +1,335 @@ + + + HTML_Template_IT + pear.php.net + Integrated Templates + HTML_Template_IT is a templating engine designed to allow easy separation of concerns. It does this by clearly separating the presentational code from the PHP code. The presentation code may be of any format, however generally XML or HTML is used. +This engine works on the foundation of blocks and placeholders. It uses the hierarchy of blocks to determine which presentational code is instantiated when blocks are parsed. The placeholders allow the insertion of "dynamic" information. +There are two classes to use for templating. HTML_Template_IT is used for basic templating needs. HTML_Template_ITX gives you full power over the templating engine, allowing blocks to be added, and function callbacks to be used. + + Gregory Currie + gregorycu + gregorycu@php.net + yes + + + Pierre-Alain Joye + pajoye + pajoye@php.net + no + + + David Soria Parra + dsp + dsp@php.net + no + + + Thorsten Rinne + thorstenr + thorstenr@php.net + no + + + Ulf Wendel + uw + ulf.wendel@phpdoc.de + no + + 2010-03-10 + + + 1.3.0 + 1.3.0 + + + stable + stable + + Modified BSD license + +Changes since last stable release (1.2.1): +- Add support for pear package 2.0 format +- Remove support for pear package 1.0 format +- Fix bug #9501, doller signs disapear if preg_match is used. +- Fix bug #9783, don't remove variable which values follow the variable pattern + To allow backwards compatbility an option preserve_input is added. + If it is false, the old behaviour will be used and therefore those values will be deleted. + Default is true, so new behaviour. +- Fix bug #9853, problems with dots in placeholders or blocknames +- Fix bug #13935, docblock is wrong +- Fix bug #17129 +- Add option 'preserve_input' to only remove unkown variable that were present + during setTemplate or loadTemplatefile + which is the behaviour before 1.3.0a1 +- Improved PHPCS (Request #15039) +- Added unit tests +- Fixed unit tests + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.0.0 + + + 1.4.0b1 + + + + + + + + 1.1 + 1.1 + + + stable + stable + + 2003-03-11 + Modified BSD license + +*BETA* release. + + + + + 1.1.1 + 1.1.1 + + + stable + stable + + 2003-08-21 + Modified BSD license + +- fix #4590, case sensitive method name getFile fix +- fix #1453, haltOnWarning fix, wrong property name called +- fix #3952, return IT_OK on success in setOptions + + + + + 1.1.2 + 1.1.2 + + + stable + stable + + 2005-10-28 + Modified BSD license + +- Comply better with the coding standards (dufuz@php.net) +- Fixed Bug #5774 ITX->buildFunctionlist, forced to use {} as delimiters + instead of the user defined once (dufuz@php.net) +- Fixed Bug #5642 Undefined variable: blockname (dufuz@php.net) + + + + + 1.1.3 + 1.1.3 + + + stable + stable + + 2005-11-01 + Modified BSD license + +- Change to the new BSD License + (see http://www.opensource.org/licenses/bsd-license.php) + + + + + 1.1.4 + 1.1.4 + + + stable + stable + + 2006-04-12 + Modified BSD license + +- #6084, fread raises warning when used with empty files +- #7359, remove notices when a block is not yet defined +- fix a bug introduced with some cleanup commit, in some cases, + callbacks did not work anymore + + + + + 1.1.5 + 1.1.5 + + + stable + stable + + 2006-06-13 + Modified BSD license + +- #7611, wrong array initialized, the same object cannot be + used for multiple templates + + + + + 1.2.0 + 1.2.0 + + + beta + beta + + 2006-08-17 + Modified BSD license + +- Deprecate $callbackobject parameter in setCallbackFunction +- Introduce $expandCallbackParameters parameter to setCallbackFunction to support + callbacks that expect to get the parameters in a regular way, not as an array +- #7651, allow dots in placeholder and block names + + + + + 1.2.1 + 1.2.1 + + + stable + stable + + 2006-08-25 + Modified BSD license + +- Deprecate $callbackobject parameter in setCallbackFunction +- Introduce $expandCallbackParameters parameter to setCallbackFunction to support + callbacks that expect to get the parameters in a regular way, not as an array +- #7651, allow dots in placeholder and block names +- #7611, wrong array initialized, the same object cannot be + used for multiple templates + + + + + 1.3.0a1 + 1.2.1 + + + alpha + stable + + 2010-02-15 + Modified BSD license + +- Add support for pear package 2.0 format +- Remove support for pear package 1.0 format +- Fix bug #9501, doller signs disapear if preg_match is used. +- Fix bug #9783, don't remove variable which values follow the variable pattern + To allow backwards compatbility an option preserve_input is added. + If it is false, the old behaviour will be used and therefore those values will be deleted. + Default is true, so new behaviour. +- Fix bug #9853, problems with dots in placeholders or blocknames +- Add option 'preserve_input' to only remove unkown variable that were present during setTemplate or lodaTemplatefile + which is the behaviour before 1.3.0a1 +- Fix bug #13935 - docblock is wrong +- Improved PHPCS (Request #15039) + + + + + 1.3.0a2 + 1.3.0 + + + alpha + stable + + 2010-02-16 + Modified BSD license + +Fixed unit tests + + + + + 1.3.0a3 + 1.3.0 + + + alpha + stable + + 2010-03-01 + Modified BSD license + +- Fix bug #17129 +- Added unit test + + + + + 1.3.0 + 1.3.0 + + + stable + stable + + 2010-03-10 + Modified BSD license + +Changes since last stable release (1.2.1): +- Add support for pear package 2.0 format +- Remove support for pear package 1.0 format +- Fix bug #9501, doller signs disapear if preg_match is used. +- Fix bug #9783, don't remove variable which values follow the variable pattern + To allow backwards compatbility an option preserve_input is added. + If it is false, the old behaviour will be used and therefore those values will be deleted. + Default is true, so new behaviour. +- Fix bug #9853, problems with dots in placeholders or blocknames +- Fix bug #13935, docblock is wrong +- Fix bug #17129 +- Add option 'preserve_input' to only remove unkown variable that were present + during setTemplate or loadTemplatefile + which is the behaviour before 1.3.0a1 +- Improved PHPCS (Request #15039) +- Added unit tests +- Fixed unit tests + + + +