1

I have a single array containing menu items. Each item have its parent_id. I am searching and trying for many hours but can't figure out how to traverse the array recursively. I'm not good at recursion.

I have tried to use the code from the following post. It generates the html menu but it misses the 1st record also I want an array so I can make custom html menu out of the array.

Using recursion to build navigation

I have tried this code from an other post but it returns empty array.

create_array(-1, $array);

function create_array($number, $data)
{
    $result = array();
    foreach ($data as $row)
    {
        if ($row['parent_id'] == $number)
        {
            $result[$row['id']] = create_array($row['id'], $data);
        }
    }
    return $result;
}

data array:

Array
(
    [0] => Array
        (
            [id] => 1
            [parent_id] => -1
            [url] => /home
        )

    [1] => Array
        (
            [id] => 2
            [parent_id] => 0
            [url] => /page
        )

    [2] => Array
        (
            [id] => 3
            [parent_id] => 2
            [url] => /page/sub_page
        )

    [3] => Array
        (
            [id] => 4
            [parent_id] => 3
            [url] => /page/sub_page/inner_page/
        )

)

result desired:

home - page
         sub_page
           inner_page

Any help will be very appreciated please.

Community
  • 1
  • 1
Abdul Rehman
  • 1,662
  • 3
  • 22
  • 36

2 Answers2

1

What it should do is start by printing the ones with 0 as parent, for each one find it's children and start again for each children.

Something like:

function menu($data,$parent=-1) {
    $res='';    
    foreach($data as $e) {
        if($e['parent_id']==$parent||($parent==-1&&$e['parent_id']==0)) { //Also search for 0 when parent is  -1 as are both the roots
            $res.='<li>'.$e['url']; //Or whatever you want to show
            $sub=menu($data,$e['id']);
            if($sub) $res.='<ul>'.$sub.'</ul>';
            $res.='</li>';
         }
    }
    return $res;
}

<ul><?=menu($data)?></ul>
Gabriel
  • 2,170
  • 1
  • 17
  • 20
  • Thanks a bunch. This works great. I'll use this but can you provide a way to return an array instead of printing it? I don't understand how to do that. But This works very nice for my situation. – Abdul Rehman Apr 25 '16 at 08:36
  • 1
    Exactly as you did it. Populating an array instead of printing. – Gabriel Apr 25 '16 at 13:44
0

Thanks to Gabriel, I have used his method to create an other method that returns an array for the menu.

 $data = array(
    array('id'=>1, 'parent_id'=>-1, 'url_title'=>'home', 'url'=>'/home'),
    array('id'=>2, 'parent_id'=>0, 'url_title'=>'page-one', 'url'=>'/page-one'),
    array('id'=>3, 'parent_id'=>2, 'url_title'=>'sub-page', 'url'=>'/sub-page'),
    array('id'=>4, 'parent_id'=>3, 'url_title'=>'inner-page', 'url'=>'/inner-page')
    );


function menu_html($data,$parent=-1) {
    $res='';
    foreach($data as $e) {
        if($e['parent_id']==$parent||($parent==-1&&$e['parent_id']==0)) {
            $res.='<li>'.$e['url'];
            $sub=menu_html($data,$e['id']);
            if($sub) $res.='<ul>'.$sub.'</ul>';
            $res.='</li>';
         }
    }
    return $res;
}

echo '<ul>'.menu_html($data).'</ul>';

function menu_array($data,$parent=-1) {
    $res=array();
    foreach($data as $e) {
        if($e['parent_id']==$parent||($parent==-1&&$e['parent_id']==0)) {
            $res[$e['url']] = $e;
            $sub=menu_array($data, $e['id']);
            if($sub) $res[$e['url']]['sub-nav'] = $sub;
         }
    }
    return $res;
}

echo "<pre>";
print_r(menu_array($data));
echo "</pre>";

Output:

    /home
    /page-one
        /sub-page
            /inner-page

Array
(
    [/home] => Array
        (
            [id] => 1
            [parent_id] => -1
            [url_title] => home
            [url] => /home
        )

    [/page-one] => Array
        (
            [id] => 2
            [parent_id] => 0
            [url_title] => page-one
            [url] => /page-one
            [sub-nav] => Array
                (
                    [/sub-page] => Array
                        (
                            [id] => 3
                            [parent_id] => 2
                            [url_title] => sub-page
                            [url] => /sub-page
                            [sub-nav] => Array
                                (
                                    [inner-page] => Array
                                        (
                                            [id] => 4
                                            [parent_id] => 3
                                            [url_title] => inner-page
                                            [url] => inner-page
                                        )

                                )

                        )

                )

        )

)
Abdul Rehman
  • 1,662
  • 3
  • 22
  • 36