Creating a menu from a categories table

#11
[eluser]Jondolar[/eluser]
You might not want to make the category name a unique field. It is not unreasonable for a sub menu to have the same name as some other sub menu in another branch. For example: You might have two top level menu categories of "Shirts" and "Pants". Each of them may have sub-categories of "Ladies" or "Mens".

If you plan on using the category name to reference the record, then it won't work.

#12
[eluser]skunkbad[/eluser]
[quote author="jedd" date="1259915600"]For anyone trying to follow that link - manually change the '#' to '% 23' (no space).

By the way - will your data have sub-menus that contain both leaf items as well as sub-menus themselves, or will it always be a collection of one or the other only?[/quote]

I don't know what these terms are, leaf vs. sub-menus.

I've got a good start on what I'm working on though. Just some procedural stuff:

Code:
<?php
$i = array();
$i[] = array('Examples'    ,1    ,0);
$i[] = array('Widgets'    ,2    ,1);
$i[] = array('Things'    ,3    ,0);
$i[] = array('Shiny'    ,4    ,3);
$i[] = array('Metal'     ,5    ,4);
$i[] = array('Silver'    ,6    ,5);

foreach($i as $a)
{
    // if top level
    if($a[2] == 0)
    {
        // create a top level category
        $menu[$a[0]] = array(
                        'category_id' => $a[1]
        );
    }
    else
    {
        foreach($menu as $b => $c)
        {
            if($c['category_id'] == $a[2])
            {
                $menu[$b]['sub'][$a[0]] = array(
                    'category_id' => $a[1]
                );
                break;
            }
            else if(array_key_exists('sub', $c))
            {
                foreach($c['sub'] as $d => $e)
                {
                    if($e['category_id'] == $a[2])
                    {
                        $menu[$b]['sub'][$d]['sub'][$a[0]] = array(
                            'category_id' => $a[1]
                        );
                        break;
                    }
                    else if(array_key_exists('sub', $e))
                    {
                        foreach($e['sub'] as $f => $g)
                        {
                            if($g['category_id'] == $a[2])
                            {
                                $menu[$b]['sub'][$d]['sub'][$f]['sub'][$a[0]] = array(
                                    'category_id' => $a[1]
                                );
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
}

function buildMenu($menu_array, $is_sub=FALSE)
{
    /*
     * If the supplied array is part of a sub-menu, add the
     * sub-menu class instead of the menu ID for CSS styling
     */
    $attr = (!$is_sub) ? ' id="menu"' : ' class="submenu"';
    $menu = "<ul$attr>\n"; // Open the menu container  
    /*
     * Loop through the array to extract element values
     */
    foreach($menu_array as $id => $properties) {

        /*
         * Because each page element is another array, we
         * need to loop again. This time, we save individual
         * array elements as variables, using the array key
         * as the variable name.
         */
        foreach($properties as $key => $val) {

            /*
             * If the array element contains another array,
             * call the buildMenu() function recursively to
             * build the sub-menu and store it in $sub
             */
            if(is_array($val))
            {
                $sub = buildMenu($val, TRUE);
            }

            /*
             * Otherwise, set $sub to NULL and store the  
             * element's value in a variable
             */
            else
            {
                $sub = NULL;
                $$key = $val;
            }
        }

        /*
         * If no array element had the key 'url', set the  
         * $url variable equal to the containing element's ID
         */
        if(!isset($url)) {
            $url = $id;
        }

        /*
         * Use the created variables to output HTML
         */
        $menu .= "<li><a href='$url'>$url</a>$sub</li>\n";

        /*
         * Destroy the variables to ensure they're reset  
         * on each iteration
         */
        unset($url, $display, $sub);
        
    }
    return $menu . "</ul>\n";
}

echo buildMenu($menu, FALSE);

#13
[eluser]wh1tel1te[/eluser]
Might want to have a look at Modified Preorder Tree Traversal. It is a different way of thinking about database table ordering, but once you get the hang of it, it will do exactly what you want: unlimited nesting.

#14
[eluser]überfuzz[/eluser]
My example covers infinite levels.

#15
[eluser]skunkbad[/eluser]
[quote author="überfuzz" date="1259928609"]My example covers infinite levels.[/quote]

I didn't start playing with that because while it may be recursive, and cover infinite levels, that would mean that there is a possiblity of infinite database queries. What I'm working on now needs only one query to build the menu.

#16
[eluser]überfuzz[/eluser]
Ehh... did you read my post..?

The idea way to cache the menu. The site will be much faster. The only draw back I can see is that you'll not be able to have the clicked link marked as active. But you where making a drop-down menu weren't you?

If you cache it every time someone logges out from backend, or when a cache button is fired in backend you'll end up with a fast and enough-dynamic-menu.

#17
[eluser]überfuzz[/eluser]
Seems I spelled badly. I meant to write cache. I edited it in my previous posts. Sorry!

#18
[eluser]skunkbad[/eluser]
Yes, caching could be beneficial. I think CI has something built in that I might be able to use.

What I've got now works, and that's a good starting point for me. It's a bit of a kludge, but at least I have something. What I'd like to do now is refine my function, and make it truly recursive (if possible).

#19
[eluser]bluepicaso[/eluser]
OK I some similar problem.
I have a system where the can create categories and sub-categories.
each can have tour packages and further sub-categories.. following the same rule..
Now i want to delete all the data from the category. No matter how may sub-categories they have or tours they have. I want to delete all of it...
I found a code it uses a recursive function. It lists the cats and sub-cats.

Code:
&lt;?php

//connect to database

$link = mysqli_connect('localhost','root','root');

mysqli_select_db($link,'around');





//get all rows

$query = mysqli_query($link,'SELECT * FROM category');

while ( $row = mysqli_fetch_assoc($query) )

{

        $menu_array[$row['cat_id']] = array('name' => $row['cat_name'],'parent' => $row['parent_cat']);
}
?&gt;
<pre>
&lt;?
//print_r($menu_array);
?&gt;
</pre>
&lt;?


//recursive function that prints categories as a nested html unorderd list

function generate_menu($parent)

{

        $has_childs = false;

        //this prevents printing 'ul' if we don't have subcategories for this category


        global $menu_array;

        //use global array variable instead of a local variable to lower stack memory requierment



        foreach($menu_array as $key => $value)

        {

                if ($value['parent'] == $parent)

                {      

                        //if this is the first child print '<ul>'                      

                        if ($has_childs === false)

                        {

                                //don't print '<ul>' multiple times                            

                                $has_childs = true;

                                echo '<ul>';

                        }

                        echo '<li><a href="/category/' . $value['name'] . '/">' . $value['name'] . '</a>';

                        generate_menu($key);

                        //call function again to generate nested list for subcategories belonging to this category

                        echo '</li>';

                }

        }

        if ($has_childs === true) echo '</ul>';

}





//generate menu starting with parent categories (that have a 0 parent)

generate_menu(31);

Now while translating that code to CI, I'm stuck with the declaration ofthe global varaible...
Please help.

The CI code is below
Code:
function _getCatTree()

    {

        

        $this->load->model('get');

        $rslt = $this->get->getAllCats();

        foreach($rslt as $row)

        {

            $this->menu_array[$row['cat_id']] = array('name' => $row['cat_name'],'parent' => $row['parent_cat']);

        }

    }

    

    

    function _generate_menu($parent)

    {

        

        $has_childs = false;

        //this prevents printing 'ul' if we don't have subcategories for this category

        //use global array variable instead of a local variable to lower stack memory requierment

        foreach($menu_array as $key => $value)

        {

            if ($value['parent'] == $parent)

            {      

                //if this is the first child print '<ul>'

                if ($has_childs === false)

                {

                        //don't print '<ul>' multiple times                            

                        $has_childs = true;

                        echo '<ul>';    

                }

                echo '<li><a href="/category/' . $value['name'] . '/">' . $value['name'] . '</a>';

                _generate_menu($key);

                //call function again to generate nested list for subcategories belonging to this category

                echo '</li>';

            }

        }

        if ($has_childs === true) echo '</ul>';

    }

    

    function catTree2Delete()

    {

        $id = $this->input->post('catid');

        $this->_getCatTree();

        $this->_generate_menu($id);

    }

please help.. its urgent

#20
[eluser]skunkbad[/eluser]
Take a look at the remove_children method:

http://bitbucket.org/skunkbad/community-...entory.php

If you follow what is going on, you could make it work for yourself. This would target the categories for you, and then you could simply delete them using a standard delete query.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2021 MyBB Group.