Horizontal traversal - return items belonging to one node from a menu tree

12th Sep, 2011 | oop joomla

Problem: For a tree of heirarchical records with an id and parentid return all the records belonging to one node.

Thought this would be easy as the structure was not required, only the id's of the items.

Took a bit of doing but the key was forming the recursive function signature (input parameters and return value)

    /**
     * 
     * Returns a flat array of Joomla menuids
     */
    private function getMenuidsFor($nodeId) 
    {    
         $this->_db->setQuery('SELECT * FROM #__menu WHERE menutype="uko3_main"');
         $allids = $this->_db->loadAssocList('id'); 

         $output = array();

         $this->_recurseMenuItems($allids, array($nodeId), $output);

         return $output;
    }

    /**
     * Recursive function to descend into the depths of the menu and populate the $output array
     * as it goes. Not a depth first traversal but depth last (?)
     * @param array $menu               source array of menu items
     * @param array $search             items to search for this recursion
     * @param array $output             output array to aggregate all seaching
     */
    private function _recurseMenuItems(array &$menu, array $search, array &$output) 
    {
        if (count($search)) {
            foreach($search as $menuid) {
                $this->_recurseMenuItems($menu, $this->_getMenuItemChildren($menu, $menuid, $output), $output);                          
            }
        }
    }

    /**
     * Returns result array of menu ids for all children of the given menuid from menu
     * If no children exist return empty array
     * @param array &$menu       array of menu items, indexed by menuid
     * @param int $menuid        parent menu item
     * @return array             children of menuid
     */
    private function _getMenuItemChildren(array &$menu, $menuid, array &$output) 
    {
        $results = array();
        $keys = array_keys($menu);

        foreach($keys as $id) {
            if ($menu[$id]['parent'] == $menuid) {
                $results[] = $id;
                $output[] = $id;
                unset($menu[$id]);
            }
        }                

        return $results;
    }