0

Good afternoon guys, I'm having a hard time finding the solution to this simple problem, I hope someone can help me.

I have a recursive array automatically generated by the source code, I use this array as the system's menu tree, however, it goes through a permission system, and some submenus are excluded, leaving certain menus empty, follow the example in JSON:

{
    "1": {
        "id": 1,
        "idFather": null,
        "nome": "test 1",
        "sub": {
            "4": {
                "id": 4,
                "idFather": 1,
                "nome": "test 1.1",
                "sub": {}
            },
            "5": {
                "id": 5,
                "idFather": 1,
                "nome": "test 1.2",
                "sub": {
                    "7": {
                        "id": 7,
                        "idFather": 5,
                        "nome": "test 1.3.1",
                        "sub": {}
                    },
                    "8": {
                        "id": 8,
                        "idFather": 5,
                        "nome": "test 1.3.2",
                        "sub": {}
                    }
                }
            },
            "6": {
                "id": 6,
                "idFather": 1,
                "nome": "test 1.3"
            }
        }
    },
    "2": {
        "id": 2,
        "idFather": null,
        "nome": "test 2"
    },
    "3": {
        "id": 3,
        "idFather": null,
        "nome": "test 3",
        "sub": {
            "10": {
                "id": 10,
                "idFather": 3,
                "nome": "test 3.2"
            }
        }
    }
}

Within key 1 I have key 4 with no other items, and I have key 5 with two keys (7 and 8), however, these 2 keys also do not contain items, so I need to remove keys 4, 7, 8 and consequently, key 5 too, as it will be empty at the end of the removals! Note that key 6 inside key 1, key 10 inside key 3 and key 2 do not contain the "sub" element, so it must not be removed!

I am Brazilian, so my English may be a little rusty.

1 Answers1

0

A simple recursive function will handle this.

  • Check each entry at the current level.
  • If it has a sub menu, call the function on the sub menu. If not, move on.
  • If the sub menu is now empty, remove it

The implementation looks like this:

$jsonString = "{...}"; // Your data listed above, omitted here for clarity

$menus = json_decode($jsonString);

// Pass a menu into the function. 
// PHP passes objects by reference, so we're operating directly
// on the original object, hence no need for a return value.

function clearMenu(object $menu):void {

    foreach($menu as $id=>$entry) {
        if (isset($entry->sub)) {              // If we have a submenu, handle it
            clearMenu($entry->sub);
            if (empty((array)$entry->sub)) {  // Cast object to array to test for emptiness
                unset($menu->$id);            // Unset the item in the menu using the key. Unsetting the item directly doesn't work
            }
        }
    }
}

clearMenu($menus);

$newMenus = json_encode($menus, JSON_PRETTY_PRINT);
echo "<pre>$newMenus</pre>";

Output:

{
    "1": {
        "id": 1,
        "idFather": null,
        "nome": "test 1",
        "sub": {
            "6": {
                "id": 6,
                "idFather": 1,
                "nome": "test 1.3"
            }
        }
    },
    "2": {
        "id": 2,
        "idFather": null,
        "nome": "test 2"
    },
    "3": {
        "id": 3,
        "idFather": null,
        "nome": "test 3",
        "sub": {
            "10": {
                "id": 10,
                "idFather": 3,
                "nome": "test 3.2"
            }
        }
    }
}
  • I had to do some modifications by myself, i think it's because i am using PHP 7. But thanks very much for the help!!! I will post here my modifications `code` function clearMenu($menu) { $newMenu = $menu; foreach($menu AS $id => $entry) { if (array_key_exists('sub', $entry)) { $newMenu[$id]['sub'] = clearMenu($newMenu[$id]['sub']); if (empty($newMenu[$id]['sub'])) { unset($newMenu[$id]); } } } return $newMenu; } `code` – Vitor Delgallo Feb 13 '21 at 00:46
  • I'm running PHP8, but apart from the type-hinting I think it should run in PHP 7. I'll take a look later. – Tangentially Perpendicular Feb 13 '21 at 00:58
  • Just an update: I reconfigured my development server to run PHP7.3, and ran the code I posted here untouched. It worked without a problem. I'm not sure why you needed to make modifications. Perhaps the actual data you have differs slightly from the data you posted. – Tangentially Perpendicular Feb 13 '21 at 01:54