home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 August / PCWorld_2001-08_cd.bin / Komunikace / phptriad / phptriadsetup2-11.exe / php / pear / HTML / ITX.php < prev    next >
PHP Script  |  2001-01-24  |  24KB  |  659 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0                                                      |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2001 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Ulf Wendel <ulf.wendel@phpdoc.de>                           |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: ITX.php,v 1.4 2001/01/24 11:19:28 sbergmann Exp $
  20. //
  21.  
  22. require_once "HTML/IT.php";
  23.  
  24. /**
  25. * Integrated Template Extension - ITX
  26. *
  27. * With this class you get the full power of the phplib template class. 
  28. * You may have one file with blocks in it but you have as well one main file 
  29. * and multiple files one for each block. This is quite usefull when you have
  30. * user configurable websites. Using blocks not in the main template allows
  31. * you to some parts of your layout easily. 
  32. *
  33. * Note that you can replace an existing block and add new blocks add runtime.
  34. * Adding new blocks means changing a variable placeholder to a block.
  35. *
  36. * @author     Ulf Wendel <uw@netuse.de>
  37. * @access        public
  38. * @version     $Id: ITX.php,v 1.4 2001/01/24 11:19:28 sbergmann Exp $
  39. */
  40. class IntegratedTemplateExtension extends IntegratedTemplate {
  41.  
  42.     /**
  43.     * Array with all warnings.
  44.     * @var       array
  45.     * @access    public
  46.     * @see       $printWarning, $haltOnWarning, warning()
  47.     */
  48.     var $warn = array();
  49.     
  50.     /**
  51.     * Print warnings?
  52.     * @var       array
  53.     * @access    public
  54.     * @see      $haltOnWarning, $warn, warning()
  55.     */
  56.     var $printWarning = false;
  57.     
  58.     /**
  59.     * Call die() on warning?
  60.     * @var         boolean
  61.     * @access    public
  62.     * @see       $warn, $printWarning, warning()
  63.     */
  64.     var $haltOnWarning = false;
  65.         
  66.     /**
  67.     * RegExp used to test for a valid blockname.
  68.     * @var    string
  69.     */    
  70.     var $checkblocknameRegExp = "";
  71.     
  72.     /**
  73.     * Functionnameprefix used when searching function calls in the template.
  74.     * @var    string
  75.     */
  76.     var $functionPrefix = "func_";
  77.     
  78.     /**
  79.     * Functionname RegExp.
  80.     * @var    string
  81.     */
  82.     var $functionnameRegExp = "[_a-zA-Z]+[A-Za-z_0-9]*";
  83.     
  84.     /**
  85.     * RegExp used to grep function calls in the template.
  86.     * 
  87.     * The variable gets set by the constructor.
  88.     * 
  89.     * @var    string
  90.     * @see    IntegratedTemplateExtension()
  91.     */
  92.     var $functionRegExp = "";
  93.     
  94.     /**
  95.     * List of functions found in the template.
  96.     *
  97.     * @var    array
  98.     */
  99.     var $functions         = array();
  100.     
  101.     /**
  102.     * List of callback functions specified by the user.
  103.     * 
  104.     * @var    array
  105.     */
  106.     var $callback         = array();
  107.     
  108.     /**
  109.     * Builds some complex regexps and calls the constructor of the parent class.
  110.     *
  111.     * Make sure that you call this constructor if you derive you own 
  112.     * template class from this one.
  113.     *
  114.     * @see    IntegratedTemplate()
  115.     */
  116.     function IntegratedTemplateExtension($root = "") {
  117.     
  118.         $this->checkblocknameRegExp = "@" . $this->blocknameRegExp . "@";
  119.         $this->functionRegExp = "@" . $this->functionPrefix . "(" . $this->functionnameRegExp . ")\s*\(@sm";
  120.         
  121.         $this->IntegratedTemplate($root);
  122.                                                                                             
  123.     } // end func constructor
  124.     
  125.     function init() {
  126.     
  127.         $this->free();
  128.         $this->buildFunctionlist();
  129.         $this->findBlocks($this->template);
  130.         $this->buildBlockvariablelist();
  131.         
  132.     } // end func init
  133.  
  134.     
  135.     /**
  136.     * Replaces an existing block with new content. Warning: not implemented yet.
  137.     * 
  138.     * The Replacement does not affect previously added variables. All data is cached.
  139.     * In case the new block does contain less or other variable placeholder the previously
  140.     * passed data that is no longer referenced will be deleted. The internal list 
  141.     * of allowed variables gets updated as well.
  142.     *
  143.     * In case the original block contains other blocks it must eighter have placeholder
  144.     * for the inner blocks or contain them. If you want to use placeholder the placeholder must
  145.     * look like openingDelimiter."__".blockname."__".closingDelimiter .
  146.     *
  147.     * Due to the cache updates replaceBlock() and replaceBlockfile() are "expensive" operations 
  148.     * which means extensive usage will slow down your script. So try to avoid them and if 
  149.     * you can't do so try to use them before you pass lots of variables to the block you're 
  150.     * replacing.
  151.     * 
  152.     * @param    string    Blockname
  153.     * @param    string    Blockcontent
  154.     * @return   boolean    
  155.     * @see      replaceBlockfile(), addBlock(), addBlockfile()
  156.     * @access   public
  157.     */
  158.     function replaceBlock($block, $template) {
  159.         if (!isset($this->blocklist[$block])) {
  160.             $this->halt("The block '$block' does not exist in the template and thus it can't be replaced.", __FILE__, __LINE__);
  161.             return false;
  162.         }
  163.         if (""==$template) {
  164.             $this->halt("No block content given.", __FILE__, __LINE__);
  165.             return false;
  166.         }
  167.         
  168.         print "This function has not been coded yet.";
  169.         
  170.         // find inner blocks
  171.         // add to variablelist
  172.         // compare variable list
  173.         // update caches
  174.         
  175.         return true;
  176.     } // end func replaceBlock
  177.     
  178.     /**
  179.     * Replaces an existing block with new content from a file. Warning: not implemented yet.
  180.     * @brother replaceBlock()
  181.     * @param    string    Blockname
  182.     * @param    string    Name of the file that contains the blockcontent
  183.     */
  184.     function replaceBlockfile($block, $filename) {
  185.         return $this->replaceBlock($block, $this->getFile($filename));    
  186.     } // end func replaceBlockfile
  187.     
  188.     /**
  189.     * Adds a block to the template changing a variable placeholder to a block placeholder.
  190.     *
  191.     * Add means "replace a variable placeholder by a new block". 
  192.     * This is different to PHPLibs templates. The function loads a 
  193.     * block, creates a handle for it and assigns it to a certain 
  194.     * variable placeholder. To to the same with PHPLibs templates you would 
  195.     * call set_file() to create the handle and parse() to assign the
  196.     * parsed block to a variable. By this PHPLibs templates assume that you tend
  197.     * to assign a block to more than one one placeholder. To assign a parsed block
  198.     * to more than only the placeholder you specify in this function you have
  199.     * to use a combination of getBlock() and setVariable().
  200.     *
  201.     * As no updates to cached data is necessary addBlock() and addBlockfile() 
  202.     * are rather "cheap" meaning quick operations.
  203.     *
  204.     * The block content must not start with <!-- BEGIN blockname --> and end with 
  205.     * <!-- END blockname --> this would cause overhead and produce an error.
  206.     * 
  207.     * @param    string    Name of the variable placeholder, the name must be unique within the template.
  208.     * @param    string    Name of the block to be added
  209.     * @param    string    Content of the block
  210.     * @return    boolean
  211.     * @see        addBlockfile()
  212.     * @access    public
  213.     */    
  214.     function addBlock($placeholder, $blockname, $template) {
  215.     
  216.         // Don't trust any user even if it's a programmer or yourself...
  217.         if ("" == $placeholder) {
  218.         
  219.             $this->halt("No variable placeholder given.", __FILE__, __LINE__);
  220.             return false;
  221.             
  222.         } else if ("" == $blockname || !preg_match($this->checkblocknameRegExp, $blockname) ) {
  223.             
  224.             print $this->checkblocknameRegExp;
  225.             $this->halt("No or invalid blockname '$blockname' given.", __FILE__, __LINE__);
  226.             return false;
  227.             
  228.         } else if ("" == $template) {
  229.         
  230.             $this->halt("No block content given.", __FILE__, __LINE__);
  231.             return false;
  232.             
  233.         } else if (isset($this->blocklist[$blockname])) {
  234.         
  235.             $this->halt("The block already exists.", __FILE__, __LINE__);
  236.             return false;
  237.             
  238.         }
  239.         
  240.         // Hmm, we should do some more tests.
  241.         $parents = $this->findPlaceholderBlocks($placeholder);
  242.         if (0 == count($parents)) {
  243.         
  244.             $this->halt("The variable placeholder '$placeholder' was not found in the template.", __FILE__, __LINE__);
  245.             return false;
  246.             
  247.         } else if ( count($parents) > 1 ) {
  248.             
  249.             reset($parents);
  250.             while (list($k, $parent) = each($parents)) 
  251.                 $msg .= "$parent, ";
  252.             $msg = substr($parent, -2);
  253.             
  254.             $this->halt("The variable placeholder '$placeholder' must be unique, found in multiple blocks '$msg'.", __FILE__, __LINE__);
  255.             return false;
  256.                         
  257.         }
  258.         
  259.         $template = "<!-- BEGIN $blockname -->" . $template . "<!-- END $blockname -->";
  260.         $this->findBlocks($template);
  261.         if ($this->flagBlocktrouble) 
  262.             return false;    // findBlocks() already throws an exception
  263.         
  264.         $this->blockinner[$parents[0]][] = $blockname;
  265.         $this->blocklist[$parents[0]] = preg_replace(   "@" . $this->openingDelimiter . $placeholder . $this->closingDelimiter . "@", 
  266.                                                         $this->openingDelimiter . "__" . $blockname . "__" . $this->closingDelimiter, 
  267.                                                         $this->blocklist[$parents[0]]
  268.                                                       );
  269.                                                                                                 
  270.         $this->deleteFromBlockvariablelist($parents[0], $placeholder);
  271.         $this->updateBlockvariablelist($blockname);
  272.         
  273.         return true;
  274.     } // end func addBlock
  275.     
  276.     /**
  277.     * Adds a block taken from a file to the template changing a variable placeholder to a block placeholder. 
  278.     * 
  279.     * @param      string    Name of the variable placeholder to be converted
  280.     * @param      string    Name of the block to be added
  281.     * @param      string    File that contains the block
  282.     * @brother    addBlock()
  283.     */
  284.     function addBlockfile($placeholder, $blockname, $filename) {
  285.         return $this->addBlock($placeholder, $blockname, $this->getFile($filename));
  286.     } // end func addBlockfile
  287.     
  288.     /**
  289.     * Returns the name of the (first) block that contains the specified placeholder.
  290.     * 
  291.     * @param    string  Name of the placeholder you're searching
  292.     * @param    string  Name of the block to scan. If left out (default) all blocks are scanned.
  293.     * @return   string  Name of the (first) block that contains the specified placeholder. 
  294.     *                   If the placeholder was not found or an error occured an empty string is returned.
  295.     * @access   public
  296.     */
  297.     function placeholderExists($placeholder, $block = "") {
  298.         
  299.         if ("" == $placeholder) {
  300.             $this->halt("No placeholder name given.", __FILE__, __LINE__);
  301.             return "";
  302.         }
  303.         
  304.         if ("" != $block && !isset($this->blocklist[$block])) {
  305.             $this->halt("Unknown block '$block'.", __FILE__, __LINE__);
  306.             return "";
  307.         }
  308.         
  309.         
  310.         // name of the block where the given placeholder was found
  311.         $found = "";
  312.         
  313.         if ("" != $block) {
  314.  
  315.             if (is_array($variables = $this->blockvariables[$block])) {
  316.             
  317.                 // search the value in the list of blockvariables
  318.                 reset($variables);
  319.                 while (list($k, $variable) = each($variables)) 
  320.                     if ($variable == $placeholder) {
  321.                         $found = $block;
  322.                         break;
  323.                     }
  324.                         
  325.             }
  326.                         
  327.         } else {
  328.         
  329.             // search all blocks and return the name of the first block that 
  330.             // contains the placeholder
  331.             reset($this->blockvariables);
  332.             while (list($blockname, $variables) = each($this->blockvariables)) {
  333.  
  334.                 reset($variables);
  335.                 while (list($k, $variable) = each($variables)) 
  336.                     if ($variable == $placeholder) {
  337.                         $found = $blockname;
  338.                         break 2;
  339.                     }
  340.  
  341.             }
  342.             
  343.         }
  344.         
  345.         return $found;
  346.     } // end func placeholderExists
  347.     
  348.     /**
  349.     * Checks the list of function calls in the template and calls their callback function.
  350.     *
  351.     *    @access    public
  352.     */
  353.     function performCallback() {
  354.     
  355.         reset($this->functions);
  356.         while (list($func_id, $function) = each($this->functions)) {
  357.             
  358.             if (isset($this->callback[$function["name"]])) {
  359.             
  360.                 if ("" != $this->callback[$function["name"]]["object"])
  361.                     $this->setFunctioncontent($func_id, 
  362.                                               call_user_method( 
  363.                                                                 $this->callback[$function["name"]]["function"], 
  364.                                                                 $GLOBALS[$this->callback[$function["name"]]["object"]],
  365.                                                                 $function["args"]
  366.                                                                )
  367.                                                   );
  368.                 else
  369.                     $this->setFunctioncontent(  $func_id, 
  370.                                                 call_user_func( 
  371.                                                                 $this->callback[$function["name"]]["function"], 
  372.                                                                 $function["args"]
  373.                                                                )
  374.                                                    );
  375.                                                                         
  376.             }
  377.             
  378.         }
  379.         
  380.     } // end func performCallback
  381.     
  382.     /**
  383.     * Returns a list of all function calls in the current template.
  384.     *
  385.     * @return array
  386.     * @access    public
  387.     */
  388.     function getFunctioncalls() {
  389.         
  390.         return $this->functions;
  391.         
  392.     } // end func getFunctioncalls
  393.     
  394.     /**
  395.     * Replaces a function call with the given replacement.
  396.     * 
  397.     * @param    int            Function ID
  398.     * @param    string    Replacement
  399.     * @access    public
  400.     */
  401.     function setFunctioncontent($functionID, $replacement) {
  402.         
  403.         $this->variableCache["__function" . $functionID . "__"] = $replacement;
  404.         
  405.     } // end func setFunctioncontent
  406.     
  407.     /**
  408.     * Sets a callback function.
  409.     * 
  410.     * @param    string    Function name in the template
  411.     * @param    string    Name of the callback function
  412.     * @param    string    Name of the callback object
  413.     * @return    boolean    False on failure.
  414.     * @access    public
  415.     */
  416.     function setCallbackFunction($tplfunction, $callbackfunction, $callbackobject = "") {
  417.         
  418.         if ("" == $tplfunction || "" == $callbackfunction) {
  419.             $this->halt("No template function ('$tplfunction') and/or no callback function ('$callback') given.", __FILE__, __LINE__);
  420.             return false;
  421.         }
  422.         
  423.         $this->callback[$tplfunction] = array(
  424.                                               "function"    => $callbackfunction,
  425.                                               "object"        => $callbackobject
  426.                                         );            
  427.  
  428.         return true;
  429.     } // end func setCallbackFunction
  430.     
  431.     /**
  432.     * Sets the Callback function lookup table
  433.     * 
  434.     * @param    array    function table - array[templatefunction] = array( "function" => userfunction, "object" => userobject )
  435.     * @access    public
  436.     */
  437.     function setCallbackFuntiontable($functions) {
  438.     
  439.         $this->callback = $functions;
  440.     
  441.     } // end func setCallbackFunctiontable
  442.     
  443.     /**
  444.     * Returns a list of blocknames in the template.
  445.     *
  446.     * @return    array    [blockname => blockname]
  447.     * @access    public
  448.     * @see        blockExists()
  449.     */
  450.     function getBlocklist() {
  451.     
  452.         $blocklist = array();
  453.         foreach ($this->blocklist as $block => $content) 
  454.             $blocklist[$block] = $block;
  455.             
  456.         return $blocklist;
  457.     } // end func getBlocklist
  458.  
  459.     /**
  460.     * Checks wheter a block exists.
  461.     * 
  462.     * @param    string    
  463.     * @return    boolean
  464.     * @access    public
  465.     * @see        getBlocklist()
  466.     */
  467.     function blockExists($blockname) {
  468.         return isset($this->blocklist[$blockname]);
  469.     } // end func blockExists
  470.     
  471.     /**
  472.     * Returns a list of variables of a block.
  473.     *
  474.     * @param    string    Blockname
  475.     * @return    array    [varname => varname]
  476.     * @access    public
  477.     * @see        BlockvariableExists()
  478.     */
  479.     function getBlockvariables($block) {
  480.         if (!isset($this->blockvariables[$block]))
  481.             return array();
  482.             
  483.         $variables = array();
  484.         foreach ($this->blockvariables as $variable => $v)
  485.             $variables[$variable] = $variable;
  486.             
  487.         return $variables;
  488.     } // end func getBlockvariables
  489.     
  490.     /**
  491.     * Checks wheter a block variable exists.
  492.     * 
  493.     * @param    string    Blockname
  494.     * @param    string    Variablename
  495.     * @return    boolean
  496.     * @access    public
  497.     * @see    getBlockvariables()
  498.     */
  499.     function BlockvariableExists($block, $variable) {
  500.         return isset($this->blockvariables[$block][$variable]);
  501.     } // end func BlockvariableExists
  502.     
  503.     /**
  504.     * Builds a functionlist from the template.
  505.     */
  506.     function buildFunctionlist() {
  507.         
  508.         $this->functions = array();
  509.         
  510.         $template = $this->template;
  511.         $num = 0;
  512.         
  513.         while (preg_match($this->functionRegExp, $template, $regs))    {
  514.         
  515.             $pos = strpos($template, $regs[0]);
  516.             $template = substr($template, $pos + strlen($regs[0]));
  517.             
  518.             $head = $this->getValue($template, ")");
  519.             $args = array();
  520.             
  521.             $this->template = str_replace($regs[0] . $head . ")", "{__function" . $num . "__}", $this->template);
  522.             $template = str_replace($regs[0] . $head . ")", "{__function" . $num . "__}", $template);
  523.             
  524.             while ("" != $head && $arg = $this->getValue($head, ",")) {
  525.                 $args[] = trim($arg);
  526.                 if ($arg == $head)                                     
  527.                     break;
  528.                 $head = substr($head, strlen($arg) + 1);
  529.             }    
  530.  
  531.             $this->functions[$num++] = array( 
  532.                                                 "name"    => $regs[1],
  533.                                                 "args"    => $args
  534.                                             );            
  535.         }
  536.  
  537.     } // end func buildFunctionlist
  538.     
  539.     
  540.     function getValue($code, $delimiter) {
  541.         if ("" == $code)
  542.             return "";
  543.     
  544.         if (!is_array($delimiter)) 
  545.             $delimiter = array( $delimiter => true );
  546.             
  547.         $len            = strlen($code);
  548.         $enclosed       = false;
  549.         $enclosed_by    = "";
  550.         
  551.         if (isset($delimiter[$code[0]])) {
  552.         
  553.             $i = 1;
  554.             
  555.         } else {
  556.         
  557.             for ($i = 0; $i < $len; ++$i) {
  558.             
  559.                 $char = $code[$i];
  560.  
  561.                 if (('"' == $char || "'" == $char) && ($char == $enclosed_by || "" == $enclosed_by) && (0 == $i || ($i > 0 && "\\" != $code[$i - 1]))) {
  562.                 
  563.                     if (!$enclosed)
  564.                         $enclosed_by = $char;
  565.                     else 
  566.                         $enclosed_by = "";
  567.                         
  568.                     $enclosed = !$enclosed;
  569.                     
  570.                 }
  571.                 if (!$enclosed && isset($delimiter[$char]))
  572.                     break;                    
  573.                     
  574.             }
  575.         
  576.         }
  577.   
  578.         return substr($code, 0, $i);
  579.     } // end func getValue
  580.  
  581.         
  582.     /**
  583.     * Deletes one or many variables from the block variable list.
  584.     *
  585.     * @param    string    Blockname
  586.     * @param    mixed        Name of one variable or array of variables ( array ( name => true ) ) to be stripped.
  587.     */
  588.     function deleteFromBlockvariablelist($block, $variables) {
  589.     
  590.         if (!is_array($variables))
  591.             $variables = array($variables => true);
  592.             
  593.         reset($this->blockvariables[$block]);
  594.         while (list($k, $varname) = each($this->blockvariables[$block])) 
  595.             if (isset($variables[$varname])) 
  596.                 unset($this->blockvariables[$block][$k]);
  597.                     
  598.     } // end deleteFromBlockvariablelist
  599.  
  600.     /**
  601.     * Updates the variable list of a block.
  602.     *
  603.     * @param    string    Blockname
  604.     */    
  605.     function updateBlockvariablelist($block) {
  606.         
  607.         preg_match_all( $this->variablesRegExp, $this->blocklist[$block], $regs );
  608.         $this->blockvariables[$block] = $regs[1];
  609.             
  610.     } // end func updateBlockvariablelist
  611.     
  612.     /**
  613.     * Returns an array of blocknames where the given variable placeholder is used.
  614.     *
  615.     * @param    string    Variable placeholder
  616.     * @return    array    $parents    parents[0..n] = blockname
  617.     */
  618.     function findPlaceholderBlocks($variable) {
  619.         
  620.         $parents = array();
  621.         
  622.         reset($this->blocklist);
  623.         while (list($blockname, $content) = each($this->blocklist)) {
  624.             
  625.             reset($this->blockvariables[$blockname]);
  626.             while (list($k, $varname) = each($this->blockvariables[$blockname]))
  627.                 if ($variable == $varname) 
  628.                     $parents[] = $blockname;
  629.         }
  630.             
  631.         return $parents;
  632.     } // end func findPlaceholderBlocks
  633.     
  634.     /**
  635.     * Handles warnings, saves them to $warn and prints them or calls die() depending on the flags
  636.     * @param    string    Warning
  637.     * @param    string    File where the warning occured
  638.     * @param    int       Linenumber where the warning occured
  639.     * @see      $warn, $printWarning, $haltOnWarning
  640.     */
  641.     function warning($message, $file="", $line=0) {
  642.         
  643.         $message = sprintf("IntegratedTemplateExtension Warning: %s [File: %s, Line: %d]",
  644.                                 $message,
  645.                                 $file, 
  646.                                 $line );
  647.  
  648.         $this->warn[] = $message;
  649.         
  650.         if ($this->printWarning)
  651.             print $message;
  652.             
  653.         if ($this->haltOnError) 
  654.             die($message);
  655.         
  656.     } // end func warning
  657.     
  658. } // end class IntegratedTemplateExtension
  659. ?>