2

I have been working on this for long and I got it working as I want but I think there is simpler solution.

So far I got this:

$menu = array(
    0 => (object) array(
        'cat_id'   => 1,
        'cat_parent' => 0,
        'cat_name' => 'domov',
        'cat_href' => 'domov',
        'cat_subcategories' => array()
    ),
    1 => (object) array(
        'cat_id'   => 2,
        'cat_parent' => 0,
        'cat_name' => 'clanky',
        'cat_href' => 'clanky',
        'cat_subcategories' => array(
            0 => (object) array(
                'cat_id'   => 9,
                'cat_parent' => 2,
                'cat_name' => 'apple clanky',
                'cat_href' => 'apple',
                'cat_subcategories' => array(
                    0 => (object) array(
                        'cat_id'   => 11,
                        'cat_parent' => 9,
                        'cat_name' => 'iphone clanky',
                        'cat_href' => 'iphone',
                        'cat_subcategories' => array()
                    ),
                    1 => (object) array(
                        'cat_id'   => 12,
                        'cat_parent' => 9,
                        'cat_name' => 'macbook clanky',
                        'cat_href' => 'macbook',
                        'cat_subcategories' => array()
                    )
                )
            ),
            1 => (object) array(
                'cat_id'   => 10,
                'cat_parent' => 2,
                'cat_name' => 'microsoft clanky',
                'cat_href' => 'microsoft',
                'cat_subcategories' => array()
            ),
        )
    ),
    2 => (object) array(
        'cat_id'   => 3,
        'cat_parent' => 0,
        'cat_name' => 'produkty',
        'cat_href' => 'produkty',
        'cat_subcategories' => array()
    ),
    3 => (object) array(
        'cat_id'   => 4,
        'cat_parent' => 0,
        'cat_name' => 'vyrobcovia',
        'cat_href' => 'vyrobcovia',
        'cat_subcategories' =>
            array(
                0 => (object) array(
                    'cat_id'   => 5,
                    'cat_parent' => 4,
                    'cat_name' => 'apple',
                    'cat_href' => 'apple',
                    'cat_subcategories' => array(
                        0 => (object) array(
                            'cat_id'   => 7,
                            'cat_parent' => 5,
                            'cat_name' => 'iphone',
                            'cat_href' => 'iphone',
                            'cat_subcategories' => array()
                        ),
                        1 => (object) array(
                            'cat_id'   => 8,
                            'cat_parent' => 5,
                            'cat_name' => 'macbook',
                            'cat_href' => 'macbook',
                            'cat_subcategories' => array()
                        )
                    )
                ),
                1 => (object) array(
                    'cat_id'   => 6,
                    'cat_parent' => 4,
                    'cat_name' => 'microsoft',
                    'cat_href' => 'microsoft',
                    'cat_subcategories' => array()
                ),
            )
    ),
);
function generate_menu($menu, $level = 1, $tmp_array = array())
{
    foreach($menu as $key => $c)
    {
        $menu_item = get_menu_elements($c, $level);
        $tmp_array = array_replace_recursive($tmp_array, $menu_item);

        foreach($c->cat_subcategories as $_key => $_c)
        {
            $menu_item = get_menu_elements($_c, $level+1);
            $tmp_array = array_replace_recursive($tmp_array, $menu_item);

            foreach($_c->cat_subcategories as $__key => $__c)
            {
                $menu_item = get_menu_elements($__c, $level+2);
                $tmp_array = array_replace_recursive($tmp_array, $menu_item);
            }

        }
    }

    return $tmp_array;
}

function get_menu_elements($c, $level = 1)
{

    $level_var   = "level_".($level);


    $output = array(
        $level_var => array()
    );



    $output[$level_var][$c->cat_id] = array(
        'parent' => $c->cat_parent,
        'html'   => $c->cat_name
    );

    return $output;

}

In the end I should have multidimensional array with:

array(3) {
  ["level_1"]=>
  array(4) {
    [1]=>
    array(2) {
      ["parent"]=>
      int(0)
      ["html"]=>
      string(5) "domov"
    }
    [2]=>
    array(2) {
      ["parent"]=>
      int(0)
      ["html"]=>
      string(6) "clanky"
    }
    [3]=>
    array(2) {
      ["parent"]=>
      int(0)
      ["html"]=>
      string(8) "produkty"
    }
    [4]=>
    array(2) {
      ["parent"]=>
      int(0)
      ["html"]=>
      string(10) "vyrobcovia"
    }
  }
  ["level_2"]=>
  array(4) {
    [9]=>
    array(2) {
      ["parent"]=>
      int(2)
      ["html"]=>
      string(12) "apple clanky"
    }
    [10]=>
    array(2) {
      ["parent"]=>
      int(2)
      ["html"]=>
      string(16) "microsoft clanky"
    }
    [5]=>
    array(2) {
      ["parent"]=>
      int(4)
      ["html"]=>
      string(5) "apple"
    }
    [6]=>
    array(2) {
      ["parent"]=>
      int(4)
      ["html"]=>
      string(9) "microsoft"
    }
  }
  ["level_3"]=>
  array(4) {
    [11]=>
    array(2) {
      ["parent"]=>
      int(9)
      ["html"]=>
      string(13) "iphone clanky"
    }
    [12]=>
    array(2) {
      ["parent"]=>
      int(9)
      ["html"]=>
      string(14) "macbook clanky"
    }
    [7]=>
    array(2) {
      ["parent"]=>
      int(5)
      ["html"]=>
      string(6) "iphone"
    }
    [8]=>
    array(2) {
      ["parent"]=>
      int(5)
      ["html"]=>
      string(7) "macbook"
    }
  }
}

