[ create a new paste ] login | about

Link: http://codepad.org/hvv8iiT5    [ raw code | output | fork | 1 comment ]

PHP, pasted on Nov 27:
<?php

$tree = array('H' => 'G', 'F' => 'G', 'G' => 'D', 'E' => 'D', 'A' => 'E', 'B' => 'C', 'C' => 'E', 'D' => null);

// add children to parents
$flat = array(); # temporary array
foreach ($tree as $name => $parent)
{
    $flat[$name]['name'] = $name; # self
    if (NULL === $parent)
    {
        # no parent, is root element, assign it to $tree
        $tree = &$flat[$name];
    }
    else
    {
    	# has parent, add self as child    
        $flat[$parent]['children'][] = &$flat[$name];
    }
}
unset($flat);

class TreeNode
{
    protected $data;
    public function __construct(array $element)
    {
        if (!isset($element['name']))
            throw new InvalidArgumentException('Element has no name.');

		if (isset($element['children']) && !is_array($element['children']))
		    throw new InvalidArgumentException('Element has invalid children.');

        $this->data = $element;
    }
    public function getName()
    {
         return $this->data['name'];
    }
    public function hasChildren()
    {
        return isset($this->data['children']) && count($this->data['children']);
    }
    /**
     * @return array of child TreeNode elements 
     */
    public function getChildren()
    {        
        $children = $this->hasChildren() ? $this->data['children'] : array();
        $class = 'TreeNode';
    	foreach($children as &$element)
    	{
    		$element = new $class($element);
    	}
    	unset($element);        
		return $children;
    }
}

class TreeNodesIterator implements RecursiveIterator
{
	private $nodes;
	public function __construct(array $nodes)
	{
		$this->nodes = new ArrayIterator($nodes);
	}
	public function  getInnerIterator()
	{
		return $this->nodes;
	}
	public function getChildren()
	{
		return new TreeNodesIterator($this->nodes->current()->getChildren());
	}
	public function hasChildren()
	{
		return $this->nodes->current()->hasChildren();
	}
	public function rewind()
	{
		$this->nodes->rewind();
	}
	public function valid()
	{
		return $this->nodes->valid();
	}	
	public function current()
	{
		return $this->nodes->current();
	}
	public function key()
	{
		return $this->nodes->key();
	}
	public function next()
	{
		return $this->nodes->next();
	}
}

class RecursiveListIterator extends RecursiveIteratorIterator
{
	private $elements;
	/**
	 * @var ListDecorator
	 */
	private $decorator;
	public function addDecorator(ListDecorator $decorator)
	{
		$this->decorator = $decorator;
	}
	public function __construct($iterator, $mode = RecursiveIteratorIterator::SELF_FIRST, $flags = 0)
	{
		parent::__construct($iterator, $mode, $flags);
	}
	private function event($name)
	{
		// event debug code: printf("--- %'.-20s --- (Depth: %d, Element: %d)\n", $name, $this->getDepth(), @$this->elements[$this->getDepth()]);
		$callback = array($this->decorator, $name);
		is_callable($callback) && call_user_func($callback);
	}
	public function beginElement()
	{
		$this->event('beginElement');
	}
	public function beginChildren()
	{
		$this->event('beginChildren');
	}
	public function endChildren()
	{
		$this->testEndElement();
		$this->event('endChildren');
	}
	private function testEndElement($depthOffset = 0)
	{
		$depth = $this->getDepth() + $depthOffset;		
		isset($this->elements[$depth]) || $this->elements[$depth] = 0;
		$this->elements[$depth] && $this->event('endElement');
		
	}
	public function nextElement()
	{
		$this->testEndElement();
		$this->event('{nextElement}');
		$this->event('beginElement');		
		$this->elements[$this->getDepth()] = 1;
	} 
	public function beginIteration()
	{
		$this->event('beginIteration');
	}
	public function endIteration()
	{
		$this->testEndElement();
		$this->event('endIteration');		
	}
}

class ListDecorator
{
	private $iterator;
	public function __construct(RecursiveListIterator $iterator)
	{
		$this->iterator = $iterator;
	}
	public function inset($add = 0)
	{
		return str_repeat('  ', $this->iterator->getDepth()*2+$add);
	}
	public function beginElement()
	{
		printf("%s<li>\n", $this->inset(1));
	}
	public function endElement()
	{
		printf("%s</li>\n", $this->inset(1));
	}
	public function beginChildren()
	{
		printf("%s<ul>\n", $this->inset());
	}
	public function endChildren()
	{
		printf("%s</ul>\n", $this->inset());
	}
	public function beginIteration()
	{
		printf("%s<ul>\n", $this->inset());
	}
	public function endIteration()
	{
		printf("%s</ul>\n", $this->inset());
	}
}


$root = new TreeNode($tree);
$it = new TreeNodesIterator(array($root));
$rit = new RecursiveListIterator($it);
$decor = new ListDecorator($rit);
$rit->addDecorator($decor);

foreach($rit as $item)
{
	$inset = $decor->inset(2);
	printf("%s%s\n", $inset, $item->getName());
}


Output:
<ul>
  <li>
    D
    <ul>
      <li>
        G
        <ul>
          <li>
            H
          </li>
          <li>
            F
          </li>
        </ul>
      </li>
      <li>
        E
        <ul>
          </li>
          <li>
            A
          </li>
          <li>
            C
            <ul>
              <li>
                B
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>


Create a new paste based on this one


Comments:
posted by garethsoul on Apr 1
Thanks a lot!!!!!
reply