[ Index ] |
|
Code source de PHP PEAR 1.4.5 |
1 <?php 2 // +---------------------------------------------------------------------+ 3 // | PHP Version 4 | 4 // +---------------------------------------------------------------------+ 5 // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group | 6 // +---------------------------------------------------------------------+ 7 // | This source file is subject to version 2.0 of the PHP license, | 8 // | that is bundled with this package in the file LICENSE, and is | 9 // | available at through the world-wide-web at | 10 // | http://www.php.net/license/2_02.txt. | 11 // | If you did not receive a copy of the PHP license and are unable to | 12 // | obtain it through the world-wide-web, please send a note to | 13 // | license@php.net so we can mail you a copy immediately. | 14 // +---------------------------------------------------------------------+ 15 // | Author: Bertrand Mansion <bmansion@mamasam.com> | 16 // +---------------------------------------------------------------------+ 17 // 18 // $Id: Container.php,v 1.41 2006/05/30 06:37:28 aashley Exp $ 19 20 require_once 'Config.php'; 21 22 /** 23 * Interface for Config containers 24 * 25 * @author Bertrand Mansion <bmansion@mamasam.com> 26 * @package Config 27 */ 28 class Config_Container { 29 30 /** 31 * Container object type 32 * Ex: section, directive, comment, blank 33 * @var string 34 */ 35 var $type; 36 37 /** 38 * Container object name 39 * @var string 40 */ 41 var $name = ''; 42 43 /** 44 * Container object content 45 * @var string 46 */ 47 var $content = ''; 48 49 /** 50 * Container object children 51 * @var array 52 */ 53 var $children = array(); 54 55 /** 56 * Reference to container object's parent 57 * @var object 58 */ 59 var $parent; 60 61 /** 62 * Array of attributes for this item 63 * @var array 64 */ 65 var $attributes; 66 67 /** 68 * Unique id to differenciate nodes 69 * 70 * This is used to compare nodes 71 * Will not be needed anymore when this class will use ZendEngine 2 72 * 73 * @var int 74 */ 75 var $_id; 76 77 /** 78 * Constructor 79 * 80 * @param string $type Type of container object 81 * @param string $name Name of container object 82 * @param string $content Content of container object 83 * @param array $attributes Array of attributes for container object 84 */ 85 function Config_Container($type = 'section', $name = '', $content = '', $attributes = null) 86 { 87 $this->type = $type; 88 $this->name = $name; 89 $this->content = $content; 90 $this->attributes = $attributes; 91 $this->parent = null; 92 if (version_compare(PHP_VERSION, '5.0.0', 'gt')) { 93 $this->_id = uniqid($name.$type, true); 94 } else { 95 $this->_id = uniqid(substr($name.$type, 0, 114), true); 96 } 97 } // end constructor 98 99 /** 100 * Create a child for this item. 101 * @param string $type type of item: directive, section, comment, blank... 102 * @param mixed $item item name 103 * @param string $content item content 104 * @param array $attributes item attributes 105 * @param string $where choose a position 'bottom', 'top', 'after', 'before' 106 * @param object $target needed if you choose 'before' or 'after' for where 107 * @return object reference to new item or Pear_Error 108 */ 109 function &createItem($type, $name, $content, $attributes = null, $where = 'bottom', $target = null) 110 { 111 $item =& new Config_Container($type, $name, $content, $attributes); 112 $result =& $this->addItem($item, $where, $target); 113 return $result; 114 } // end func &createItem 115 116 /** 117 * Adds an item to this item. 118 * @param object $item a container object 119 * @param string $where choose a position 'bottom', 'top', 'after', 'before' 120 * @param object $target needed if you choose 'before' or 'after' in $where 121 * @return mixed reference to added container on success, Pear_Error on error 122 */ 123 function &addItem(&$item, $where = 'bottom', $target = null) 124 { 125 if ($this->type != 'section') { 126 return PEAR::raiseError('Config_Container::addItem must be called on a section type object.', null, PEAR_ERROR_RETURN); 127 } 128 if (is_null($target)) { 129 $target =& $this; 130 } 131 if (strtolower(get_class($target)) != 'config_container') { 132 return PEAR::raiseError('Target must be a Config_Container object in Config_Container::addItem.', null, PEAR_ERROR_RETURN); 133 } 134 135 switch ($where) { 136 case 'before': 137 $index = $target->getItemIndex(); 138 break; 139 case 'after': 140 $index = $target->getItemIndex()+1; 141 break; 142 case 'top': 143 $index = 0; 144 break; 145 case 'bottom': 146 $index = -1; 147 break; 148 default: 149 return PEAR::raiseError('Use only top, bottom, before or after in Config_Container::addItem.', null, PEAR_ERROR_RETURN); 150 } 151 if (isset($index) && $index >= 0) { 152 array_splice($this->children, $index, 0, 'tmp'); 153 } else { 154 $index = count($this->children); 155 } 156 $this->children[$index] =& $item; 157 $this->children[$index]->parent =& $this; 158 159 return $item; 160 } // end func addItem 161 162 /** 163 * Adds a comment to this item. 164 * This is a helper method that calls createItem 165 * 166 * @param string $content Object content 167 * @param string $where Position : 'top', 'bottom', 'before', 'after' 168 * @param object $target Needed when $where is 'before' or 'after' 169 * @return object reference to new item or Pear_Error 170 */ 171 function &createComment($content = '', $where = 'bottom', $target = null) 172 { 173 return $this->createItem('comment', null, $content, null, $where, $target); 174 } // end func &createComment 175 176 /** 177 * Adds a blank line to this item. 178 * This is a helper method that calls createItem 179 * 180 * @return object reference to new item or Pear_Error 181 */ 182 function &createBlank($where = 'bottom', $target = null) 183 { 184 return $this->createItem('blank', null, null, null, $where, $target); 185 } // end func &createBlank 186 187 /** 188 * Adds a directive to this item. 189 * This is a helper method that calls createItem 190 * 191 * @param string $name Name of new directive 192 * @param string $content Content of new directive 193 * @param mixed $attributes Directive attributes 194 * @param string $where Position : 'top', 'bottom', 'before', 'after' 195 * @param object $target Needed when $where is 'before' or 'after' 196 * @return object reference to new item or Pear_Error 197 */ 198 function &createDirective($name, $content, $attributes = null, $where = 'bottom', $target = null) 199 { 200 return $this->createItem('directive', $name, $content, $attributes, $where, $target); 201 } // end func &createDirective 202 203 /** 204 * Adds a section to this item. 205 * 206 * This is a helper method that calls createItem 207 * If the section already exists, it won't create a new one. 208 * It will return reference to existing item. 209 * 210 * @param string $name Name of new section 211 * @param array $attributes Section attributes 212 * @param string $where Position : 'top', 'bottom', 'before', 'after' 213 * @param object $target Needed when $where is 'before' or 'after' 214 * @return object reference to new item or Pear_Error 215 */ 216 function &createSection($name, $attributes = null, $where = 'bottom', $target = null) 217 { 218 return $this->createItem('section', $name, null, $attributes, $where, $target); 219 } // end func &createSection 220 221 /** 222 * Tries to find the specified item(s) and returns the objects. 223 * 224 * Examples: 225 * $directives =& $obj->getItem('directive'); 226 * $directive_bar_4 =& $obj->getItem('directive', 'bar', null, 4); 227 * $section_foo =& $obj->getItem('section', 'foo'); 228 * 229 * This method can only be called on an object of type 'section'. 230 * Note that root is a section. 231 * This method is not recursive and tries to keep the current structure. 232 * For a deeper search, use searchPath() 233 * 234 * @param string $type Type of item: directive, section, comment, blank... 235 * @param mixed $name Item name 236 * @param mixed $content Find item with this content 237 * @param array $attributes Find item with attribute set to the given value 238 * @param int $index Index of the item in the returned object list. If it is not set, will try to return the last item with this name. 239 * @return mixed reference to item found or false when not found 240 * @see &searchPath() 241 */ 242 function &getItem($type = null, $name = null, $content = null, $attributes = null, $index = -1) 243 { 244 if ($this->type != 'section') { 245 return PEAR::raiseError('Config_Container::getItem must be called on a section type object.', null, PEAR_ERROR_RETURN); 246 } 247 if (!is_null($type)) { 248 $testFields[] = 'type'; 249 } 250 if (!is_null($name)) { 251 $testFields[] = 'name'; 252 } 253 if (!is_null($content)) { 254 $testFields[] = 'content'; 255 } 256 if (!is_null($attributes) && is_array($attributes)) { 257 $testFields[] = 'attributes'; 258 } 259 260 $itemsArr = array(); 261 $fieldsToMatch = count($testFields); 262 for ($i = 0, $count = count($this->children); $i < $count; $i++) { 263 $match = 0; 264 reset($testFields); 265 foreach ($testFields as $field) { 266 if ($field != 'attributes') { 267 if ($this->children[$i]->$field == ${$field}) { 268 $match++; 269 } 270 } else { 271 // Look for attributes in array 272 $attrToMatch = count($attributes); 273 $attrMatch = 0; 274 foreach ($attributes as $key => $value) { 275 if (isset($this->children[$i]->attributes[$key]) && 276 $this->children[$i]->attributes[$key] == $value) { 277 $attrMatch++; 278 } 279 } 280 if ($attrMatch == $attrToMatch) { 281 $match++; 282 } 283 } 284 } 285 if ($match == $fieldsToMatch) { 286 $itemsArr[] =& $this->children[$i]; 287 } 288 } 289 if ($index >= 0) { 290 if (isset($itemsArr[$index])) { 291 return $itemsArr[$index]; 292 } else { 293 $return = false; 294 return $return; 295 } 296 } else { 297 if ($count = count($itemsArr)) { 298 return $itemsArr[$count-1]; 299 } else { 300 $return = false; 301 return $return; 302 } 303 } 304 } // end func &getItem 305 306 /** 307 * Finds a node using XPATH like format. 308 * 309 * The search format is an array: 310 * array(item1, item2, item3, ...) 311 * 312 * Each item can be defined as the following: 313 * item = 'string' : will match the container named 'string' 314 * item = array('string', array('name' => 'xyz')) 315 * will match the container name 'string' whose attribute name is equal to "xyz" 316 * For example : <string name="xyz"> 317 * 318 * @param mixed Search path and attributes 319 * 320 * @return mixed Config_Container object, array of Config_Container objects or false on failure. 321 * @access public 322 */ 323 function &searchPath($args) 324 { 325 if ($this->type != 'section') { 326 return PEAR::raiseError('Config_Container::searchPath must be called on a section type object.', null, PEAR_ERROR_RETURN); 327 } 328 329 $arg = array_shift($args); 330 331 if (is_array($arg)) { 332 $name = $arg[0]; 333 $attributes = $arg[1]; 334 } else { 335 $name = $arg; 336 $attributes = null; 337 } 338 // find all the matches for first.. 339 $match =& $this->getItem(null, $name, null, $attributes); 340 341 if (!$match) { 342 $return = false; 343 return $return; 344 } 345 if (!empty($args)) { 346 return $match->searchPath($args); 347 } 348 return $match; 349 } // end func &searchPath 350 351 /** 352 * Return a child directive's content. 353 * 354 * This method can use two different search approach, depending on 355 * the parameter it is given. If the parameter is an array, it will use 356 * the {@link Config_Container::searchPath()} method. If it is a string, 357 * it will use the {@link Config_Container::getItem()} method. 358 * 359 * Example: 360 * <code> 361 * require_once 'Config.php'; 362 * $ini = new Config(); 363 * $conf =& $ini->parseConfig('/path/to/config.ini', 'inicommented'); 364 * 365 * // Will return the value found at : 366 * // [Database] 367 * // host=localhost 368 * echo $conf->directiveContent(array('Database', 'host'))); 369 * 370 * // Will return the value found at : 371 * // date="dec-2004" 372 * echo $conf->directiveContent('date'); 373 * 374 * </code> 375 * 376 * @param mixed Search path and attributes or a directive name 377 * @param int Index of the item in the returned directive list. 378 * Eventually used if args is a string. 379 * 380 * @return mixed Content of directive or false if not found. 381 * @access public 382 */ 383 function directiveContent($args, $index = -1) 384 { 385 if (is_array($args)) { 386 $item =& $this->searchPath($args); 387 } else { 388 $item =& $this->getItem('directive', $args, null, null, $index); 389 } 390 if ($item) { 391 return $item->getContent(); 392 } 393 return false; 394 } // end func getDirectiveContent 395 396 /** 397 * Returns how many children this container has 398 * 399 * @param string $type type of children counted 400 * @param string $name name of children counted 401 * @return int number of children found 402 */ 403 function countChildren($type = null, $name = null) 404 { 405 if (is_null($type) && is_null($name)) { 406 return count($this->children); 407 } 408 $count = 0; 409 if (isset($name) && isset($type)) { 410 for ($i = 0, $children = count($this->children); $i < $children; $i++) { 411 if ($this->children[$i]->name === $name && 412 $this->children[$i]->type == $type) { 413 $count++; 414 } 415 } 416 return $count; 417 } 418 if (isset($type)) { 419 for ($i = 0, $children = count($this->children); $i < $children; $i++) { 420 if ($this->children[$i]->type == $type) { 421 $count++; 422 } 423 } 424 return $count; 425 } 426 if (isset($name)) { 427 // Some directives can have the same name 428 for ($i = 0, $children = count($this->children); $i < $children; $i++) { 429 if ($this->children[$i]->name === $name) { 430 $count++; 431 } 432 } 433 return $count; 434 } 435 } // end func &countChildren 436 437 /** 438 * Deletes an item (section, directive, comment...) from the current object 439 * TODO: recursive remove in sub-sections 440 * @return mixed true if object was removed, false if not, or PEAR_Error if root 441 */ 442 function removeItem() 443 { 444 if ($this->isRoot()) { 445 return PEAR::raiseError('Cannot remove root item in Config_Container::removeItem.', null, PEAR_ERROR_RETURN); 446 } 447 $index = $this->getItemIndex(); 448 if (!is_null($index)) { 449 array_splice($this->parent->children, $index, 1); 450 return true; 451 } 452 return false; 453 } // end func removeItem 454 455 /** 456 * Returns the item index in its parent children array. 457 * @return int returns int or null if root object 458 */ 459 function getItemIndex() 460 { 461 if (is_object($this->parent)) { 462 // This will be optimized with Zend Engine 2 463 $pchildren =& $this->parent->children; 464 for ($i = 0, $count = count($pchildren); $i < $count; $i++) { 465 if ($pchildren[$i]->_id == $this->_id) { 466 return $i; 467 } 468 } 469 } 470 return; 471 } // end func getItemIndex 472 473 /** 474 * Returns the item rank in its parent children array 475 * according to other items with same type and name. 476 * @param bool count items differently by type 477 * @return int returns int or null if root object 478 */ 479 function getItemPosition($byType = true) 480 { 481 if (is_object($this->parent)) { 482 $pchildren =& $this->parent->children; 483 for ($i = 0, $count = count($pchildren); $i < $count; $i++) { 484 if ($pchildren[$i]->name == $this->name) { 485 if ($byType == true) { 486 if ($pchildren[$i]->type == $this->type) { 487 $obj[] =& $pchildren[$i]; 488 } 489 } else { 490 $obj[] =& $pchildren[$i]; 491 } 492 } 493 } 494 for ($i = 0, $count = count($obj); $i < $count; $i++) { 495 if ($obj[$i]->_id == $this->_id) { 496 return $i; 497 } 498 } 499 } 500 return; 501 } // end func getItemPosition 502 503 /** 504 * Returns the item parent object. 505 * @return object returns reference to parent object or null if root object 506 */ 507 function &getParent() 508 { 509 return $this->parent; 510 } // end func &getParent 511 512 /** 513 * Returns the item parent object. 514 * @return mixed returns reference to child object or false if child does not exist 515 */ 516 function &getChild($index = 0) 517 { 518 if (!empty($this->children[$index])) { 519 return $this->children[$index]; 520 } else { 521 return false; 522 } 523 } // end func &getChild 524 525 /** 526 * Set this item's name. 527 * @return void 528 */ 529 function setName($name) 530 { 531 $this->name = $name; 532 } // end func setName 533 534 /** 535 * Get this item's name. 536 * @return string item's name 537 */ 538 function getName() 539 { 540 return $this->name; 541 } // end func getName 542 543 /** 544 * Set this item's content. 545 * @return void 546 */ 547 function setContent($content) 548 { 549 $this->content = $content; 550 } // end func setContent 551 552 /** 553 * Get this item's content. 554 * @return string item's content 555 */ 556 function getContent() 557 { 558 return $this->content; 559 } // end func getContent 560 561 /** 562 * Set this item's type. 563 * @return void 564 */ 565 function setType($type) 566 { 567 $this->type = $type; 568 } // end func setType 569 570 /** 571 * Get this item's type. 572 * @return string item's type 573 */ 574 function getType() 575 { 576 return $this->type; 577 } // end func getType 578 579 /** 580 * Set this item's attributes. 581 * @param array $attributes Array of attributes 582 * @return void 583 */ 584 function setAttributes($attributes) 585 { 586 $this->attributes = $attributes; 587 } // end func setAttributes 588 589 /** 590 * Set this item's attributes. 591 * @param array $attributes Array of attributes 592 * @return void 593 */ 594 function updateAttributes($attributes) 595 { 596 if (is_array($attributes)) { 597 foreach ($attributes as $key => $value) { 598 $this->attributes[$key] = $value; 599 } 600 } 601 } // end func updateAttributes 602 603 /** 604 * Get this item's attributes. 605 * @return array item's attributes 606 */ 607 function getAttributes() 608 { 609 return $this->attributes; 610 } // end func getAttributes 611 612 /** 613 * Get one attribute value of this item 614 * @param string $attribute Attribute key 615 * @return mixed item's attribute value 616 */ 617 function getAttribute($attribute) 618 { 619 if (isset($this->attributes[$attribute])) { 620 return $this->attributes[$attribute]; 621 } 622 return null; 623 } // end func getAttribute 624 625 /** 626 * Set a children directive content. 627 * This is an helper method calling getItem and addItem or setContent for you. 628 * If the directive does not exist, it will be created at the bottom. 629 * 630 * @param string $name Name of the directive to look for 631 * @param mixed $content New content 632 * @param int $index Index of the directive to set, 633 * in case there are more than one directive 634 * with the same name 635 * @return object newly set directive 636 */ 637 function &setDirective($name, $content, $index = -1) 638 { 639 $item =& $this->getItem('directive', $name, null, null, $index); 640 if ($item === false || PEAR::isError($item)) { 641 // Directive does not exist, will create one 642 unset($item); 643 return $this->createDirective($name, $content, null); 644 } else { 645 // Change existing directive value 646 $item->setContent($content); 647 return $item; 648 } 649 } // end func setDirective 650 651 /** 652 * Is this item root, in a config container object 653 * @return bool true if item is root 654 */ 655 function isRoot() 656 { 657 if (is_null($this->parent)) { 658 return true; 659 } 660 return false; 661 } // end func isRoot 662 663 /** 664 * Call the toString methods in the container plugin 665 * @param string $configType Type of configuration used to generate the string 666 * @param array $options Specify special options used by the parser 667 * @return mixed true on success or PEAR_ERROR 668 */ 669 function toString($configType, $options = array()) 670 { 671 $configType = strtolower($configType); 672 if (!isset($GLOBALS['CONFIG_TYPES'][$configType])) { 673 return PEAR::raiseError("Configuration type '$configType' is not registered in Config_Container::toString.", null, PEAR_ERROR_RETURN); 674 } 675 $includeFile = $GLOBALS['CONFIG_TYPES'][$configType][0]; 676 $className = $GLOBALS['CONFIG_TYPES'][$configType][1]; 677 include_once($includeFile); 678 $renderer = new $className($options); 679 return $renderer->toString($this); 680 } // end func toString 681 682 /** 683 * Returns a key/value pair array of the container and its children. 684 * 685 * Format : section[directive][index] = value 686 * If the container has attributes, it will use '@' and '#' 687 * index is here because multiple directives can have the same name. 688 * 689 * @param bool $useAttr Whether to return the attributes too 690 * @return array 691 */ 692 function toArray($useAttr = true) 693 { 694 $array[$this->name] = array(); 695 switch ($this->type) { 696 case 'directive': 697 if ($useAttr && count($this->attributes) > 0) { 698 $array[$this->name]['#'] = $this->content; 699 $array[$this->name]['@'] = $this->attributes; 700 } else { 701 $array[$this->name] = $this->content; 702 } 703 break; 704 case 'section': 705 if ($useAttr && count($this->attributes) > 0) { 706 $array[$this->name]['@'] = $this->attributes; 707 } 708 if ($count = count($this->children)) { 709 for ($i = 0; $i < $count; $i++) { 710 $newArr = $this->children[$i]->toArray($useAttr); 711 if (!is_null($newArr)) { 712 foreach ($newArr as $key => $value) { 713 if (isset($array[$this->name][$key])) { 714 // duplicate name/type 715 if (!is_array($array[$this->name][$key]) || 716 !isset($array[$this->name][$key][0])) { 717 $old = $array[$this->name][$key]; 718 unset($array[$this->name][$key]); 719 $array[$this->name][$key][0] = $old; 720 } 721 $array[$this->name][$key][] = $value; 722 } else { 723 $array[$this->name][$key] = $value; 724 } 725 } 726 } 727 } 728 } 729 break; 730 default: 731 return null; 732 } 733 return $array; 734 } // end func toArray 735 736 /** 737 * Writes the configuration to a file 738 * 739 * @param mixed $datasrc Info on datasource such as path to the configuraton file or dsn... 740 * @param string $configType Type of configuration 741 * @param array $options Options for writer 742 * @access public 743 * @return mixed true on success or PEAR_ERROR 744 */ 745 function writeDatasrc($datasrc, $configType, $options = array()) 746 { 747 $configType = strtolower($configType); 748 if (!isset($GLOBALS['CONFIG_TYPES'][$configType])) { 749 return PEAR::raiseError("Configuration type '$configType' is not registered in Config_Container::writeDatasrc.", null, PEAR_ERROR_RETURN); 750 } 751 $includeFile = $GLOBALS['CONFIG_TYPES'][$configType][0]; 752 $className = $GLOBALS['CONFIG_TYPES'][$configType][1]; 753 include_once($includeFile); 754 755 $writeMethodName = (version_compare(phpversion(), '5', '<')) ? 'writedatasrc' : 'writeDatasrc'; 756 if (in_array($writeMethodName, get_class_methods($className))) { 757 $writer = new $className($options); 758 return $writer->writeDatasrc($datasrc, $this); 759 } 760 761 // Default behaviour 762 $fp = @fopen($datasrc, 'w'); 763 if ($fp) { 764 $string = $this->toString($configType, $options); 765 $len = strlen($string); 766 @flock($fp, LOCK_EX); 767 @fwrite($fp, $string, $len); 768 @flock($fp, LOCK_UN); 769 @fclose($fp); 770 return true; 771 } else { 772 return PEAR::raiseError('Cannot open datasource for writing.', 1, PEAR_ERROR_RETURN); 773 } 774 } // end func writeDatasrc 775 } // end class Config_Container 776 ?>
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 |