I want to print multi-level menu recursion. I got it working with this code but in function generate_menu I had to use 3 foreach loops for cat_subcategories. When I used recursion like this:

function generate_menu($menu, $level = 1, $tmp_array = array())
{
    foreach($menu as $key => $c)
    {
        $menu_item = get_menu_elements($c, $level);
        $tmp_array = array_replace_recursive($tmp_array, $menu_item);

        if (!empty($c->cat_subcategories)) generate_menu($c->cat_subcategories, $level + 1, $tmp_array);
    }

    return $tmp_array;
}

i got only 'level_1' in output

The output which I am getting now is the same I want I just want to simplify the multiple foreach()

etc. Basicaly

level_1 - first loop of $menu level_2 - loop of cat_subcategories level_3 - loop of cat_subcategories for cat_subcategories item

4
  • Please provide the desired output for the sample input. It is not clear what you expect the ....... to be after level_1, level_2 and level_3. Also, what is get_menu_elements? Commented Jul 22, 2017 at 13:18
  • edited, that function gets html file with template for menu and I am just basically parsing the data from database in the html. This structure is working I just find those loops in generate_menu unnecessary and I think they might be somehow simplified Commented Jul 22, 2017 at 14:59
  • I am trying to understand the output, but I immediately wonder why domov does not occur in your desired output. Maybe I am naive, but is that output only part of what you want? If so, could you just add a bit more? I would run your code if I could, but I don't have get_level_templates. Commented Jul 22, 2017 at 15:09
  • yep it was just part I didnt have the code with me. I edited the code so you can run it also included whole output Commented Jul 22, 2017 at 15:26

3 Answers 3

2

You essentially need to perform a breadth-first traversal in your menu tree. For that I would suggest an iterative function instead of a recursive function, as the latter is more suitable for a depth-first traversal.

Here is the function:

function generate_menu($menu) {
    $result = [];

    $level = 1;
    while (count($menu)) {
        $queue = [];
        $items = [];
        foreach($menu as $cat) {
            $items[$cat->cat_id] = [
                "parent" => $cat->cat_parent,
                "html" => $cat->cat_name
            ];
            $queue = array_merge($queue, $cat->cat_subcategories);
        }
        $result["level_$level"] = $items;
        $level++;
        $menu = $queue;
    }
    return $result;
}

See it run on eval.in.

As this function traverses the top level of the tree, it collects all the children into $queue. Once the top level has been translated into the output (in the level_1 key), that queue will have all second level entries. This then is moved to $menu, and the process is repeated, but now with level_2. This continues until a level is reached where no more entries are found.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks i was thinking about collecting the top level items first but didnt know what to do with the subcategories :D thanks
0

I've made some time ago this function. It could help you.

I've got an array where $arr[actual item][parental id]

function getChild($id, $result, $count) {
    for( $i = 0; $i < sizeof($result); $i ++) {
        if( $result[$i][2] == $id) {
            getChild($result[$i][0], $result, $count + 1);
        }
    }
}

EDIT

In my case, where all the items in the one-dimensional array, but with the hierarchy of n-dimensional array depended on the parental id.

1 Comment

Not my case I just need to edit my code so I dont have to use 3 loops but recursion cos I want to use my templates
0

CODE TO PRINT MENU

This code will work for N-number of hierarchy

 static function printAllCategoriesAsCheckbox($arr, $d=0){

    $htmlString = "";

    if (is_array($arr)){
        foreach($arr as $category){

            $htmlString = $htmlString . '<div><input style="margin-left: ' . 30*$d . 'px;" value="'.$category->id.'" class="category-input" type="checkbox" name="category_id[]">';

            $htmlString = $htmlString . ' <label for="category_'.$category->id.'">' . $category->name . '</label></div>';


            if (is_array($category['childs'])){
                $htmlString = $htmlString . ItemCategory::printAllCategoriesAsCheckbox($category['childs'], $d+1);
            }
        }
    }

    return $htmlString;
}

item list

3 Comments

Not my case I just need to edit my code so I dont have to use 3 loops but recursion cos I want to use my templates
@DeiForm it totally fit your template. I have seen that your input. you dont need 3 loops
I do not want string as retirn value

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.