views:

189

answers:

1

Hello Everyone,

I am trying to build a dynamically generated unordered list in the following format using PHP. I am using CodeIgniter but it can just be normal php.

This is the end output I need to achieve.

<ul id="categories" class="menu">
<li rel="1">
    Arts &amp; Humanities
    <ul>
        <li rel="2">
            Photography
            <ul>
                <li rel="3">
                    3D
                </li>
                <li rel="4">
                    Digital
                </li>
            </ul>
        </li>
        <li rel="5">
            History
        </li>
        <li rel="6">
                        Literature
        </li>
    </ul>
</li>
<li rel="7">
    Business &amp; Economy
</li>
<li rel="8">
    Computers &amp; Internet
</li>
<li rel="9">
    Education
</li>
<li rel="11">
    Entertainment
    <ul>
        <li rel="12">
            Movies
        </li>
        <li rel="13">
            TV Shows
        </li>
        <li rel="14">
            Music
        </li>
        <li rel="15">
            Humor
        </li>
    </ul>
</li>
<li rel="10">
    Health
</li>

And here is my SQL that I have to work with.

--
-- Table structure for table `categories`
--

CREATE TABLE IF NOT EXISTS `categories` (
  `id` mediumint(8) NOT NULL auto_increment,
  `dd_id` mediumint(8) NOT NULL,
  `parent_id` mediumint(8) NOT NULL,
  `cat_name` varchar(256) NOT NULL,
  `cat_order` smallint(4) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

So I know that I am going to need at least 1 foreach loop to generate the first level of categories.

What I don't know is how to iterate inside each loop and check for parents and do that in a dynamic way so that there could be an endless tree of children.

Thanks for any help you can offer.

Tim

+3  A: 

If you're outputting every category, then I'd probably do it in two steps:

First, grab all the relevant data from the database

$items = array();

$res = mysql_query(...);
while ($row = mysql_fetch_assoc($res)) {
 $items[$row['parent_id']][] = $row;
}

Then you have all your items grouped by their parent. You can then use a recursive function to process them all:

function showMenu($items, $parent = null) {
 // Assuming root elements have parent_id of 0:
 $index = $parent == null ? '0' : $parent;

 if (empty($items[$index])) {
  // No children, don't output anything
  return;
 }

 echo '<ul', $parent == null ? ' id="categories" ... ' : '', '>';

 foreach ($items[$index] as $child) {
  echo '<li rel="', $child['id'], '">', htmlentities($child['cat_name']);
  showMenu($items, $child['id']);
  echo '</li>';
 }

 echo '</ul>';
}

showMenu($items);

The function is recursively called for each item in the menu, and checks to see if that item has any children. If it does, it prints out the relevant <li/> entries and calls itself again to print out the children of that item.

Chris Smith
Hey Dude, Thats amazing. Works so well. Thank-you so much for taking the time to make and share that code. I am wondering if there is an easy way to make the script generic enough so that it can handle multiple lists (so using dd_id in the DB as the list identifier) ?Once again, thankyou so muchTim
Tim
@Tim - No problem. As for making it generic, how about putting the initial bit (that builds the $items array) in a function which takes an $id param, then just modify the SQL query to select where dd_id = $id?
Chris Smith
Hey Chris,My friend and I have been trying to nut this out but I think ive ended up confusing myself. Could you (if you have any time) post an example of how I can generate lists based on the dd_id field in the db ?
Tim