Witam, siedzę nad tym już 3 dzień. Mam problem z Recursive Iterator i RecursiveIteratorIterator. Problem polega na tym, że zawsze wyświetla najniżej zagłębiony węzeł, pewnie w implementacji metod interfejsu jest coś pokićkane sad.gif

Klasa prostego drzewka:

  1. <?php
  2. class Tree implements IteratorAggregate {
  3.  
  4. protected $oElement;
  5. protected $aNode = array();
  6.  
  7. public function __construct($sName = NULL) 
  8. {
  9. if($sName != NULL) 
  10. { 
  11. $this->$sName = new Tree;
  12. }
  13. }
  14.  
  15. /**
  16.  * Dodajemy nowy wezel do istniejacego
  17.  * @acces public
  18.  * @param string $sName nazwa naszego wezla
  19.  * @param object $oItem obiekt ktory chcemy podlaczyc do naszego drzewa
  20.  * @return void
  21.  */
  22. public function addChild($sName, $oItem) 
  23. {
  24. $this->$sName = new Tree;
  25. $this->aNode[$sName]->oElement = &$oItem;
  26. }
  27.  
  28. /**
  29.  * Sprawdzamy czy dany wezel ma wezly potomne
  30.  * @acces public
  31.  * @return bool
  32.  */
  33. public function checkChildren()
  34. {
  35. return (count($this->aNode) > 0 )TRUE : FALSE;
  36. }
  37.  
  38. /**
  39.  * Pobieramy obiekt przywiazany do danego wezla
  40.  * @acces public
  41.  * @return object
  42.  */
  43. public function &getObject()
  44. {
  45. $oObject = &$this->oElement;
  46. return ( is_object($oObject) )$oObject : NULL;
  47. }
  48.  
  49. /**
  50.  * Pobieramy wezly
  51.  * @acces public
  52.  * @return object
  53.  */
  54. public function getNodes()
  55. {
  56. return $this->aNode;
  57. }
  58.  
  59. // php 5 RoX
  60. public function __get($p)
  61. {
  62. if(isset($this->aNode[$p]))
  63. return $this->aNode[$p];
  64. else
  65. return false;
  66. }
  67.  
  68. public function __set($p,$val)
  69. {
  70. $this->aNode[$p] = $val;
  71. }
  72.  
  73.  
  74. public function getIterator()
  75. {
  76. return new RecursiveIteratorIterator(new TreeIterator($this));
  77. }
  78. }
  79. ?>


Iterator dla tego drzewka:

  1. <?php
  2. class TreeIterator implements RecursiveIterator {
  3.  
  4. private $oTree = NULL;
  5. private $aItems = array();
  6. private $iKey = 0;
  7. private $oCurrentNode;
  8.  
  9. public function __construct($oMenu)
  10. {
  11. $this->oTree = &$oMenu;
  12. foreach(new ArrayObject($this->oTree->getNodes()) as $property => $value)
  13. {
  14.  $this->aItems[] = $property;
  15. }
  16. }
  17.  
  18.  /**
  19.  * Ustawiamy obecny wezel
  20.  * @acces private
  21.  * @param int $iKey klucz danego wezla
  22.  * @return void
  23.  */
  24. private function setCurrent($iKey)
  25. {
  26. $sNodeName = $this->aItems[$iKey];
  27. $this->oCurrentNode = $this->oTree->$sNodeName;
  28. }
  29.  
  30. //Metody Interfejsu
  31.  
  32. public function rewind() 
  33. { 
  34. $this->iKey = 0;
  35. $this->setCurrent($this->iKey);
  36. }
  37.  
  38. public function valid() 
  39. { 
  40. return isset($this->aItems[$this->iKey]);
  41. }
  42.  
  43. public function next() 
  44. { 
  45. $this->iKey++;
  46. if(isset($this->aItems[$this->iKey]))
  47. $this->setCurrent($this->iKey);
  48. }
  49.  
  50. public function key() 
  51. { 
  52. return $this->iKey;
  53. }
  54.  
  55. public function current()
  56. { 
  57. $this->setCurrent($this->iKey);
  58. return $this->oCurrentNode->getObject(); //Zwracamy do petli obiekt podlaczony do tej galezi
  59. }
  60.  
  61. public function hasChildren()
  62. {
  63. return $this->oCurrentNode->checkChildren();
  64. }
  65.  
  66. public function getChildren()
  67. {
  68. return new TreeIterator($this->oCurrentNode);
  69. }
  70.  
  71. }
  72. ?>


