Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested lists using PHP's iterator?

Tags:

arrays

php

I'm trying to display this kind of array:

$nodes = array(

  1 => array(
         'title'    => 'NodeLvl1',
         'children' => array(),
       ),    
  2 => array(
         'title'    => 'NodeLvl1',
         'children' => array(        
                         1 => array(
                                'title'    => 'NodeLvl2',
                                'children' => array(),
                             ),    
                         2 => array(
                                'title'    => 'NodeLvl2',
                                'children' => array(


                                   1 => array(
                                          'title'    => 'NodeLvl3',
                                          'children' => array(),
                                       ),


                                   2 => array(
                                          'title'    => 'NodeLvl3',
                                          'children' => array(),
                                       ),    
                                ),
                              ),    

                       ),
       ),

  3 => array(
         'title'    => 'NodeLvl1',
         'children' => array(),
       ),    
);

like this:

<ul>
  <li>
    NodeLvl1
  </li>
  <li>
    NodeLvl1
      <ul>
        <li>NodeLv2</li>
         ...

      </ul>
  </li>
  ...

Basically a nested list taking into account the "children" property. So far I've come up with this:

class It extends RecursiveIteratorIterator{

  protected
    $tab    = "\t";

  public function beginChildren(){

    if(count($this->getInnerIterator()) == 0)
      return;

    echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
  }

  public function endChildren(){


    if(count($this->getInnerIterator()) == 0)
      return;

    echo str_repeat($this->tab, $this->getDepth())."\n</ul>";
  }

  public function nextElement(){
    echo str_repeat($this->tab, $this->getDepth() + 1).'<li>';
  }

}

$it = new It(new RecursiveArrayIterator($nodes));

foreach($it as $key => $item)
  echo $item;

Which doesn't work quite right: I get each item wrapped between <ul>s and I don't know how can I close <li>s...

Any ideas on how to make this work? Also is it possible to get all the array properties (the actual element), instead of just the "title" property inside my foreach() loop? And can this be done with objects instead of arrays?

like image 926
thelolcat Avatar asked Feb 28 '12 01:02

thelolcat


2 Answers

Do you need a class iterator for this? You could do this with just a simple function...

function arrayToListHTML($array, $level = 0) {
    static $tab = "\t";
    if (empty($array)) return;
    $tabs = str_repeat($tab, $level * 2);
    $result = "{$tabs}<ul>\n";
    foreach ($array as $i => $node):
        $result .= "{$tabs}{$tab}<li>\n{$tabs}{$tab}{$tab}{$node['title']}\n".arrayToListHTML($node['children'], $level + 1)."{$tabs}{$tab}</li>\n";
    endforeach;
    $result .= "{$tabs}</ul>\n";
    return $result;
}

Which will produce this output:

<ul>
    <li>
        NodeLvl1
    </li>
    <li>
        NodeLvl1
        <ul>
            <li>
                NodeLvl2
            </li>
            <li>
                NodeLvl2
                <ul>
                    <li>
                        NodeLvl3
                    </li>
                    <li>
                        NodeLvl3
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li>
        NodeLvl1
    </li>
</ul>

This covers what you've shown us, but I'm not sure what you mean by other properties. Are there more properties in each array other than title and children?

like image 54
animuson Avatar answered Oct 12 '22 23:10

animuson


Instead of trying to use your class like an array in foreach() consider using your class to perform the function. For instance, the following code will output correctly but the function is performed inside the class.

class It extends RecursiveIteratorIterator{

  protected
    $tab    = "\t";

  public function beginChildren(){

    if(count($this->getInnerIterator()) == 0)
      return;
    echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
  }

  public function endChildren(){


    if(count($this->getInnerIterator()) == 0)
      return;

    echo str_repeat($this->tab, $this->getDepth)."\n</ul>";
  }

  public function nextElement(){
    echo str_repeat($this->tab, $this->getDepth())."<li>".$this->current()."</li>\n";
  }

}

$it = new It(new RecursiveArrayIterator($nodes));
foreach($it as $key => $item)
  //echo $item;
  //it will be better to write a function inside your custom iterator class to handle iterations
?>
like image 34
Chibueze Opata Avatar answered Oct 12 '22 22:10

Chibueze Opata