7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
1/33
Building an Extensible Menu Class
By Team Melonfire
This article copyright Melonfire 20002002. All rights reserved.
http://www.melonfire.com/http://www.melonfire.com/7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
2/33
Table of ContentsThe Horns Of A Dilemma..................................................................................................................................1
Back To Class......................................................................................................................................................2
What's On The Menu?.......................................................................................................................................4
Children And Their Parents..............................................................................................................................5
I Say Method, You Say Madness.......................................................................................................................7
Playing With Nodes...........................................................................................................................................10
Rounding Up The Family.................................................................................................................................13
Saving My Bookmarks.....................................................................................................................................17
Reaching Higher................................................................................................................................................21
Collapsing Inwards...........................................................................................................................................27
Extending Yourself...........................................................................................................................................30
Building an Extensible Menu Class
i
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
3/33
The Horns Of A Dilemma
How many times have you sat down to code a script and halfway through thought to yourself, "Didn't I do
something similar just last week?"
If you're anything like the average Web developer, you probably ask yourself this question at least once everyfew days. And more often than not, you're torn between coding the same functions again (because you're
already halfway there and looking for last week's code just isn't worth the effort) and spending an hour
searching for that ittybitty script on your twentyterabyte hard drive (because it's just more convenient to
modify last week's code than to write it all over again.)
It's to resolve precisely this sort of dilemma that a bunch of whitehaired software gurus (who, according to
legend, live on a snowy mountain peak in the Himalayas and spend most of their time coding algorithms to
calculate the value of pi to the nth decimal) came up with the concept of objectoriented programming. Very
simply, objectoriented programming allows developers to create reusable, extensible program modules in
order to speed up code development and maintenance.
Now, you may not know this, but my favourite language and yours, PHP, comes with some pretty powerful
OOP capabilities. And over the course of this article, I'm going to demonstrate some of them by building an
object to address a very common task generating a menu tree on a Web site. That's not all, though once
I've successfully created a Menu object, I'm going to torturetest it with some of the most popular menu
systems available on the Web to see if it does, in fact, offer any significant advantages.
If all goes well, this experiment should teach you a little about the theory and possible applications of OOP;
provide you with a Menu class which is (hopefully) useful to you in your development activities; and perhaps
even spark off some ideas for using PHP classes in your next project. If, on the other hand, I crash and burn,
you'll have something to snicker over at the pub tonight.
Sounds like fun? Keep reading.
The Horns Of A Dilemma 1
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
4/33
Back To Class
Before we begin, let's just go over the basics quickly:
In PHP, a "class" is simply a set of program statements which perform a specific task. A typical class
definition contains both variables and functions, and serves as the template from which to spawn specificinstances of that class.
Once a class has been defined, PHP allows you to spawn as many instances of the class as you like. These
instances of a class are referred to as "objects". Each of these instances is a completely independent object,
with its own properties and methods, and can thus be manipulated independently of other objects.
This comes in handy in situations where you need to spawn more than one instance of an object for
example, two simultaneous database links for two simultaneous queries, or two shopping carts. Classes also
help you to separate your code into independent modules, and thereby simplify code maintenance and
changes.
A class definition typically looks like this:
Once the class has been defined, an object can be spawned with the "new" keyword and assigned to a PHP
variable,
Back To Class 2
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
5/33
$myCart = new ShoppingCart;
?>
which can then be used to access all object methods and properties.
Building an Extensible Menu Class
Back To Class 3
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
6/33
What's On The Menu?
So that's the theory. Let's now spend a few minutes discussing the rationale behind the Menu object I plan to
build.
Conceptually, a Web site can be considered as a combination of two things: menus and content. Menus areused to organize and classify the type of content, and to offer one or more navigational paths to specific
content modules.
Now, although a menu may be visually presented in a number of different ways, there are certain common
elements present in every menu:
1. Most menus are broken into levels, with each level more focused than the last; this hierarchical structure is
sometimes referred to as a "menu tree".
2. Every menu tree consists of nodes connected to each other by branches.
3. A node may have one or more children, but can have only one parent.
Using these common principles, it is possible to build a Menu object which exposes certain generic methods.
These methods will have nothing to do with the visual presentation of the menu tree; rather, they provide a
simple API to various menu attributes and relationships, and can be used by client or serverside scripts
which are more closely connected to the presentation layer.
What's On The Menu? 4
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
7/33
Children And Their Parents
Now, the Menu object that I plan to build actually consists of two components: a database, and a series of
functions to interact with it. The database contains all the raw data needed to generate the menu tree, while the
class contains all the functions needed to massage the data into a useful format.
I plan to use a very simple mySQL table to store all my menu information, as well as the relationships
between the various levels of the tree take a look:
#
# Table structure for table 'menu'
#
DROP TABLE IF EXISTS menu;
CREATE TABLE menu (
id tinyint(3) unsigned NOT NULL auto_increment,label varchar(255) NOT NULL,
link varchar(255),
parent tinyint(3) unsigned DEFAULT '0' NOT NULL,
PRIMARY KEY (id)
);
#
# id unique identifier for each node
# label descriptive text for each node
# link URL for each node
# parent id of this node's parent#
This design makes it easy to represent a hierarchical menu tree in terms of database records. For example, I
could represent the following visual tree
USA
|
| California
|| Los Angeles
|
| Massachusetts
|
| Boston
United Kingdom
Children And Their Parent... 5
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
8/33
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
9/33
I Say Method, You Say Madness...
With the database design out of the way, it's now time to begin work on the methods which will interact with
the records in the database. Before actually sitting down to code the class, it's a good idea to spend some time
listing the important methods, together with their purpose. Here's my initial cut:
query($query) execute an SQL query;
get_children($node) return a collection of this node's children;
get_parent($node) return the identifier of this node's parent;
get_label($node) return the name of this node
get_type($node) return the node type (leaf or branch)
is_root_node($node) is this node at the root level or not?
These are the essential methods; there may be more, which I will add as development progresses.
Let's now begin by setting up the class definition:
Now, since this class will be talking to a database, I need to
add a few
variables to hold databasespecific information.
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
10/33
var $hostname;
var $user;
var $pass;
// database and table containing menu data
var $db;
var $table;
}
?>
PHP makes it possible to automatically execute a specific function when a new instance of a class is spawned.
This function is referred to as a "constructor" and must have the same name as the class.
In this case, I plan to initialize my Menu object with certain default values for the various database
parameters. I have the option of assigning these variablevalue pairs individually, or writing a method toassign them all in one fell swoop; I pick the latter.
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
11/33
?>
In case you're wondering, the $this prefix provides a convenient way to access variables and functions which
are "local" to the class
Now, all the methods listed above will be querying the database for information. Since the
connectandquery code is common to all of them, I can extract it into a separate method named query().
All my object methods can now simply use query() to execute SQL queries on the database. Further if I ever
decide to move to another database, I need only update the code in this single function to ensure that my class
will continue to work with the new system.
Building an Extensible Menu Class
I Say Method, You Say Mad... 9
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
12/33
Playing With Nodes
With the underlying, databasespecific layer in place, I can now begin work on the main object methods. The
first of these is also one of the simplest it accepts a node id and returns the id of the node's parent.
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
13/33
}
?>
The get_label() and get_link() methods accept a node id and return the corresponding text and URL from the
table.
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
14/33
Los Angeles
Building an Extensible Menu Class
Playing With Nodes 12
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
15/33
Rounding Up The Family
Next, one of the most useful methods in this collection the get_children() method. This method accepts a
node id and returns an array containing the next level of the menu tree.
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
16/33
}
echo "";
?>
And this correctly displays the children of node id 1 (USA) to be
California
Massachusetts
A useful corollary of this is the get_type() method, which can be used to
identify whether a particular node on the tree has children or not in
other words, whether it is a leaf or a branch.
The get_ancestors() method does the reverse of the get_children() method it returns a list of nodes between
the tree root and the supplied node identifier, starting from the top of the menu tree and proceeding
downwards.
Building an Extensible Menu Class
Rounding Up The Family 14
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
17/33
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
18/33
would return
USA
Massachusetts
Finally, the print_menu_tree() method comes in handy while debugging, if
you need to visually see the complete menu tree with its internal
dependencies.
Building an Extensible Menu Class
Rounding Up The Family 16
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
19/33
Saving My Bookmarks
At this stage, I think I have enough building blocks to actually begin using this class to build menu trees.
Keep in mind, though, that I've been wrong before, and so my initial feeling of satisfaction may soon
disappear.
The only way to find out for sure is to try building a tree to see if the methods exposed by the class are simple
and generic enough to be used in a variety of situations so let's do that. I will attempt to use this Menu class
to build a simple Web portal, which has links classified into hierarchical categories (a lot like the Open
Directory Project at http://www.dmoz.org/)
This is a good time to download the accompanying source code, which contains complete versions of the SQL
records displayed below, together with a copy of the final Menu class.
menu.zip
Since this is a portal, my database needs to reflect the various categories and links. Here's a snippet:
mysql> SELECT id, link, label, parent FROM menu3;
+++++
| id | link | label | parent |
+++++
| 1 | | Server Side | 0 |
| 2 | | Client Side | 0 |
| 3 | | Tools | 0 |
| 4 | | DevTalk | 0 |
| 5 | http://www.devshed.com/ClipScripts/ | ClipScripts | 0 || 6 | http://www.devshed.com/rdf.html | DevShed RDF | 0 |
| 7 | http://www.devshed.com/Propaganda | Propaganda! | 0 |
| 8 | http://www.ngenuity.com/advertise/ | About DevShed | 0 |
| 9 | | Administration | 1 |
+++++
My user interface should clearly reflect this menu tree, by making a distinction between "categories" and
"links". A click on a category reveals the subcategories and links under it, while a click on a link directs the
browser to the appropriate content module or URL.
Here's the script to accomplish this:
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
20/33
// create Menu
$obj = new Menu;
// get next level
$children = $obj>get_children($id);
// check to see if items are "leaves" or "branches" on the
tree
for ($x=0; $xget_type($children[$x]["id"]) == 1)
{
$branches[] = $children[$x];
}
else
{
$leaves[] = $children[$x];
}
}
// get lineage from tree root (used to create navigation path)
$ancestors = $obj>get_ancestors($id)
?>
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
21/33
echo $path;
?>
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
22/33
$leaves[$x]["label"] .
"
";
}
?>
In this case, I'm first using the get_children() method to obtain a list of all items under the current tree branch.
I'm then using the get_type() method to split the list of child nodes into two separate arrays, $branches and
$nodes, and formatting and displaying each appropriately. Finally, with the help of the get_ancestors()
method, I'm building a hierarchical, clickable trail leading to the current node just like any good portal
would.
Here's what the end result looks like:
Building an Extensible Menu Class
Saving My Bookmarks 20
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
23/33
Reaching Higher
Now, while that's all fine and dandy, a portal is perhaps the simplest application of this class. It remains to be
seen if it can be used with other, more complex menu interfaces. So let's put it to the test, by putting it in the
ring with some popular JavaScriptbased menu systems.
The first of these is the very popular HIERmenus script (available at
http://www.webreference.com/dhtml/hiermenus/ ). This very flexible menu system is completely written in
JavaScript, and relies on JavaScript arrays (packaged in a specific format) to build a hierarchical menu tree.
I'm not going to get into the nittygritty of how it works there's some excellent documentation if you're
interested but rather plan to focus on how this clientside code can be connected to a database of menu
items via the Menu class.
Let's suppose that I wanted to build a menu tree which looked like this:
mysql> SELECT id, label, parent FROM menu;++++
| id | label | parent |
++++
| 1 | Services | 0 |
| 2 | Company | 0 |
| 3 | Media Center | 0 |
| 4 | Your Account | 0 |
| 5 | Community | 0 |
| 6 | For Content Publishers | 1 |
| 7 | For Small Businesses | 1 |
| 8 | Background | 2 || 9 | Clients | 2 |
| 10 | Addresses | 2 |
| 11 | Jobs | 2 |
| 12 | News | 2 |
| 13 | Press Releases | 3 |
| 14 | Media Kit | 3 |
| 15 | Log In | 4 |
| 16 | Columns | 5 |
| 17 | Colophon | 16 |
| 18 | Cut | 16 |
| 19 | Boombox | 16 |
| 20 | The HITG Report | 16 |
| 21 | Trog | 16 |
++++
21 rows in set (0.06 sec)
If I was to build this menu using the HIERmenus system, I would need to manually code a series of JavaScript
arrays, like this:
Reaching Higher 21
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
24/33
HM_Array1 = [ [180, 200, 50, "black", "white", "white",
"black", "black",
"gray", 0, 0, 0, 1, 1, 1, "null", "null", ,], ["Services",
"http://www.melonfire.com/services/", 1, 0, 1], ["Company",
"http://www.melonfire.com/company/", 1, 0, 1], ["Media
Center",
"http://www.melonfire.com/mcenter/", 1, 0, 1], ["Your
Account",
"http://www.melonfire.com/account/", 1, 0, 1], ["Community",
"http://www.melonfire.com/community/", 1, 0, 1] ];
HM_Array1_1 = [ [180, 200, 50, "black", "white", "white",
"black", "black",
"gray", 0, 0, 0, 1, 1, 1, "null", "null", ,], ["For Content
Publishers",
"http://www.melonfire.com/services/content.html", 1, 0, 0],
["For Small
Businesses", "http://www.melonfire.com/services/sbs.html", 1,
0, 0] ];
HM_Array1_2 = [ [180, 200, 50, "black", "white", "white",
"black", "black",
"gray", 0, 0, 0, 1, 1, 1, "null", "null", ,], ["Background",
"http://www.melonfire.com/company/background.html", 1, 0, 0],
["Clients",
"http://www.melonfire.com/company/clients.html", 1, 0, 0],
["Addresses",
"http://www.melonfire.com/company/addresses.html", 1, 0, 0],["Jobs",
"http://www.melonfire.com/company/jobs.html", 1, 0, 0],
["News",
"http://www.melonfire.com/company/news.php3", 1, 0, 0] ];
HM_Array1_3 = [ [180, 200, 50, "black", "white", "white",
"black", "black",
"gray", 0, 0, 0, 1, 1, 1, "null", "null", ,], ["Press
Releases",
"http://www.melonfire.com/mcenter/pr.html", 1, 0, 0], ["Media
Kit","http://www.melonfire.com/mcenter/mkit.html", 1, 0, 0] ];
HM_Array1_4 = [ [180, 200, 50, "black", "white", "white",
"black", "black",
"gray", 0, 0, 0, 1, 1, 1, "null", "null", ,], ["Log In",
"http://www.melonfire.com/account/index.html", 1, 0, 0] ];
HM_Array1_5 = [ [180, 200, 50, "black", "white", "white",
"black", "black",
Building an Extensible Menu Class
Reaching Higher 22
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
25/33
"gray", 0, 0, 0, 1, 1, 1, "null", "null", ,], ["Columns",
"http://www.melonfire.com/community/columns/", 1, 0, 1] ];
HM_Array1_5_1 = [ [180, 200, 50, "black", "white", "white",
"black",
"black", "gray", 0, 0, 0, 1, 1, 1, "null", "null", ,],
["Colophon",
"http://www.melonfire.com/community/columns/colophon/", 1, 0,
0], ["Cut",
"http://www.melonfire.com/community/columns/cut/", 1, 0, 0],
["Boombox",
"http://www.melonfire.com/community/columns/boombox/", 1, 0,
0], ["The HITG
Report", "http://www.melonfire.com/community/columns/thr/", 1,
0, 0],
["Trog", "http://www.melonfire.com/community/columns/trog/",
1, 0, 0] ];
The downside here is obvious each time I want to change the menu structure, I have to go into the
JavaScript source and muck about with the arrays (which aren't exactly all that userfriendly to begin with.)
What I would prefer to do, however, is somehow interface my database table to the HIERmenus system, so
that updating the menu becomes as simple as executing an SQL query to change the relationships in the
mySQL table.
With the help of some clever PHP code and the Menu object I've just built, this becomes not just possible, but
a snap to accomplish. The first step is to alter the HIERmenus scripts to reference a PHP file for the arrays,
rather than a JavaScript file simply alter the reference to "HM_Arrays.js" in the file "HM_Loader.js" to
"HM_Arrays.js.php", as below.
if(HM_IsMenu) {
document.write("");
document.write("");
}
Next, create the script "HM_Arrays.js.php", and populate it with the following PHP code:
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
26/33
\"white\",
\"black\", \"black\", \"gray\", 0, 0, 0, 1, 1, 1, \"null\",
\"null\", ,";
// create object
include("menu.class.php");
$obj = new Menu;
// run recursive function
buildMenu(0, "HM_Array1");
// this is a recursive function to generate
// the JS arrays needed by HIERmenus
// this function accepts an id (used to generate children)
// and a prefix string (attached to every array name, needed
by HIERmenus)
// for more information on how this works and syntax,
// refer to HIERmenus documentation
function buildMenu($id, $prefix)
{
// obtain a reference to the Menu object
// and also source the options
global $obj;
global $HM_Menu_Options;
// get children of this node$children = $obj>get_children($id);
// create a JS array with the correct name
$array_str = $prefix . " = [ [" . $HM_Menu_Options . "]";
// iterate through child nodes and create individual array
elements
for ($x=0; $xget_type($children[$x]['id'])
. "]";
// if a child node has further children,
// recurse with appropriate modification to the prefix
if($obj>get_type($children[$x]['id']) == 1)
{
$temp = $prefix . "_" . ($x+1);
Building an Extensible Menu Class
Reaching Higher 24
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
27/33
buildMenu($children[$x]['id'], $temp);
}
// add the final list of array elements to the main array
$array_str .= $array_elements_str;
}
// close the JS array
$array_str .= " ];";
// and print it
print $array_str;
}
?>
The end result of all this processing: a set of JavaScript arrays containing the various menu nodes, in a formatwhich is acceptable to HIERmenus. This is accomplished by means of a recursive function (conceptually
identical to the one used in the print_menu_tree() method) which takes care of iterating through the various
levels of the menu tree and printing arrays in the format required by HIERmenus.
Now all we need is a HTML page which activates the HIERmenus system and displays the menu tree in all its
glory.
if(window.event + "" == "undefined") event = null;
function HM_f_PopUp(){return false};
function HM_f_PopDown(){return false};
popUp = HM_f_PopUp;
popDown = HM_f_PopDown;
//>
Roll your mouse over this
link to see a
menu
Building an Extensible Menu Class
Reaching Higher 25
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
28/33
And here's what it looks like:
Don't worry too much about the JavaScript code in this example it is merely standard code required for
HIERmenus to work, and is clearly documented by the developers of the system. The important thing to note
here is that we've taken a pure clientside application and successfully connected it to a serverside database
using standard method calls within the Menu object.
Of course, this solution may not be ideal in every case. Using a database and a PHP script to generate the
JavaScript arrays dynamically (rather than storing and using arrays from static JavaScript files) may degrade
performance; however, it does offer a benefit from the point of view of simpler maintenance of menu treerelationships. It's much easier to alter relationships in a mySQL table than it is to open up a JavaScript file and
edit the information in it; a nontechnical person can easily accomplish the former, but may have difficulty
with the latter. Consequently, a thorough costbenefit analysis should be performed before making a decision
as to which option is best suited to a specific case.
Building an Extensible Menu Class
Reaching Higher 26
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
29/33
Collapsing Inwards
If you go back a few pages, you'll notice that one of the design goals of this Menu object was to separate the
visual presentation of a menu from the relationships between the various nodes. I've already demonstrated
how the same Menu object can be used to create a directory and a hierarchical menu tree with standard
methods.
My third example is similar to the second, again connecting a JavaScriptbased menu system to the menu
database to dynamically build a menu tree. For this, I plan to use another very popular menu constructor,
FolderTree (free version available at http://www.geocities.com/marcelino_martins/foldertree.html ), which
uses Windows Explorerstyle files and folders to display a hierarchy of items.
First, I need an HTML page to invoke FolderTree and display the menu:
tree >
initializeDocument()
As you can see, this file sources "menu.js.php", which contains the actual menu data. This file is usually
created manually as per the user's requirements; I plan to hook it up to my database table to generate it
dynamically. Here's the code:
// menu.js.php
// set up tree root
Collapsing Inwards 27
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
30/33
foldersTree = gFld("Melonfire", "http://www.melonfire.com");
Building an Extensible Menu Class
Collapsing Inwards 28
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
31/33
You just gotta love those recursive functions!
Here's what it all looks like:
Building an Extensible Menu Class
Collapsing Inwards 29
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
32/33
Extending Yourself
All the examples you've seen thus far have used the same standard API defined within the Menu object.
However, this assumes one important thing that a database table (in the format described) has already been
created and populated with menu records. In case this is an unreasonable assumption for your specific
requirements, you might consider adding a few method calls to add and delete nodes respectively.
7/30/2019 [Developer Shed Network] Server Side - PHP - Bulding an Extensible Menu Class
33/33
FolderTree 2.0. HIERmenus and FolderTree copyright their respective authors. Examples are illustrative only,
and are not meant for a production environment. YMMV!
Building an Extensible Menu Class