Help - Search - Members - Calendar
Full Version: How to do infinite subcats?
Invision Power Services > Community Forums > Community Web Design and Coding
ZuCruTrooper2
I've been developing news systems and download managers for some time for special uses, but I've recently run into a problem that I can't figure out.

My category tables (in MySQL) are pretty standard (name,id,parent,num_files), but I cannot figure out how to generate a navlinks system that will go through and find each parent category for the current until it reaches one with zero (a root cat.)

My goal is to make it like the IPB navlinks, where if I add a category and set the parent for it to, say, 15, that it will automatically find all links up through the heirarchy.

Any pointers would be much appreciated!

Thanks!
Phil Mossop
Here is how I would do it, I've commented the code so hopefully you can follow it even though it is a little complicated. Jut ask if you have any questions.

I have manually populated the $cats array but you would do it by querying your database and loading all categories into this array. It is structured like this:

$cats[ category_id ] = array ( 'name' => category_name, 'parent' => parent_id )

This might not scale very well if you have lots of categories, you might have to cache the $cats array to a file. That's the best way I see to avoid speed issues.

CODE
<?php

$cats[1] = array('name' => 'Test1', 'parent' => 0 );
$cats[2] = array('name' => 'Test2', 'parent' => 0);
$cats[3] = array('name' => 'Test3', 'parent' => 2 );
$cats[4] = array('name' => 'Test4', 'parent' => 2);
$cats[5] = array('name' => 'Test5', 'parent' => 3 );
$cats[6] = array('name' => 'Test6', 'parent' => 4);
$cats[7] = array('name' => 'Test7', 'parent' => 6);

// Set category to find parents for
$curr_id = 5;

// Array to store results in
$breacrumb = array();

// Load our current category
$breadcrumb[ $curr_id ] = $cats[ $curr_id ]['name'];

// Make sure we have categories
if ( count($cats) )
{
    // Loop while there is a still a parent to be found
    while ( $cats[ $curr_id ]['parent'] > 0 )
    {
        // Loop through all the categories
        foreach ( $cats as $id => $info )
        {
            // Is the parent ID of the category we are looking for
            // the same as the ID of the ID of this cateogry?
            if ( $cats[ $curr_id ]['parent'] and $cats[ $curr_id ]['parent'] == $id )
            {
                // It is, so add this to our breadcrumb array
                // and set the current category ID to continue
                $breadcrumb[ $id ] = $info['name'];
                $curr_id = $id;
                break 1;
            }
        }
    }
}

// Reverse the array so that the top category appears
// first which is more logical
$breadcrumb = array_reverse($breadcrumb, true);

// Print the breadcrumbs!
print_r($breadcrumb);

?>


All you have to do at the end is loop through the $breadcrumb array outputting a formatted link instead of just doing print_r(). Hope this helps, or at least sets you on the right track. original.gif
ZuCruTrooper2
Thanks a million Phil!

I'll try it out and let you know.
Phil Mossop
I made the loop a bit cleaner, updated my original post.
Arkitus
I remember having trouble with the same problem back when I was working on Arki-DB. Ah, the good ol' days...
Wombat
Sitepoint.com: Storing Hierarchical Data in a Database thumbsup.gif

Categories, once set up, tend to be fairly static, in that you don't often add or remove them to the database. With that in mind, you can afford for the INSERT or DELETE operations to be a lot slower than the SELECT operations.

That article explains a good way for storing tree structures in a database in that situation.
Phil Mossop
Looks like an interesting read, thanks Wombat. There is certainly more than one way to skin this particular cat...
Phil Mossop
Here's a better way of doing it (in comparison to my first try anyway), and it's about 20% faster. biggrin.gif

CODE
<?php

$cats[1] = array('name' => 'Test1', 'parent' => 0 );
$cats[2] = array('name' => 'Test2', 'parent' => 0);
$cats[3] = array('name' => 'Test3', 'parent' => 2 );
$cats[4] = array('name' => 'Test4', 'parent' => 2);
$cats[5] = array('name' => 'Test5', 'parent' => 3 );
$cats[6] = array('name' => 'Test6', 'parent' => 4);
$cats[7] = array('name' => 'Test7', 'parent' => 6);

// Set category to find parents for
$curr_id = 5;

// Array to store results in
$breacrumb = array();

// Load our current category
$breadcrumb[ $curr_id ] = $cats[ $curr_id ]['name'];

// Get the parent ID of the current category
$pid = $cats[ $curr_id ]['parent'];

while ( $pid )
{
    // See if a category with the ID of the current parent ID
    // is in our array
    if ( array_key_exists($pid, $cats) )
    {
        // Yes, add to breacrumb trail and update $pid
        $breadcrumb[ $pid ] = $cats[ $pid ]['name'];
        $pid = $cats[ $pid ]['parent'];
    }
    else
    {
        // No, so end the loop
        break;
    }
}

$breadcrumb = array_reverse($breadcrumb, true);
print_r($breadcrumb);

?>
ZuCruTrooper2
Works great Phil, thanks again!
Rikki
QUOTE(Phil Mossop @ Apr 30 2006, 04:50 PM) *
Looks like an interesting read, thanks Wombat. There is certainly more than one way to skin this particular cat...


Can I just say, that's the worst pun EVER. You should be ashamed of yourself tongue.gif

fear.gif
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2009 Invision Power Services, Inc.