| [ Index ] |
|
Code source de Symfony 1.0.0 |
1 <?php 2 3 /** 4 * @package pake 5 * @author Fabien Potencier <fabien.potencier@symfony-project.com> 6 * @copyright 2004-2005 Fabien Potencier <fabien.potencier@symfony-project.com> 7 * @license see the LICENSE file included in the distribution 8 * @version SVN: $Id: pakeYaml.class.php 2978 2006-12-08 19:15:44Z fabien $ 9 */ 10 11 class pakeYaml 12 { 13 public static function load($input) 14 { 15 // syck is prefered over spyc 16 if (function_exists('syck_load')) { 17 if (!empty($input) && is_readable($input)) 18 { 19 $input = file_get_contents($input); 20 } 21 22 return syck_load($input); 23 } 24 else 25 { 26 $spyc = new pakeSpyc(); 27 28 return $spyc->load($input); 29 } 30 } 31 32 public static function dump($array) 33 { 34 $spyc = new pakeSpyc(); 35 36 return $spyc->dump($array); 37 } 38 } 39 40 /** 41 * Spyc -- A Simple PHP YAML Class 42 * @version 0.2.2 -- 2006-01-29 43 * @author Chris Wanstrath <chris@ozmm.org> 44 * @link http://spyc.sourceforge.net/ 45 * @copyright Copyright 2005-2006 Chris Wanstrath 46 * @license http://www.opensource.org/licenses/mit-license.php MIT License 47 * @package Spyc 48 */ 49 50 /** 51 * A node, used by Spyc for parsing YAML. 52 * @package Spyc 53 */ 54 class pakeYAMLNode { 55 /**#@+ 56 * @access public 57 * @var string 58 */ 59 public $parent; 60 public $id; 61 /**#@+*/ 62 /** 63 * @access public 64 * @var mixed 65 */ 66 public $data; 67 /** 68 * @access public 69 * @var int 70 */ 71 public $indent; 72 /** 73 * @access public 74 * @var bool 75 */ 76 public $children = false; 77 78 /** 79 * The constructor assigns the node a unique ID. 80 * @access public 81 * @return void 82 */ 83 public function pakeYAMLNode() { 84 $this->id = uniqid(''); 85 } 86 } 87 88 /** 89 * The Simple PHP YAML Class. 90 * 91 * This class can be used to read a YAML file and convert its contents 92 * into a PHP array. It currently supports a very limited subsection of 93 * the YAML spec. 94 * 95 * Usage: 96 * <code> 97 * $parser = new Spyc; 98 * $array = $parser->load($file); 99 * </code> 100 * @package Spyc 101 */ 102 class pakeSpyc { 103 104 /** 105 * Load YAML into a PHP array statically 106 * 107 * The load method, when supplied with a YAML stream (string or file), 108 * will do its best to convert YAML in a file into a PHP array. Pretty 109 * simple. 110 * Usage: 111 * <code> 112 * $array = Spyc::YAMLLoad('lucky.yml'); 113 * print_r($array); 114 * </code> 115 * @access public 116 * @return array 117 * @param string $input Path of YAML file or string containing YAML 118 */ 119 public function YAMLLoad($input) { 120 $spyc = new pakeSpyc; 121 return $spyc->load($input); 122 } 123 124 /** 125 * Dump YAML from PHP array statically 126 * 127 * The dump method, when supplied with an array, will do its best 128 * to convert the array into friendly YAML. Pretty simple. Feel free to 129 * save the returned string as nothing.yml and pass it around. 130 * 131 * Oh, and you can decide how big the indent is and what the wordwrap 132 * for folding is. Pretty cool -- just pass in 'false' for either if 133 * you want to use the default. 134 * 135 * Indent's default is 2 spaces, wordwrap's default is 40 characters. And 136 * you can turn off wordwrap by passing in 0. 137 * 138 * @access public 139 * @return string 140 * @param array $array PHP array 141 * @param int $indent Pass in false to use the default, which is 2 142 * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) 143 */ 144 public function YAMLDump($array,$indent = false,$wordwrap = false) { 145 $spyc = new pakeSpyc; 146 return $spyc->dump($array,$indent,$wordwrap); 147 } 148 149 /** 150 * Load YAML into a PHP array from an instantiated object 151 * 152 * The load method, when supplied with a YAML stream (string or file path), 153 * will do its best to convert the YAML into a PHP array. Pretty simple. 154 * Usage: 155 * <code> 156 * $parser = new Spyc; 157 * $array = $parser->load('lucky.yml'); 158 * print_r($array); 159 * </code> 160 * @access public 161 * @return array 162 * @param string $input Path of YAML file or string containing YAML 163 */ 164 public function load($input) { 165 // See what type of input we're talking about 166 // If it's not a file, assume it's a string 167 if (!empty($input) && (strpos($input, "\n") === false) 168 && file_exists($input)) { 169 $yaml = file($input); 170 } else { 171 $yaml = explode("\n",$input); 172 } 173 // Initiate some objects and values 174 $base = new pakeYAMLNode; 175 $base->indent = 0; 176 $this->_lastIndent = 0; 177 $this->_lastNode = $base->id; 178 $this->_inBlock = false; 179 $this->_isInline = false; 180 181 foreach ($yaml as $linenum => $line) { 182 $ifchk = trim($line); 183 184 // If the line starts with a tab (instead of a space), throw a fit. 185 if (preg_match('/^(\t)+(\w+)/', $line)) { 186 $err = 'ERROR: Line '. ($linenum + 1) .' in your input YAML begins'. 187 ' with a tab. YAML only recognizes spaces. Please reformat.'; 188 throw new Exception($err); 189 } 190 191 if ($this->_inBlock === false && empty($ifchk)) { 192 continue; 193 } elseif ($this->_inBlock == true && empty($ifchk)) { 194 $last =& $this->_allNodes[$this->_lastNode]; 195 $last->data[key($last->data)] .= "\n"; 196 } elseif ($ifchk{0} != '#' && substr($ifchk,0,3) != '---') { 197 // Create a new node and get its indent 198 $node = new pakeYAMLNode; 199 $node->indent = $this->_getIndent($line); 200 201 // Check where the node lies in the hierarchy 202 if ($this->_lastIndent == $node->indent) { 203 // If we're in a block, add the text to the parent's data 204 if ($this->_inBlock === true) { 205 $parent =& $this->_allNodes[$this->_lastNode]; 206 $parent->data[key($parent->data)] .= trim($line).$this->_blockEnd; 207 } else { 208 // The current node's parent is the same as the previous node's 209 if (isset($this->_allNodes[$this->_lastNode])) { 210 $node->parent = $this->_allNodes[$this->_lastNode]->parent; 211 } 212 } 213 } elseif ($this->_lastIndent < $node->indent) { 214 if ($this->_inBlock === true) { 215 $parent =& $this->_allNodes[$this->_lastNode]; 216 $parent->data[key($parent->data)] .= trim($line).$this->_blockEnd; 217 } elseif ($this->_inBlock === false) { 218 // The current node's parent is the previous node 219 $node->parent = $this->_lastNode; 220 221 // If the value of the last node's data was > or | we need to 222 // start blocking i.e. taking in all lines as a text value until 223 // we drop our indent. 224 $parent =& $this->_allNodes[$node->parent]; 225 $this->_allNodes[$node->parent]->children = true; 226 if (is_array($parent->data)) { 227 $chk = $parent->data[key($parent->data)]; 228 if ($chk === '>') { 229 $this->_inBlock = true; 230 $this->_blockEnd = ' '; 231 $parent->data[key($parent->data)] = 232 str_replace('>','',$parent->data[key($parent->data)]); 233 $parent->data[key($parent->data)] .= trim($line).' '; 234 $this->_allNodes[$node->parent]->children = false; 235 $this->_lastIndent = $node->indent; 236 } elseif ($chk === '|') { 237 $this->_inBlock = true; 238 $this->_blockEnd = "\n"; 239 $parent->data[key($parent->data)] = 240 str_replace('|','',$parent->data[key($parent->data)]); 241 $parent->data[key($parent->data)] .= trim($line)."\n"; 242 $this->_allNodes[$node->parent]->children = false; 243 $this->_lastIndent = $node->indent; 244 } 245 } 246 } 247 } elseif ($this->_lastIndent > $node->indent) { 248 // Any block we had going is dead now 249 if ($this->_inBlock === true) { 250 $this->_inBlock = false; 251 if ($this->_blockEnd = "\n") { 252 $last =& $this->_allNodes[$this->_lastNode]; 253 $last->data[key($last->data)] = 254 trim($last->data[key($last->data)]); 255 } 256 } 257 258 // We don't know the parent of the node so we have to find it 259 // foreach ($this->_allNodes as $n) { 260 foreach ($this->_indentSort[$node->indent] as $n) { 261 if ($n->indent == $node->indent) { 262 $node->parent = $n->parent; 263 } 264 } 265 } 266 267 if ($this->_inBlock === false) { 268 // Set these properties with information from our current node 269 $this->_lastIndent = $node->indent; 270 // Set the last node 271 $this->_lastNode = $node->id; 272 // Parse the YAML line and return its data 273 $node->data = $this->_parseLine($line); 274 // Add the node to the master list 275 $this->_allNodes[$node->id] = $node; 276 // Add a reference to the node in an indent array 277 $this->_indentSort[$node->indent][] =& $this->_allNodes[$node->id]; 278 // Add a reference to the node in a References array if this node 279 // has a YAML reference in it. 280 if ( 281 ( (is_array($node->data)) && 282 isset($node->data[key($node->data)]) && 283 (!is_array($node->data[key($node->data)])) ) 284 && 285 ( (preg_match('/^&([^ ]+)/',$node->data[key($node->data)])) 286 || 287 (preg_match('/^\*([^ ]+)/',$node->data[key($node->data)])) ) 288 ) { 289 $this->_haveRefs[] =& $this->_allNodes[$node->id]; 290 } elseif ( 291 ( (is_array($node->data)) && 292 isset($node->data[key($node->data)]) && 293 (is_array($node->data[key($node->data)])) ) 294 ) { 295 // Incomplete reference making code. Ugly, needs cleaned up. 296 foreach ($node->data[key($node->data)] as $d) { 297 if ( !is_array($d) && 298 ( (preg_match('/^&([^ ]+)/',$d)) 299 || 300 (preg_match('/^\*([^ ]+)/',$d)) ) 301 ) { 302 $this->_haveRefs[] =& $this->_allNodes[$node->id]; 303 } 304 } 305 } 306 } 307 } 308 } 309 unset($node); 310 311 // Here we travel through node-space and pick out references (& and *) 312 $this->_linkReferences(); 313 314 // Build the PHP array out of node-space 315 $trunk = $this->_buildArray(); 316 return $trunk; 317 } 318 319 /** 320 * Dump PHP array to YAML 321 * 322 * The dump method, when supplied with an array, will do its best 323 * to convert the array into friendly YAML. Pretty simple. Feel free to 324 * save the returned string as tasteful.yml and pass it around. 325 * 326 * Oh, and you can decide how big the indent is and what the wordwrap 327 * for folding is. Pretty cool -- just pass in 'false' for either if 328 * you want to use the default. 329 * 330 * Indent's default is 2 spaces, wordwrap's default is 40 characters. And 331 * you can turn off wordwrap by passing in 0. 332 * 333 * @access public 334 * @return string 335 * @param array $array PHP array 336 * @param int $indent Pass in false to use the default, which is 2 337 * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) 338 */ 339 public function dump($array,$indent = false,$wordwrap = false) { 340 // Dumps to some very clean YAML. We'll have to add some more features 341 // and options soon. And better support for folding. 342 343 // New features and options. 344 if ($indent === false or !is_numeric($indent)) { 345 $this->_dumpIndent = 2; 346 } else { 347 $this->_dumpIndent = $indent; 348 } 349 350 if ($wordwrap === false or !is_numeric($wordwrap)) { 351 $this->_dumpWordWrap = 40; 352 } else { 353 $this->_dumpWordWrap = $wordwrap; 354 } 355 356 // New YAML document 357 $string = "---\n"; 358 359 // Start at the base of the array and move through it. 360 foreach ($array as $key => $value) { 361 $string .= $this->_yamlize($key,$value,0); 362 } 363 return $string; 364 } 365 366 /**** Private Properties ****/ 367 368 /**#@+ 369 * @access private 370 * @var mixed 371 */ 372 private $_haveRefs; 373 private $_allNodes; 374 private $_lastIndent; 375 private $_lastNode; 376 private $_inBlock; 377 private $_isInline; 378 private $_dumpIndent; 379 private $_dumpWordWrap; 380 /**#@+*/ 381 382 /**** Private Methods ****/ 383 384 /** 385 * Attempts to convert a key / value array item to YAML 386 * @access private 387 * @return string 388 * @param $key The name of the key 389 * @param $value The value of the item 390 * @param $indent The indent of the current node 391 */ 392 private function _yamlize($key,$value,$indent) { 393 if (is_array($value)) { 394 // It has children. What to do? 395 // Make it the right kind of item 396 $string = $this->_dumpNode($key,NULL,$indent); 397 // Add the indent 398 $indent += $this->_dumpIndent; 399 // Yamlize the array 400 $string .= $this->_yamlizeArray($value,$indent); 401 } elseif (!is_array($value)) { 402 // It doesn't have children. Yip. 403 $string = $this->_dumpNode($key,$value,$indent); 404 } 405 return $string; 406 } 407 408 /** 409 * Attempts to convert an array to YAML 410 * @access private 411 * @return string 412 * @param $array The array you want to convert 413 * @param $indent The indent of the current level 414 */ 415 private function _yamlizeArray($array,$indent) { 416 if (is_array($array)) { 417 $string = ''; 418 foreach ($array as $key => $value) { 419 $string .= $this->_yamlize($key,$value,$indent); 420 } 421 return $string; 422 } else { 423 return false; 424 } 425 } 426 427 /** 428 * Returns YAML from a key and a value 429 * @access private 430 * @return string 431 * @param $key The name of the key 432 * @param $value The value of the item 433 * @param $indent The indent of the current node 434 */ 435 private function _dumpNode($key,$value,$indent) { 436 // do some folding here, for blocks 437 if (strpos($value,"\n")) { 438 $value = $this->_doLiteralBlock($value,$indent); 439 } else { 440 $value = $this->_doFolding($value,$indent); 441 } 442 443 $spaces = str_repeat(' ',$indent); 444 445 if (is_int($key)) { 446 // It's a sequence 447 $string = $spaces.'- '.$value."\n"; 448 } else { 449 // It's mapped 450 $string = $spaces.$key.': '.$value."\n"; 451 } 452 return $string; 453 } 454 455 /** 456 * Creates a literal block for dumping 457 * @access private 458 * @return string 459 * @param $value 460 * @param $indent int The value of the indent 461 */ 462 private function _doLiteralBlock($value,$indent) { 463 $exploded = explode("\n",$value); 464 $newValue = '|'; 465 $indent += $this->_dumpIndent; 466 $spaces = str_repeat(' ',$indent); 467 foreach ($exploded as $line) { 468 $newValue .= "\n" . $spaces . trim($line); 469 } 470 return $newValue; 471 } 472 473 /** 474 * Folds a string of text, if necessary 475 * @access private 476 * @return string 477 * @param $value The string you wish to fold 478 */ 479 private function _doFolding($value,$indent) { 480 // Don't do anything if wordwrap is set to 0 481 if ($this->_dumpWordWrap === 0) { 482 return $value; 483 } 484 485 if (strlen($value) > $this->_dumpWordWrap) { 486 $indent += $this->_dumpIndent; 487 $indent = str_repeat(' ',$indent); 488 $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); 489 $value = ">\n".$indent.$wrapped; 490 } 491 return $value; 492 } 493 494 /* Methods used in loading */ 495 496 /** 497 * Finds and returns the indentation of a YAML line 498 * @access private 499 * @return int 500 * @param string $line A line from the YAML file 501 */ 502 private function _getIndent($line) { 503 preg_match('/^\s{1,}/',$line,$match); 504 if (!empty($match[0])) { 505 $indent = substr_count($match[0],' '); 506 } else { 507 $indent = 0; 508 } 509 return $indent; 510 } 511 512 /** 513 * Parses YAML code and returns an array for a node 514 * @access private 515 * @return array 516 * @param string $line A line from the YAML file 517 */ 518 private function _parseLine($line) { 519 $line = trim($line); 520 521 $array = array(); 522 523 if (preg_match('/^-(.*):$/',$line)) { 524 // It's a mapped sequence 525 $key = trim(substr(substr($line,1),0,-1)); 526 $array[$key] = ''; 527 } elseif ($line[0] == '-' && substr($line,0,3) != '---') { 528 // It's a list item but not a new stream 529 if (strlen($line) > 1) { 530 $value = trim(substr($line,1)); 531 // Set the type of the value. Int, string, etc 532 $value = $this->_toType($value); 533 $array[] = $value; 534 } else { 535 $array[] = array(); 536 } 537 } elseif (preg_match('/^(.+):/',$line,$key)) { 538 // It's a key/value pair most likely 539 // If the key is in double quotes pull it out 540 if (preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { 541 $value = trim(str_replace($matches[1],'',$line)); 542 $key = $matches[2]; 543 } else { 544 // Do some guesswork as to the key and the value 545 $explode = explode(':',$line); 546 $key = trim($explode[0]); 547 array_shift($explode); 548 $value = trim(implode(':',$explode)); 549 } 550 551 // Set the type of the value. Int, string, etc 552 $value = $this->_toType($value); 553 if (empty($key)) { 554 $array[] = $value; 555 } else { 556 $array[$key] = $value; 557 } 558 } 559 return $array; 560 } 561 562 /** 563 * Finds the type of the passed value, returns the value as the new type. 564 * @access private 565 * @param string $value 566 * @return mixed 567 */ 568 private function _toType($value) { 569 if (preg_match('/^("(.*)"|\'(.*)\')/',$value,$matches)) { 570 $value = (string)preg_replace('/(\'\'|\\\\\')/',"'",end($matches)); 571 $value = preg_replace('/\\\\"/','"',$value); 572 } elseif (preg_match('/^\\[(.+)\\]$/',$value,$matches)) { 573 // Inline Sequence 574 575 // Take out strings sequences and mappings 576 $explode = $this->_inlineEscape($matches[1]); 577 578 // Propogate value array 579 $value = array(); 580 foreach ($explode as $v) { 581 $value[] = $this->_toType($v); 582 } 583 } elseif (strpos($value,': ')!==false && !preg_match('/^{(.+)/',$value)) { 584 // It's a map 585 $array = explode(': ',$value); 586 $key = trim($array[0]); 587 array_shift($array); 588 $value = trim(implode(': ',$array)); 589 $value = $this->_toType($value); 590 $value = array($key => $value); 591 } elseif (preg_match("/{(.+)}$/",$value,$matches)) { 592 // Inline Mapping 593 594 // Take out strings sequences and mappings 595 $explode = $this->_inlineEscape($matches[1]); 596 597 // Propogate value array 598 $array = array(); 599 foreach ($explode as $v) { 600 $array = $array + $this->_toType($v); 601 } 602 $value = $array; 603 } elseif (strtolower($value) == 'null' or $value == '' or $value == '~') { 604 $value = NULL; 605 } elseif (ctype_digit($value)) { 606 $value = (int)$value; 607 } elseif (in_array(strtolower($value), 608 array('true', 'on', '+', 'yes', 'y'))) { 609 $value = TRUE; 610 } elseif (in_array(strtolower($value), 611 array('false', 'off', '-', 'no', 'n'))) { 612 $value = FALSE; 613 } elseif (is_numeric($value)) { 614 $value = (float)$value; 615 } else { 616 // Just a normal string, right? 617 $value = trim(preg_replace('/#(.+)$/','',$value)); 618 } 619 620 return $value; 621 } 622 623 /** 624 * Used in inlines to check for more inlines or quoted strings 625 * @access private 626 * @return array 627 */ 628 private function _inlineEscape($inline) { 629 // There's gotta be a cleaner way to do this... 630 // While pure sequences seem to be nesting just fine, 631 // pure mappings and mappings with sequences inside can't go very 632 // deep. This needs to be fixed. 633 634 // Check for strings 635 $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; 636 if (preg_match_all($regex,$inline,$strings)) { 637 $strings = $strings[2]; 638 $inline = preg_replace($regex,'YAMLString',$inline); 639 } 640 unset($regex); 641 642 // Check for sequences 643 if (preg_match_all('/\[(.+)\]/U',$inline,$seqs)) { 644 $inline = preg_replace('/\[(.+)\]/U','YAMLSeq',$inline); 645 $seqs = $seqs[0]; 646 } 647 648 // Check for mappings 649 if (preg_match_all('/{(.+)}/U',$inline,$maps)) { 650 $inline = preg_replace('/{(.+)}/U','YAMLMap',$inline); 651 $maps = $maps[0]; 652 } 653 654 $explode = explode(', ',$inline); 655 656 // Re-add the strings 657 if (!empty($strings)) { 658 $i = 0; 659 foreach ($explode as $key => $value) { 660 if ($value == 'YAMLString') { 661 $explode[$key] = $strings[$i]; 662 ++$i; 663 } 664 } 665 } 666 667 // Re-add the sequences 668 if (!empty($seqs)) { 669 $i = 0; 670 foreach ($explode as $key => $value) { 671 if (strpos($value,'YAMLSeq') !== false) { 672 $explode[$key] = str_replace('YAMLSeq',$seqs[$i],$value); 673 ++$i; 674 } 675 } 676 } 677 678 // Re-add the mappings 679 if (!empty($maps)) { 680 $i = 0; 681 foreach ($explode as $key => $value) { 682 if (strpos($value,'YAMLMap') !== false) { 683 $explode[$key] = str_replace('YAMLMap',$maps[$i],$value); 684 ++$i; 685 } 686 } 687 } 688 689 return $explode; 690 } 691 692 /** 693 * Builds the PHP array from all the YAML nodes we've gathered 694 * @access private 695 * @return array 696 */ 697 private function _buildArray() { 698 $trunk = array(); 699 700 if (!isset($this->_indentSort[0])) { 701 return $trunk; 702 } 703 704 foreach ($this->_indentSort[0] as $n) { 705 if (empty($n->parent)) { 706 $this->_nodeArrayizeData($n); 707 // Check for references and copy the needed data to complete them. 708 $this->_makeReferences($n); 709 // Merge our data with the big array we're building 710 $trunk = $this->_array_kmerge($trunk,$n->data); 711 } 712 } 713 714 return $trunk; 715 } 716 717 /** 718 * Traverses node-space and sets references (& and *) accordingly 719 * @access private 720 * @return bool 721 */ 722 private function _linkReferences() { 723 if (is_array($this->_haveRefs)) { 724 foreach ($this->_haveRefs as $node) { 725 if (!empty($node->data)) { 726 $key = key($node->data); 727 // If it's an array, don't check. 728 if (is_array($node->data[$key])) { 729 foreach ($node->data[$key] as $k => $v) { 730 $this->_linkRef($node,$key,$k,$v); 731 } 732 } else { 733 $this->_linkRef($node,$key); 734 } 735 } 736 } 737 } 738 return true; 739 } 740 741 function _linkRef(&$n,$key,$k = NULL,$v = NULL) { 742 if (empty($k) && empty($v)) { 743 // Look for &refs 744 if (preg_match('/^&([^ ]+)/',$n->data[$key],$matches)) { 745 // Flag the node so we know it's a reference 746 $this->_allNodes[$n->id]->ref = substr($matches[0],1); 747 $this->_allNodes[$n->id]->data[$key] = 748 substr($n->data[$key],strlen($matches[0])+1); 749 // Look for *refs 750 } elseif (preg_match('/^\*([^ ]+)/',$n->data[$key],$matches)) { 751 $ref = substr($matches[0],1); 752 // Flag the node as having a reference 753 $this->_allNodes[$n->id]->refKey = $ref; 754 } 755 } elseif (!empty($k) && !empty($v)) { 756 if (preg_match('/^&([^ ]+)/',$v,$matches)) { 757 // Flag the node so we know it's a reference 758 $this->_allNodes[$n->id]->ref = substr($matches[0],1); 759 $this->_allNodes[$n->id]->data[$key][$k] = 760 substr($v,strlen($matches[0])+1); 761 // Look for *refs 762 } elseif (preg_match('/^\*([^ ]+)/',$v,$matches)) { 763 $ref = substr($matches[0],1); 764 // Flag the node as having a reference 765 $this->_allNodes[$n->id]->refKey = $ref; 766 } 767 } 768 } 769 770 /** 771 * Finds the children of a node and aids in the building of the PHP array 772 * @access private 773 * @param int $nid The id of the node whose children we're gathering 774 * @return array 775 */ 776 private function _gatherChildren($nid) { 777 $return = array(); 778 $node =& $this->_allNodes[$nid]; 779 foreach ($this->_allNodes as $z) { 780 if ($z->parent == $node->id) { 781 // We found a child 782 $this->_nodeArrayizeData($z); 783 // Check for references 784 $this->_makeReferences($z); 785 // Merge with the big array we're returning 786 // The big array being all the data of the children of our parent node 787 $return = $this->_array_kmerge($return,$z->data); 788 } 789 } 790 return $return; 791 } 792 793 /** 794 * Turns a node's data and its children's data into a PHP array 795 * 796 * @access private 797 * @param array $node The node which you want to arrayize 798 * @return boolean 799 */ 800 private function _nodeArrayizeData(&$node) { 801 if (is_array($node->data) && $node->children == true) { 802 // This node has children, so we need to find them 803 $childs = $this->_gatherChildren($node->id); 804 // We've gathered all our children's data and are ready to use it 805 $key = key($node->data); 806 $key = empty($key) ? 0 : $key; 807 // If it's an array, add to it of course 808 if (is_array($node->data[$key])) { 809 $node->data[$key] = $this->_array_kmerge($node->data[$key],$childs); 810 } else { 811 $node->data[$key] = $childs; 812 } 813 } elseif (!is_array($node->data) && $node->children == true) { 814 // Same as above, find the children of this node 815 $childs = $this->_gatherChildren($node->id); 816 $node->data = array(); 817 $node->data[] = $childs; 818 } 819 820 // We edited $node by reference, so just return true 821 return true; 822 } 823 824 /** 825 * Traverses node-space and copies references to / from this object. 826 * @access private 827 * @param object $z A node whose references we wish to make real 828 * @return bool 829 */ 830 private function _makeReferences(&$z) { 831 // It is a reference 832 if (isset($z->ref)) { 833 $key = key($z->data); 834 // Copy the data to this object for easy retrieval later 835 $this->ref[$z->ref] =& $z->data[$key]; 836 // It has a reference 837 } elseif (isset($z->refKey)) { 838 if (isset($this->ref[$z->refKey])) { 839 $key = key($z->data); 840 // Copy the data from this object to make the node a real reference 841 $z->data[$key] =& $this->ref[$z->refKey]; 842 } 843 } 844 return true; 845 } 846 847 848 /** 849 * Merges arrays and maintains numeric keys. 850 * 851 * An ever-so-slightly modified version of the array_kmerge() function posted 852 * to php.net by mail at nospam dot iaindooley dot com on 2004-04-08. 853 * 854 * http://us3.php.net/manual/en/function.array-merge.php#41394 855 * 856 * @access private 857 * @param array $arr1 858 * @param array $arr2 859 * @return array 860 */ 861 private function _array_kmerge($arr1,$arr2) { 862 if(!is_array($arr1)) 863 $arr1 = array(); 864 865 if(!is_array($arr2)) 866 $arr2 = array(); 867 868 $keys1 = array_keys($arr1); 869 $keys2 = array_keys($arr2); 870 $keys = array_merge($keys1,$keys2); 871 $vals1 = array_values($arr1); 872 $vals2 = array_values($arr2); 873 $vals = array_merge($vals1,$vals2); 874 $ret = array(); 875 876 foreach($keys as $key) { 877 list($unused,$val) = each($vals); 878 // This is the good part! If a key already exists, but it's part of a 879 // sequence (an int), just keep addin numbers until we find a fresh one. 880 if (isset($ret[$key]) and is_int($key)) { 881 while (array_key_exists($key, $ret)) { 882 $key++; 883 } 884 } 885 $ret[$key] = $val; 886 } 887 888 return $ret; 889 } 890 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Fri Mar 16 22:42:14 2007 | par Balluche grâce à PHPXref 0.7 |