[UPHPU] Hierarchical Menu Ideas
Brandon Stout
hplsbyufan at imapmail.org
Mon Dec 5 17:30:48 MST 2005
Here's a thread recap, with objective, summary, methods, results (so
far), and conclusion
OBJECTIVE:
I have a static hierarchical menu I wrote in JavaScript. I borrowed the
code from here:
http://javascript.internet.com/navigation/click-to-expand-menu.html
I use it for my main menu on my website:
http://mscis.org
I want to generate this menu with a MySQL hierarchy scheme described in
the section entitled "Finding the Depth of the Nodes" here:
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
I'm using the nested set model because of the several advantages it has
over the traditional categorization scheme.
THREAD SUMMARY
Here's my category table:
-- Table structure for table `categories`
--
CREATE TABLE `categories` (
`Created` datetime NOT NULL,
`Updated` timestamp NULL default CURRENT_TIMESTAMP,
`CategoryID` smallint(6) NOT NULL auto_increment,
`CategoryName` varchar(20) NOT NULL,
`LeftValue` smallint(6) NOT NULL,
`RightValue` smallint(6) NOT NULL,
`Description` text NOT NULL,
PRIMARY KEY (`CategoryID`),
UNIQUE KEY `UniqueLeft` (`LeftValue`),
UNIQUE KEY `UniqueRight` (`RightValue`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Web Page Categories'
AUTO_INCREMENT=9 ;
Full data dump available on request, the hierarchy looks like this:
TechWriting
Hardware
Network
ProjectManagement
phpMyResume
WebMaster
FamilyPages
METHOD 1:
My original php code had a syntax error (else does not use parameters):
Here's the revised code:
$mainMenuQuery="(
SELECT
COUNT(`parent`.`CategoryName`) - 1 AS `depth`,
`node`.`CategoryName` AS `Category`
FROM `web`.`categories` `node`, `web`.`categories` `parent`
WHERE
`node`.`LeftValue` BETWEEN `parent`.`LeftValue` AND `parent`.`RightValue`
AND `parent`.`LeftValue` > 1
GROUP BY `node`.`CategoryID`
ORDER BY `node`.`LeftValue`
)";
$mainMenu = mysql_query($mainMenuQuery);
echo "<ul id=\"containerul\">\r\n";
while($row = mysql_fetch_row($mainMenu)) {
for($i=0; $i < mysql_num_fields($mainMenu); $i++) {
if($row[0] = 0) {
echo "<li>$row[1]";
} elseif($row[0] > $row[0]--) {
echo "</li>\r\n<ul>\r\n <li>$row[1]";
} else {
echo "</li>\r\n</ul>\r\n<li>$row[1]";
}
}
}
echo "</li>\r\n</ul>";
RESULT 1:
This produces doubles of every list item, and problematic html code:
<ul id="containerul">
</li>
</ul>
<li>TechWriting</li>
</ul>
<li>TechWriting</li>
</ul>
<li>Hardware</li>
</ul>
<li>Hardware</li>
</ul>
<li>Network</li>
</ul>
<li>Network</li>
</ul>
<li>ProjectManagement</li>
</ul>
<li>ProjectManagement</li>
</ul>
<li>phpMyResume</li>
</ul>
<li>phpMyResume</li>
</ul>
<li>WebMaster</li>
</ul>
<li>WebMaster</li>
</ul>
<li>FamilyPages</li>
</ul>
<li>FamilyPages</li>
</ul>
METHOD 2:
Ryan Oldham suggested that $row-- wasn't doing what I thought it was
doing. He suggested using ($row - 1) instead.
I replaced this line in the above code:
} elseif($row[0] > $row[0]--) {
with this:
} elseif($row[0] > ($row[0] -1)) {
RESULT 2:
This also produces doubles of every list item, and problematic html code:
<ul id="containerul">
</li>
<ul>
<li>TechWriting</li>
<ul>
<li>TechWriting</li>
<ul>
<li>Hardware</li>
<ul>
<li>Hardware</li>
<ul>
<li>Network</li>
<ul>
<li>Network</li>
<ul>
<li>ProjectManagement</li>
<ul>
<li>ProjectManagement</li>
<ul>
<li>phpMyResume</li>
<ul>
<li>phpMyResume</li>
<ul>
<li>WebMaster</li>
<ul>
<li>WebMaster</li>
<ul>
<li>FamilyPages</li>
<ul>
<li>FamilyPages</li>
</ul>
METHOD 3:
Dave Boucha suggested using a variable to hold the previous row's
value. Here's the code I tested:
$mainMenu = mysql_query($mainMenuQuery);
$prevRow = '0';
echo "<ul id=\"containerul\">\r\n";
while($row = mysql_fetch_row($mainMenu)) {
for($i=0; $i < mysql_num_fields($mainMenu); $i++) {
if($row[0] = 0) {
echo "<li>$row[1]";
} elseif($row[0] > $prevRow) {
echo "</li>\r\n<ul>\r\n <li>$row[1]";
} else {
echo "</li>\r\n</ul>\r\n<li>$row[1]";
}
}
$prevRow = $row[0];
}
echo "</li>\r\n</ul>";
RESULT 3:
This seemed to produce the same output as method 1:
<ul id="containerul">
</li>
</ul>
<li>TechWriting</li>
</ul>
<li>TechWriting</li>
</ul>
<li>Hardware</li>
</ul>
<li>Hardware</li>
</ul>
<li>Network</li>
</ul>
<li>Network</li>
</ul>
<li>ProjectManagement</li>
</ul>
<li>ProjectManagement</li>
</ul>
<li>phpMyResume</li>
</ul>
<li>phpMyResume</li>
</ul>
<li>WebMaster</li>
</ul>
<li>WebMaster</li>
</ul>
<li>FamilyPages</li>
</ul>
<li>FamilyPages</li>
</ul>
METHOD 4:
Fred Larsen suggested a completely different approach, which resulted in
this code (I fixed one error in the select statement):
$mainMenuQuery="(
SELECT
`node`.`RightValue`,
`node`.`LeftValue`,
`node`.`CategoryName` AS `Category`
FROM
`web`.`categories` `node`,
`web`.`categories` `parent`
WHERE
`node`.`LeftValue` BETWEEN `parent`.`LeftValue` AND `parent`.`RightValue`
AND `parent`.`LeftValue` > 1
ORDER BY `node`.`LeftValue`
)";
$mainMenu = mysql_query($mainMenuQuery);
$right = array();
echo "<ul id=\"containerul\">\r\n";
while($row = mysql_fetch_row($mainMenu)) {
// only check stack if there is one
if (count($right) > 0) {
// check if we should remove a node from the stack
while (count($right) && $right[count($right)-1] < $row[0]) {
echo "</ul></li>\r\n";
array_pop($right);
}
}
echo '<li>' . $row[2];
if (($row[0] - $row[1]) > 1) {
echo '<ul>'; // new branch
} else {
echo "</li>\r\n"; // leaf node close
}
$right[] = $row[0];
}
// finish the tree
if (count($right) > 0) {
while (count($right)) {
echo "</ul></li>\r\n";
array_pop($right);
}
}
// complete the opening ul
echo "\r\n</ul>";
RESULT 4:
The result was again doubles of every list item, and problematic html code:
<ul id="containerul">
<li>TechWriting<ul><li>Hardware</li>
<li>Hardware</li>
</ul></li>
</ul></li>
<li>Network</li>
<li>Network</li>
</ul></li>
</ul></li>
</ul></li>
<li>ProjectManagement<ul><li>phpMyResume</li>
<li>phpMyResume</li>
</ul></li>
</ul></li>
</ul></li>
<li>WebMaster<ul><li>FamilyPages</li>
<li>FamilyPages</li>
</ul></li>
</ul></li>
</ul></li>
</ul>
CONCLUSION:
So far, each method produces results, but none of them achieve the
objective yet. Now that I'm getting results, I can see the how the code
produces what it does, and I'm working on some revisions to make it
work, but I have to run off now, and can't properly summarize what's
going on. In the mean time, I welcome any new ideas.
Thank you,
Brandon Stout
http://mscis.org
More information about the UPHPU
mailing list