Testowe obiekty które wrzucam do drzewa:

  1. <?php
  2. abstract class MenuElement {
  3. private $fullName;
  4.  
  5. public function __construct($sName)
  6. {
  7. $this->fullName = $sName;
  8. }
  9.  
  10. public function getName()
  11. {
  12. return $this->fullName;
  13. }
  14. }
  15.  
  16. class MenuFolder extends MenuElement {
  17.  
  18. }
  19.  
  20. class MenuLink extends MenuElement {
  21.  
  22. private $sAction;
  23. private $aParams = array();
  24.  
  25. public function __construct($sName, $sAction, $aParams = array())
  26. {
  27. parent::__construct($sName);
  28. $this->setParams($aParams);
  29. $this->setAction($sAction);
  30. }
  31.  
  32. public function setParams($aParams)
  33. {
  34. $this->aParams = &$aParams;
  35. }
  36.  
  37. public function setAction($sActionName)
  38. {
  39. $this->sAction = $sActionName;
  40. }
  41.  
  42. private function paramsToString()
  43. {
  44. $string = '';
  45.  
  46. foreach ($this->aParams as $key => $val)
  47. {
  48. $string .= '&'.$key.'='.$val;
  49. }
  50.  
  51. return $string;
  52. }
  53.  
  54. public function getUrl()
  55. {
  56. return '?action='.$this->sAction.$this->paramsToString();
  57. }
  58.  
  59.  
  60. }
  61.  
  62. ?>


I test:

  1. <?php
  2.  
  3. include('menu.php');
  4. include('TreeIterator.php');
  5.  
  6.  
  7. $menu = new Tree();
  8. $menu->addChild( 'artykuly' , new MenuFolder('Nasze Artykuły') );
  9.  
  10. $menu->artykuly->addChild( 'pralki' , new MenuFolder( 'Zobacz pralki') );
  11. $menu->artykuly->pralki->addChild('automatyczne' , new MenuLink( 'Zobacz automatyczne','showNews',array('id' => 5) ));
  12.  
  13. $menu->addChild( 'onas' , new MenuFolder('O nas') );
  14. $menu->addChild( 'firma' , new MenuFolder('Nasza firma, adres i kontakt') );
  15. $menu->addChild( 'news' , new MenuFolder('Aktualnosci na stronie') );
  16. $menu->news->addChild( 'dzisiaj' , new MenuLink( 'Dzisiejsze newsy','showNews',array('id' => 5) ) );
  17. $menu->news->addChild('wczoraj' , new MenuLink('Wczorajsze newsy','showNews',array('id' => 19)));
  18. $menu->news->addChild('wszystkie' , new MenuFolder('Wszystkie newsy'));
  19. $menu->news->wszystkie->addChild('jakis', new MenuLink( 'News ze srody','showNews',array('id' => 5) ));
  20. $menu->addChild('test',new MenuFolder('Testowy folder'));
  21.  
  22. echo '<pre>';
  23.  
  24. foreach($menu as $key => $val )
  25. {
  26. print_r($val);
  27. //echo $value;
  28.  
  29. //echo '<br>';
  30. }
  31. echo '</pre>';
  32. ?>


A zwraca:

Kod
MenuLink Object
(
    [sAction:private] => showNews
    [aParams:private] => Array
        (
            [id] => 5
        )

    [fullName:private] => Zobacz automatyczne
)
MenuFolder Object
(
    [fullName:private] => O nas
)
MenuFolder Object
(
    [fullName:private] => Nasza firma, adres i kontakt
)
MenuLink Object
(
    [sAction:private] => showNews
    [aParams:private] => Array
        (
            [id] => 5
        )

    [fullName:private] => Dzisiejsze newsy
)
MenuLink Object
(
    [sAction:private] => showNews
    [aParams:private] => Array
        (
            [id] => 19
        )

    [fullName:private] => Wczorajsze newsy
)
MenuLink Object
(
    [sAction:private] => showNews
    [aParams:private] => Array
        (
            [id] => 5
        )

    [fullName:private] => News ze srody
)
MenuFolder Object
(
    [fullName:private] => Testowy folder
)


Czyli zawsze ostatni element galezi pomijajac elementy wyzszego rzędu sad.gif. Najepewniej coś jest nie tak z implementacją interfejsu ale nie mam pojęcia co sad.gif


I problem rozwiązany
biggrin.gif, a rozwiązanie jest banalne RecursiveIteratorIterator jako drugi parametr ma stałą i defaultowo jest:
  1. <?php
  2.  RIT_LEAVES_ONLY // (the default) only returns leaves in current and skips all parents (elements that have children).
  3. ?>


A jeśli zmienimy na:

  1. <?php
  2.  RIT_SELF_FIRST //first returns the parent and then their children.
  3. ?>

Otrzymamy efekt, który chciałem smile.gif Może się komuś przyda...