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

Klasa prostego drzewka:
<?php
class Tree implements IteratorAggregate {
protected $oElement;
protected
$aNode = array();
public function __construct($sName = NULL)
{
if($sName != NULL)
{
$this->$sName = new Tree;
}
}
/**
* Dodajemy nowy wezel do istniejacego
* @acces public
* @param string $sName nazwa naszego wezla
* @param object $oItem obiekt ktory chcemy podlaczyc do naszego drzewa
* @return void
*/
public function addChild($sName, $oItem)
{
$this->$sName = new Tree;
$this->aNode[$sName]->oElement = &$oItem;
}
/**
* Sprawdzamy czy dany wezel ma wezly potomne
* @acces public
* @return bool
*/
public function checkChildren()
{
return (count($this->aNode) > 0
)?
TRUE : FALSE; }
/**
* Pobieramy obiekt przywiazany do danego wezla
* @acces public
* @return object
*/
public function &getObject()
{
$oObject = &$this->oElement;
return ( is_object($oObject) )?
$oObject : NULL; }
/**
* Pobieramy wezly
* @acces public
* @return object
*/
public function getNodes()
{
return $this->aNode;
}
// php 5 RoX
public function __get($p)
{
if(isset($this->aNode[$p])) return $this->aNode[$p];
else
return false;
}
public function __set($p,$val)
{
$this->aNode[$p] = $val;
}
public function getIterator()
{
return new RecursiveIteratorIterator(new TreeIterator($this));
}
}
?>
Iterator dla tego drzewka:
<?php
class TreeIterator implements RecursiveIterator {
private $oTree = NULL;
private $aItems = array(); private $iKey = 0;
private $oCurrentNode;
public function __construct($oMenu)
{
$this->oTree = &$oMenu;
foreach(new ArrayObject($this->oTree->getNodes()) as $property => $value)
{
$this->aItems[] = $property;
}
}
/**
* Ustawiamy obecny wezel
* @acces private
* @param int $iKey klucz danego wezla
* @return void
*/
private function setCurrent($iKey)
{
$sNodeName = $this->aItems[$iKey];
$this->oCurrentNode = $this->oTree->$sNodeName;
}
//Metody Interfejsu
{
$this->iKey = 0;
$this->setCurrent($this->iKey);
}
public function valid()
{
return isset($this->aItems[$this->iKey]); }
{
$this->iKey++;
if(isset($this->aItems[$this->iKey])) $this->setCurrent($this->iKey);
}
{
return $this->iKey;
}
{
$this->setCurrent($this->iKey);
return $this->oCurrentNode->getObject(); //Zwracamy do petli obiekt podlaczony do tej galezi
}
public function hasChildren()
{
return $this->oCurrentNode->checkChildren();
}
public function getChildren()
{
return new TreeIterator($this->oCurrentNode);
}
}
?>
Testowe obiekty które wrzucam do drzewa:
<?php
abstract class MenuElement {
private $fullName;
public function __construct($sName)
{
$this->fullName = $sName;
}
public function getName()
{
return $this->fullName;
}
}
class MenuFolder extends MenuElement {
}
class MenuLink extends MenuElement {
private $sAction;
private $aParams = array();
public function __construct
($sName, $sAction, $aParams = array()) {
parent::__construct($sName);
$this->setParams($aParams);
$this->setAction($sAction);
}
public function setParams($aParams)
{
$this->aParams = &$aParams;
}
public function setAction($sActionName)
{
$this->sAction = $sActionName;
}
private function paramsToString()
{
$string = '';
foreach ($this->aParams as $key => $val)
{
$string .= '&'.$key.'='.$val;
}
return $string;
}
public function getUrl()
{
return '?action='.$this->sAction.$this->paramsToString();
}
}
?>
I test:
<?php
include('menu.php');
include('TreeIterator.php');
$menu = new Tree();
$menu->addChild( 'artykuly' , new MenuFolder('Nasze Artykuły') );
$menu->artykuly->addChild( 'pralki' , new MenuFolder( 'Zobacz pralki') );
$menu->artykuly->pralki->addChild('automatyczne' , new MenuLink
( 'Zobacz automatyczne','showNews',array('id' => 5
) ));
$menu->addChild( 'onas' , new MenuFolder('O nas') );
$menu->addChild( 'firma' , new MenuFolder('Nasza firma, adres i kontakt') );
$menu->addChild( 'news' , new MenuFolder('Aktualnosci na stronie') );
$menu->news->addChild( 'dzisiaj' , new MenuLink
( 'Dzisiejsze newsy','showNews',array('id' => 5
) ) ); $menu->news->addChild('wczoraj' , new MenuLink
('Wczorajsze newsy','showNews',array('id' => 19
))); $menu->news->addChild('wszystkie' , new MenuFolder('Wszystkie newsy'));
$menu->news->wszystkie->addChild('jakis', new MenuLink
( 'News ze srody','showNews',array('id' => 5
) )); $menu->addChild('test',new MenuFolder('Testowy folder'));
foreach($menu as $key => $val )
{
//echo $value;
//echo '<br>';
}
?>
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

. Najepewniej coś jest nie tak z implementacją interfejsu ale nie mam pojęcia co

I problem rozwiązany 
, a rozwiązanie jest banalne RecursiveIteratorIterator jako drugi parametr ma stałą i defaultowo jest:
<?php
RIT_LEAVES_ONLY // (the default) only returns leaves in current and skips all parents (elements that have children).
?>
A jeśli zmienimy na:
<?php
RIT_SELF_FIRST //first returns the parent and then their children.
?>
Otrzymamy efekt, który chciałem

Może się komuś przyda...
Ten post edytował ebe 10.04.2005, 12:41:04