How to create a PHP tree object using parent child notation

Posted by Mike Caisey on 20th August 2010

This is a quick guide for PHP coders to help in building things like menus for a website It encapsulates everything in a single object from one database query.


I've found it very useful in the past, it’s simple and I'm quite proud of it. If only for the fact that it has been the longest running useful code item in my personal arsenal.


It took me a while to get my head around the self-referencing functionality. And it could be argued that the implementation could be handled using arrays. I find using object notation nicer and cleaner and more in line with the direction of PHP 5.3


The key useful feature of this object is being able to identify the id for every ancestor all the way back to the root of the tree from any node. This is very useful for building menus especially as it allows you to highlight every menu item to root from the current page.


Another useful feature is being able to iterate over the tree from any node onwards. You query the root object using the id of a specific node and a section of the tree is returned as an object with child objects of the same class.


Below is an example database table of the basic information required to build a tree object:

 

Id

Parent Id

Data 1

Data 2

1

0

Home

Data1

2

0

Contact Us

Data2

3

0

About Us

Data3

4

0

Portfolio

Data4

5

1

Home Level 1

Data5

6

1

Home Level 1

Data6

7

2

Our Bristol Address

Data7

8

2

Our US Address

Data8

9

3

What we do

Data9

10

6

Home Level 2

Data10

11

6

Home Level 2

Data11

You'd query the database ordering by parent then id. This ensures there is always a parent node to add the next child node to.

 

The first/root node in the tree starts with zero

 

$parentId is the id of the parent node 0 and upwards to the highest node in the tree so far.

$id is the id of the node being created, used for internal reference when adding nodes and querying for them.

$data is any data of any type you want to add to the node.

 

Now if you queried for node 5:

The $node variable now contains the tree from node 5 onwards. Which, if the node was going to be used in a menu, would be very useful as you could now iterate from this node.

If you needed to query which nodes are ancestor to the current node:

This returns the array of hops showing the ids of all ancestors. You can then inspect the array in code to tell you, for example when building a menu, if this menu item is the ancestor to the current node.

I have resorted to using this object over Zend_Navigation from the Zend Framework. In their navigation you can omit the current page from the breadcrumb, as it could be deemed as superfluous. This then omits it from the menu you draw further down the screen. You can use the Tree object to quickly build a tree of the current menu and then iterate over it to build the menu.

You can download the object here

Update: The new version of the tree class is here. This version is an improvement on the previous one and implements the PHP ArrayIterator methods. Also in the tar file are the PHPUnit tests that work with it.


Comments

Thanks for sharing this! It will be very helpful to me. I'm trying to refactor some website navigation code and this class is just what I was looking for.

Can you explain why: calling findParent and findChildren would return the same thing?
Posted by Kevin on Mon, 21 Mar 2011 at 23:38
I'm really glad you're finding the code useful. I've got an updated version that implements the ArrayIterator methods.

I admit that there doesn't need to be three different functions that do the same thing but when I was try to understand the self referencing nested object model I couldn't decide on which function name to use.

I've subsequently updated the class and will post it here as an update.
Posted by Mike Caisey on Tue, 29 Mar 2011 at 09:30
I've hard time understand your script. You would make my night if you could help me out:
This code, gives me one subchild-rowset - but I dont get how i make it work in the infinity? I mean child's child an so on:

foreach ($tree as $node) {
echo $node->getData('title') . "-" . $node->getData('id') . "
";

if ($node->hasChildren()) {
foreach ($node->find($node->id) as $childNode) {
// Do something with the nodeChild like draw a menu item
echo "-" .$childNode->getData('title') . "
";
}
}

}
Posted by Nicklas on Tue, 13 Sep 2011 at 20:32
Nicklas,

I think what you should be looking at using is a recurring function.

I've created a sample example that does what I believe you want. You can view the code example here: https://gist.github.com/1214872.

Notice $this->printChild() is called on line 18 which is within the function itself.
Posted by Stuart Forster on Tue, 13 Sep 2011 at 20:44
привет
Posted by Dimyanshan on Sun, 08 Jan 2012 at 11:21
Children with disabilities
Posted by Qrgmrved on Wed, 25 Jan 2012 at 21:13

Have Your Say

Submit Comment