| [ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 // 3 // +----------------------------------------------------------------------+ 4 // | Copyright (c) 1997-2005 Ulf Wendel, Pierre-Alain Joye | 5 // +----------------------------------------------------------------------+ 6 // | This source file is subject to the New BSD license, That is bundled | 7 // | with this package in the file LICENSE, and is available through | 8 // | the world-wide-web at | 9 // | http://www.opensource.org/licenses/bsd-license.php | 10 // | If you did not receive a copy of the new BSD license and are unable | 11 // | to obtain it through the world-wide-web, please send a note to | 12 // | pajoye@php.net so we can mail you a copy immediately. | 13 // +----------------------------------------------------------------------+ 14 // | Author: Ulf Wendel <ulf.wendel@phpdoc.de> | 15 // | Pierre-Alain Joye <pajoye@php.net> | 16 // +----------------------------------------------------------------------+ 17 // 18 // $Id: ITX.php,v 1.16 2006/08/17 15:47:22 dsp Exp $ 19 // 20 21 require_once 'HTML/Template/IT.php'; 22 require_once 'HTML/Template/IT_Error.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 modify some parts of your layout easily. 32 * 33 * Note that you can replace an existing block and add new blocks at 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.16 2006/08/17 15:47:22 dsp Exp $ 39 * @package HTML_Template_IT 40 */ 41 class HTML_Template_ITX extends HTML_Template_IT 42 { 43 /** 44 * Array with all warnings. 45 * @var array 46 * @access public 47 * @see $printWarning, $haltOnWarning, warning() 48 */ 49 var $warn = array(); 50 51 /** 52 * Print warnings? 53 * @var array 54 * @access public 55 * @see $haltOnWarning, $warn, warning() 56 */ 57 var $printWarning = false; 58 59 /** 60 * Call die() on warning? 61 * @var boolean 62 * @access public 63 * @see $warn, $printWarning, warning() 64 */ 65 var $haltOnWarning = false; 66 67 /** 68 * RegExp used to test for a valid blockname. 69 * @var string 70 */ 71 var $checkblocknameRegExp = ''; 72 73 /** 74 * Functionnameprefix used when searching function calls in the template. 75 * @var string 76 */ 77 var $functionPrefix = 'func_'; 78 79 /** 80 * Functionname RegExp. 81 * @var string 82 */ 83 var $functionnameRegExp = '[_a-zA-Z]+[A-Za-z_0-9]*'; 84 85 /** 86 * RegExp used to grep function calls in the template. 87 * 88 * The variable gets set by the constructor. 89 * 90 * @var string 91 * @see HTML_Template_IT() 92 */ 93 var $functionRegExp = ''; 94 95 /** 96 * List of functions found in the template. 97 * 98 * @var array 99 */ 100 var $functions = array(); 101 102 /** 103 * List of callback functions specified by the user. 104 * 105 * @var array 106 */ 107 var $callback = array(); 108 109 /** 110 * Builds some complex regexps and calls the constructor 111 * of the parent class. 112 * 113 * Make sure that you call this constructor if you derive your own 114 * template class from this one. 115 * 116 * @see HTML_Template_IT() 117 */ 118 function HTML_Template_ITX($root = '') 119 { 120 121 $this->checkblocknameRegExp = '@' . $this->blocknameRegExp . '@'; 122 $this->functionRegExp = '@' . $this->functionPrefix . '(' . 123 $this->functionnameRegExp . ')\s*\(@sm'; 124 125 $this->HTML_Template_IT($root); 126 } // end func constructor 127 128 function init() 129 { 130 $this->free(); 131 $this->buildFunctionlist(); 132 $this->findBlocks($this->template); 133 // we don't need it any more 134 $this->template = ''; 135 $this->buildBlockvariablelist(); 136 137 } // end func init 138 139 /** 140 * Replaces an existing block with new content. 141 * 142 * This function will replace a block of the template and all blocks 143 * contained in the replaced block and add a new block insted, means 144 * you can dynamically change your template. 145 * 146 * Note that changing the template structure violates one of the IT[X] 147 * development goals. I've tried to write a simple to use template engine 148 * supporting blocks. In contrast to other systems IT[X] analyses the way 149 * you've nested blocks and knows which block belongs into another block. 150 * The nesting information helps to make the API short and simple. Replacing 151 * blocks does not only mean that IT[X] has to update the nesting 152 * information (relatively time consumpting task) but you have to make sure 153 * that you do not get confused due to the template change itself. 154 * 155 * @param string Blockname 156 * @param string Blockcontent 157 * @param boolean true if the new block inherits the content 158 * of the old block 159 * @return boolean 160 * @throws IT_Error 161 * @see replaceBlockfile(), addBlock(), addBlockfile() 162 * @access public 163 */ 164 function replaceBlock($block, $template, $keep_content = false) 165 { 166 if (!isset($this->blocklist[$block])) { 167 return new IT_Error( 168 "The block "."'$block'". 169 " does not exist in the template and thus it can't be replaced.", 170 __FILE__, __LINE__ 171 ); 172 } 173 174 if ($template == '') { 175 return new IT_Error('No block content given.', __FILE__, __LINE__); 176 } 177 178 if ($keep_content) { 179 $blockdata = $this->blockdata[$block]; 180 } 181 182 // remove all kinds of links to the block / data of the block 183 $this->removeBlockData($block); 184 185 $template = "<!-- BEGIN $block -->" . $template . "<!-- END $block -->"; 186 $parents = $this->blockparents[$block]; 187 $this->findBlocks($template); 188 $this->blockparents[$block] = $parents; 189 190 // KLUDGE: rebuild the list for all block - could be done faster 191 $this->buildBlockvariablelist(); 192 193 if ($keep_content) { 194 $this->blockdata[$block] = $blockdata; 195 } 196 197 // old TODO - I'm not sure if we need this 198 // update caches 199 200 return true; 201 } // end func replaceBlock 202 203 /** 204 * Replaces an existing block with new content from a file. 205 * 206 * @brother replaceBlock() 207 * @param string Blockname 208 * @param string Name of the file that contains the blockcontent 209 * @param boolean true if the new block inherits the content of the old block 210 * @access public 211 */ 212 function replaceBlockfile($block, $filename, $keep_content = false) 213 { 214 return $this->replaceBlock($block, $this->getFile($filename), $keep_content); 215 } // end func replaceBlockfile 216 217 /** 218 * Adds a block to the template changing a variable placeholder 219 * to a block placeholder. 220 * 221 * Add means "replace a variable placeholder by a new block". 222 * This is different to PHPLibs templates. The function loads a 223 * block, creates a handle for it and assigns it to a certain 224 * variable placeholder. To to the same with PHPLibs templates you would 225 * call set_file() to create the handle and parse() to assign the 226 * parsed block to a variable. By this PHPLibs templates assume 227 * that you tend to assign a block to more than one one placeholder. 228 * To assign a parsed block to more than only the placeholder you specify 229 * in this function you have to use a combination of getBlock() 230 * and setVariable(). 231 * 232 * As no updates to cached data is necessary addBlock() and addBlockfile() 233 * are rather "cheap" meaning quick operations. 234 * 235 * The block content must not start with <!-- BEGIN blockname --> 236 * and end with <!-- END blockname --> this would cause overhead and 237 * produce an error. 238 * 239 * @param string Name of the variable placeholder, the name must be unique 240 * within the template. 241 * @param string Name of the block to be added 242 * @param string Content of the block 243 * @return boolean 244 * @throws IT_Error 245 * @see addBlockfile() 246 * @access public 247 */ 248 function addBlock($placeholder, $blockname, $template) 249 { 250 // Don't trust any user even if it's a programmer or yourself... 251 if ($placeholder == '') { 252 return new IT_Error('No variable placeholder given.', 253 __FILE__, __LINE__ 254 ); 255 } elseif ($blockname == '' || 256 !preg_match($this->checkblocknameRegExp, $blockname) 257 ) { 258 return new IT_Error("No or invalid blockname '$blockname' given.", 259 __FILE__, __LINE__ 260 ); 261 } elseif ($template == '') { 262 return new IT_Error('No block content given.', __FILE__, __LINE__); 263 } elseif (isset($this->blocklist[$blockname])) { 264 return new IT_Error('The block already exists.', 265 __FILE__, __LINE__ 266 ); 267 } 268 269 // find out where to insert the new block 270 $parents = $this->findPlaceholderBlocks($placeholder); 271 if (count($parents) == 0) { 272 273 return new IT_Error( 274 "The variable placeholder". 275 " '$placeholder' was not found in the template.", 276 __FILE__, __LINE__ 277 ); 278 279 } elseif (count($parents) > 1) { 280 281 reset($parents); 282 while (list($k, $parent) = each($parents)) { 283 $msg .= "$parent, "; 284 } 285 $msg = substr($parent, -2); 286 287 return new IT_Error("The variable placeholder "."'$placeholder'". 288 " must be unique, found in multiple blocks '$msg'.", 289 __FILE__, __LINE__ 290 ); 291 } 292 293 $template = "<!-- BEGIN $blockname -->" . $template . "<!-- END $blockname -->"; 294 $this->findBlocks($template); 295 if ($this->flagBlocktrouble) { 296 return false; // findBlocks() already throws an exception 297 } 298 $this->blockinner[$parents[0]][] = $blockname; 299 $this->blocklist[$parents[0]] = preg_replace( 300 '@' . $this->openingDelimiter . $placeholder . 301 $this->closingDelimiter . '@', 302 303 $this->openingDelimiter . '__' . $blockname . '__' . 304 $this->closingDelimiter, 305 306 $this->blocklist[$parents[0]] 307 ); 308 309 $this->deleteFromBlockvariablelist($parents[0], $placeholder); 310 $this->updateBlockvariablelist($blockname); 311 312 return true; 313 } // end func addBlock 314 315 /** 316 * Adds a block taken from a file to the template changing a variable 317 * placeholder to a block placeholder. 318 * 319 * @param string Name of the variable placeholder to be converted 320 * @param string Name of the block to be added 321 * @param string File that contains the block 322 * @brother addBlock() 323 * @access public 324 */ 325 function addBlockfile($placeholder, $blockname, $filename) 326 { 327 return $this->addBlock($placeholder, $blockname, $this->getFile($filename)); 328 } // end func addBlockfile 329 330 /** 331 * Returns the name of the (first) block that contains 332 * the specified placeholder. 333 * 334 * @param string Name of the placeholder you're searching 335 * @param string Name of the block to scan. If left out (default) 336 * all blocks are scanned. 337 * @return string Name of the (first) block that contains 338 * the specified placeholder. 339 * If the placeholder was not found or an error occured 340 * an empty string is returned. 341 * @throws IT_Error 342 * @access public 343 */ 344 function placeholderExists($placeholder, $block = '') 345 { 346 if ($placeholder == '') { 347 new IT_Error('No placeholder name given.', __FILE__, __LINE__); 348 return ''; 349 } 350 351 if ($block != '' && !isset($this->blocklist[$block])) { 352 new IT_Error("Unknown block '$block'.", __FILE__, __LINE__); 353 return ''; 354 } 355 356 // name of the block where the given placeholder was found 357 $found = ''; 358 359 if ($block != '') { 360 if (is_array($variables = $this->blockvariables[$block])) { 361 // search the value in the list of blockvariables 362 reset($variables); 363 while (list($k, $variable) = each($variables)) { 364 if ($k == $placeholder) { 365 $found = $block; 366 break; 367 } 368 } 369 } 370 } else { 371 372 // search all blocks and return the name of the first block that 373 // contains the placeholder 374 reset($this->blockvariables); 375 while (list($blockname, $variables) = each($this->blockvariables)){ 376 if (is_array($variables) && isset($variables[$placeholder])) { 377 $found = $blockname; 378 break; 379 } 380 } 381 } 382 383 return $found; 384 } // end func placeholderExists 385 386 /** 387 * Checks the list of function calls in the template and 388 * calls their callback function. 389 * 390 * @access public 391 */ 392 function performCallback() 393 { 394 reset($this->functions); 395 while (list($func_id, $function) = each($this->functions)) { 396 if (isset($this->callback[$function['name']])) { 397 if ($this->callback[$function['name']]['expandParameters']) { 398 $callFunction = 'call_user_func_array'; 399 } else { 400 $callFunction = 'call_user_func'; 401 } 402 403 if ($this->callback[$function['name']]['object'] != '') { 404 $call = 405 $callFunction( 406 array( 407 &$GLOBALS[$this->callback[$function['name']]['object']], 408 $this->callback[$function['name']]['function']), 409 $function['args'] 410 ); 411 412 } else { 413 $call = 414 $callFunction( 415 $this->callback[$function['name']]['function'], 416 $function['args'] 417 ); 418 } 419 $this->variableCache['__function' . $func_id . '__'] = $call; 420 } 421 } 422 423 } // end func performCallback 424 425 /** 426 * Returns a list of all function calls in the current template. 427 * 428 * @return array 429 * @access public 430 */ 431 function getFunctioncalls() 432 { 433 return $this->functions; 434 } // end func getFunctioncalls 435 436 /** 437 * Replaces a function call with the given replacement. 438 * 439 * @param int Function ID 440 * @param string Replacement 441 * @deprecated 442 */ 443 function setFunctioncontent($functionID, $replacement) 444 { 445 $this->variableCache['__function' . $functionID . '__'] = $replacement; 446 } // end func setFunctioncontent 447 448 /** 449 * Sets a callback function. 450 * 451 * IT[X] templates (note the X) can contain simple function calls. 452 * "function call" means that the editor of the template can add 453 * special placeholder to the template like 'func_h1("embedded in h1")'. 454 * IT[X] will grab this function calls and allow you to define a callback 455 * function for them. 456 * 457 * This is an absolutely evil feature. If your application makes heavy 458 * use of such callbacks and you're even implementing if-then etc. on 459 * the level of a template engine you're reiventing the wheel... - that's 460 * actually how PHP came into life. Anyway, sometimes it's handy. 461 * 462 * Consider also using XML/XSLT or native PHP. And please do not push 463 * IT[X] any further into this direction of adding logics to the template 464 * engine. 465 * 466 * For those of you ready for the X in IT[X]: 467 * 468 * <?php 469 * ... 470 * function h_one($args) { 471 * return sprintf('<h1>%s</h1>', $args[0]); 472 * } 473 * 474 * ... 475 * $itx = new HTML_Template_ITX( ... ); 476 * ... 477 * $itx->setCallbackFunction('h1', 'h_one'); 478 * $itx->performCallback(); 479 * ?> 480 * 481 * template: 482 * func_h1('H1 Headline'); 483 * 484 * @param string Function name in the template 485 * @param string Name of the callback function 486 * @param string Name of the callback object 487 * @param boolean If the callback is called with a list of parameters or 488 * with an array holding the parameters 489 * @return boolean False on failure. 490 * @throws IT_Error 491 * @access public 492 * @deprecated The $callbackobject parameter is depricated since 493 * version 1.2 and might be dropped in further versions. 494 */ 495 function 496 setCallbackFunction($tplfunction, $callbackfunction, $callbackobject = '', $expandCallbackParameters=false) 497 { 498 if ($tplfunction == '' || $callbackfunction == '') { 499 return new IT_Error( 500 "No template function "."('$tplfunction')". 501 " and/or no callback function ('$callback') given.", 502 __FILE__, __LINE__ 503 ); 504 } 505 $this->callback[$tplfunction] = array( 506 'function' => $callbackfunction, 507 'object' => $callbackobject, 508 'expandParameters' => (boolean) $expandCallbackParameters 509 ); 510 511 return true; 512 } // end func setCallbackFunction 513 514 /** 515 * Sets the Callback function lookup table 516 * 517 * @param array function table 518 * array[templatefunction] = 519 * array( 520 * "function" => userfunction, 521 * "object" => userobject 522 * ) 523 * @access public 524 */ 525 function setCallbackFuntiontable($functions) 526 { 527 $this->callback = $functions; 528 } // end func setCallbackFunctiontable 529 530 /** 531 * Recursively removes all data assiciated with a block, including all inner blocks 532 * 533 * @param string block to be removed 534 * @access private 535 */ 536 function removeBlockData($block) 537 { 538 if (isset($this->blockinner[$block])) { 539 foreach ($this->blockinner[$block] as $k => $inner) { 540 $this->removeBlockData($inner); 541 } 542 543 unset($this->blockinner[$block]); 544 } 545 546 unset($this->blocklist[$block]); 547 unset($this->blockdata[$block]); 548 unset($this->blockvariables[$block]); 549 unset($this->touchedBlocks[$block]); 550 551 } // end func removeBlockinner 552 553 /** 554 * Returns a list of blocknames in the template. 555 * 556 * @return array [blockname => blockname] 557 * @access public 558 * @see blockExists() 559 */ 560 function getBlocklist() 561 { 562 $blocklist = array(); 563 foreach ($this->blocklist as $block => $content) { 564 $blocklist[$block] = $block; 565 } 566 567 return $blocklist; 568 } // end func getBlocklist 569 570 /** 571 * Checks wheter a block exists. 572 * 573 * @param string 574 * @return boolean 575 * @access public 576 * @see getBlocklist() 577 */ 578 function blockExists($blockname) 579 { 580 return isset($this->blocklist[$blockname]); 581 } // end func blockExists 582 583 /** 584 * Returns a list of variables of a block. 585 * 586 * @param string Blockname 587 * @return array [varname => varname] 588 * @access public 589 * @see BlockvariableExists() 590 */ 591 function getBlockvariables($block) 592 { 593 if (!isset($this->blockvariables[$block])) { 594 return array(); 595 } 596 597 $variables = array(); 598 foreach ($this->blockvariables[$block] as $variable => $v) { 599 $variables[$variable] = $variable; 600 } 601 602 return $variables; 603 } // end func getBlockvariables 604 605 /** 606 * Checks wheter a block variable exists. 607 * 608 * @param string Blockname 609 * @param string Variablename 610 * @return boolean 611 * @access public 612 * @see getBlockvariables() 613 */ 614 function BlockvariableExists($block, $variable) 615 { 616 return isset($this->blockvariables[$block][$variable]); 617 } // end func BlockvariableExists 618 619 /** 620 * Builds a functionlist from the template. 621 * @access private 622 */ 623 function buildFunctionlist() 624 { 625 $this->functions = array(); 626 627 $template = $this->template; 628 $num = 0; 629 630 while (preg_match($this->functionRegExp, $template, $regs)) { 631 632 $pos = strpos($template, $regs[0]); 633 $template = substr($template, $pos + strlen($regs[0])); 634 635 $head = $this->getValue($template, ')'); 636 $args = array(); 637 638 $search = $regs[0] . $head . ')'; 639 640 $replace = $this->openingDelimiter . 641 '__function' . $num . '__' . 642 $this->closingDelimiter; 643 644 $this->template = str_replace($search, $replace, $this->template); 645 $template = str_replace($search, $replace, $template); 646 647 while ($head != '' && $args2 = $this->getValue($head, ',')) { 648 $arg2 = trim($args2); 649 $args[] = ('"' == $arg2{0} || "'" == $arg2{0}) ? 650 substr($arg2, 1, -1) : $arg2; 651 if ($arg2 == $head) { 652 break; 653 } 654 $head = substr($head, strlen($arg2) + 1); 655 } 656 657 $this->functions[$num++] = array( 658 'name' => $regs[1], 659 'args' => $args 660 ); 661 } 662 663 } // end func buildFunctionlist 664 665 /** 666 * Truncates the given code from the first occurence of 667 * $delimiter but ignores $delimiter enclosed by " or '. 668 * 669 * @access private 670 * @param string The code which should be parsed 671 * @param string The delimiter char 672 * @return string 673 * @see buildFunctionList() 674 */ 675 function getValue($code, $delimiter) { 676 if ($code == '') { 677 return ''; 678 } 679 680 if (!is_array($delimiter)) { 681 $delimiter = array( $delimiter => true ); 682 } 683 684 $len = strlen($code); 685 $enclosed = false; 686 $enclosed_by = ''; 687 688 if (isset($delimiter[$code[0]])) { 689 $i = 1; 690 } else { 691 for ($i = 0; $i < $len; ++$i) { 692 $char = $code[$i]; 693 694 if ( 695 ($char == '"' || $char == "'") && 696 ($char == $enclosed_by || '' == $enclosed_by) && 697 (0 == $i || ($i > 0 && '\\' != $code[$i - 1])) 698 ) { 699 700 if (!$enclosed) { 701 $enclosed_by = $char; 702 } else { 703 $enclosed_by = ""; 704 } 705 $enclosed = !$enclosed; 706 707 } 708 709 if (!$enclosed && isset($delimiter[$char])) { 710 break; 711 } 712 } 713 } 714 715 return substr($code, 0, $i); 716 } // end func getValue 717 718 /** 719 * Deletes one or many variables from the block variable list. 720 * 721 * @param string Blockname 722 * @param mixed Name of one variable or array of variables 723 * ( array ( name => true ) ) to be stripped. 724 * @access private 725 */ 726 function deleteFromBlockvariablelist($block, $variables) 727 { 728 if (!is_array($variables)) { 729 $variables = array($variables => true); 730 } 731 732 reset($this->blockvariables[$block]); 733 while (list($varname, $val) = each($this->blockvariables[$block])) { 734 if (isset($variables[$varname])) { 735 unset($this->blockvariables[$block][$varname]); 736 } 737 } 738 } // end deleteFromBlockvariablelist 739 740 /** 741 * Updates the variable list of a block. 742 * 743 * @param string Blockname 744 * @access private 745 */ 746 function updateBlockvariablelist($block) 747 { 748 preg_match_all( $this->variablesRegExp, 749 $this->blocklist[$block], $regs 750 ); 751 752 if (count($regs[1]) != 0) { 753 foreach ($regs[1] as $k => $var) { 754 $this->blockvariables[$block][$var] = true; 755 } 756 } else { 757 $this->blockvariables[$block] = array(); 758 } 759 760 // check if any inner blocks were found 761 if (isset($this->blockinner[$block]) && 762 is_array($this->blockinner[$block]) && 763 count($this->blockinner[$block]) > 0 764 ) { 765 /* 766 * loop through inner blocks, registering the variable 767 * placeholders in each 768 */ 769 foreach ($this->blockinner[$block] as $childBlock) { 770 $this->updateBlockvariablelist($childBlock); 771 } 772 } 773 } // end func updateBlockvariablelist 774 775 /** 776 * Returns an array of blocknames where the given variable 777 * placeholder is used. 778 * 779 * @param string Variable placeholder 780 * @return array $parents parents[0..n] = blockname 781 * @access public 782 */ 783 function findPlaceholderBlocks($variable) 784 { 785 $parents = array(); 786 reset($this->blocklist); 787 while (list($blockname, $content) = each($this->blocklist)) { 788 reset($this->blockvariables[$blockname]); 789 while ( 790 list($varname, $val) = each($this->blockvariables[$blockname])) 791 { 792 if ($variable == $varname) { 793 $parents[] = $blockname; 794 } 795 } 796 } 797 798 return $parents; 799 } // end func findPlaceholderBlocks 800 801 /** 802 * Handles warnings, saves them to $warn and prints them or 803 * calls die() depending on the flags 804 * 805 * @param string Warning 806 * @param string File where the warning occured 807 * @param int Linenumber where the warning occured 808 * @see $warn, $printWarning, $haltOnWarning 809 * @access private 810 */ 811 function warning($message, $file = '', $line = 0) 812 { 813 $message = sprintf( 814 'HTML_Template_ITX Warning: %s [File: %s, Line: %d]', 815 $message, 816 $file, 817 $line 818 ); 819 820 $this->warn[] = $message; 821 822 if ($this->printWarning) { 823 print $message; 824 } 825 826 if ($this->haltOnWarning) { 827 die($message); 828 } 829 } // end func warning 830 831 } // end class HTML_Template_ITX 832 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |