Search code examples
phparrayshierarchy

Flat PHP Array to Hierarchy Tree


I have an array with the following keys

id   
parent_id
name

A sample array:

array(7) {
  [0]=>
  array(3) {
    ["id"]=>
    string(1) "4"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 4"
  }
  [1]=>
  array(3) {
    ["id"]=>
    string(1) "5"
    ["parent_id"]=>
    string(1) "1"
    ["name"]=>
    string(19) "Second Level Page 1"
  }
  [2]=>
  array(3) {
    ["id"]=>
    string(1) "6"
    ["parent_id"]=>
    string(1) "2"
    ["name"]=>
    string(19) "Second Level Page 2"
  }
  [3]=>
  array(3) {
    ["id"]=>
    string(1) "7"
    ["parent_id"]=>
    string(1) "5"
    ["name"]=>
    string(18) "Third Level Page 1"
  }
  [4]=>
  array(3) {
    ["id"]=>
    string(1) "3"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 3"
  }
  [5]=>
  array(3) {
    ["id"]=>
    string(1) "2"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 2"
  }
  [6]=>
  array(3) {
    ["id"]=>
    string(1) "1"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 1"
  }
}

What I would like to do is display a hierarchy tree using this array, the code I have at the moment is producing:

Top Level Page 4
--Second Level Page 1
---Second Level Page 2
----Third Level Page 1
Top Level Page 3
Top Level Page 2
Top Level Page 1

Ideally I need to produce the below result but with unlimited levels:

Top Level Page 4
-Second Level Page 1
-Second Level Page 2
--Third Level Page 1
Top Level Page 3
Top Level Page 2
Top Level Page 1

The code I have so far is:

$level = 1;
        foreach ($data as $row) {
            if ($row['parent_id'] == 0) {
                echo $row['name'] . '<br/>';
            } else {
                $level++;
                foreach ($data as $m) {
                    if ($m['parent_id'] === $row['parent_id']) {
                        $c = 0;
                        $append = '';
                        while ($c < $level) {
                            $append.="-";
                            $c++;
                        }
                        echo $append . $row['name'] . '<br/>';
                    }
                }
            }
        }
    }

If anyone could give me some pointers on how to achieve this it would be much appreciated.

I found a solution here: Create nested list from PHP array for dropdown select field


Solution

  • You should use recursion.

    Here an exemple of code:

    $datas = array(
        array('id' => 1, 'parent' => 0, 'name' => 'Page 1'),
        array('id' => 2, 'parent' => 1, 'name' => 'Page 1.1'),
        array('id' => 3, 'parent' => 2, 'name' => 'Page 1.1.1'),
        array('id' => 4, 'parent' => 3, 'name' => 'Page 1.1.1.1'),
        array('id' => 5, 'parent' => 3, 'name' => 'Page 1.1.1.2'),
        array('id' => 6, 'parent' => 1, 'name' => 'Page 1.2'),
        array('id' => 7, 'parent' => 6, 'name' => 'Page 1.2.1'),
        array('id' => 8, 'parent' => 0, 'name' => 'Page 2'),
        array('id' => 9, 'parent' => 0, 'name' => 'Page 3'),
        array('id' => 10, 'parent' => 9, 'name' => 'Page 3.1'),
        array('id' => 11, 'parent' => 9, 'name' => 'Page 3.2'),
        array('id' => 12, 'parent' => 11, 'name' => 'Page 3.2.1'),
        );
    
    function generatePageTree($datas, $parent = 0, $depth=0){
        $ni=count($datas);
        if($ni === 0 || $depth > 1000) return ''; // Make sure not to have an endless recursion
        $tree = '<ul>';
        for($i=0; $i < $ni; $i++){
            if($datas[$i]['parent'] == $parent){
                $tree .= '<li>';
                $tree .= $datas[$i]['name'];
                $tree .= generatePageTree($datas, $datas[$i]['id'], $depth+1);
                $tree .= '</li>';
            }
        }
        $tree .= '</ul>';
        return $tree;
    }
    
    echo(generatePageTree($datas));
    

    You can test it at: http://phpfiddle.org/main/code/1qy-5fj

    Or if you want the exact format:

    function generatePageTree($datas, $parent = 0, $depth = 0){
        $ni=count($datas);
        if($ni === 0 || $depth > 1000) return ''; // Make sure not to have an endless recursion
        $tree = '';
        for($i=0; $i < $ni; $i++){
            if($datas[$i]['parent'] == $parent){
                $tree .= str_repeat('-', $depth);
                $tree .= $datas[$i]['name'] . '<br/>';
                $tree .= generatePageTree($datas, $datas[$i]['id'], $depth+1);
            }
        }
        return $tree;
    }
    

    The test: http://phpfiddle.org/main/code/jw3-s1j