Part of the EllisLab Network
   
1 of 2
1
Nested Set library (aka MPTT, aka Hierarchy DB Trees)
Posted: 01 October 2008 12:58 AM   [ Ignore ]  
Grad Student
Avatar
Rank
Total Posts:  68
Joined  08-03-2007

Hey everyone. Last year I found Thunder’s Nested Set class, implemented as a model.
Thunder’s original class was great, but there were a few things I felt were lacking.

Thunder’s Nested Set thread

Some basic info before proceeding:
- This class implements Joe Celko’s Nested Set data model, also known as MPTT or Modified Preorder Tree Traversal.
- Nested Sets are great for storing hierarchical data in a database.
- This data model is a better alternative to the Adjacency List model.

Changes:

* Now implemented as a Library as opposed to Model (but could easily be converted back if needed)
* PHP 4 support dropped
* CI db class & active record used as extensively as possible, replacing ALL manual SQL queries
* Table prefixes now supported
* Code cleanup (i.e. - single quotes now replace double quotes when possible)
* Added support for a “parent” column (i.e. - parent_id), enables a DBA to easily
  see which child values belong to which parent values, gives ability to speedily
  request immediate children only, etc. (plans in the future to expand on this)
* Multiple root nodes now supported. The original class assumed only 1 root node
  existed in a table, now multiple roots can exist (or you can view the table itself
  as the root node, with multiple direct children allowed)

Attempts were made to keep this class compatible with Thunder’s original class,
and it is compatible in almost every way, EXCEPT for the following:

- getRoot no longer exists, now getRootNodes is required, which returns an array of nodes
- parent column is now expected to exist, default name is “parent_id”, type should be integer

The library is attached to this post.

Example DB structure:

CREATE TABLE `nested_set_tree` (
  `
id` int(10) unsigned NOT NULL auto_increment,
  `
lft` int(10) unsigned NOT NULL default '0',
  `
rgt` int(10) unsigned NOT NULL default '0',
  `
parent_id` int(10) unsigned NOT NULL default '0',
  
PRIMARY KEY  (`id`),
  
KEY `lft` (`lft`),
  
KEY `rgt` (`rgt`),
  
KEY `parent_id` (`parent_id`)
)
ENGINE=MyISAM;

Example basic PHP usage:

<?php
class Example {
    public
function __construct() {
        
        $this
->load->library('nested_set');
        
        
# If you are using nested_set in multiple locations, it's best to create a new instance
        
        # Using original instance
        
$this->nested_set->setControlParams('nested_set_tree');
        
        
# Using new instance
        
$this->new_nested_set = new Nested_set();
        
$this->new_nested_set->setControlParams('nested_set_tree2');
        
        
# Alternatively, you can use the original $this->nested_set for multiple tables,
        # but you must call setControlParams before each separate table use
         
        
$this->nested_set->setControlParams('nested_set_tree');
        
$root_nodes1 = $this->nested_set->getRootNodes();
         
        
$this->nested_set->setControlParams('nested_set_tree2');
        
$root_nodes2 = $this->nested_set->getRootNodes();
       
    
}
}
?>

I already have this class in use with Backend Pro. Had to modify Backend Pro of course, and also modified KHACL to use this class (as KHACL stores it’s data using nested sets, but was managing the data itself, instead of using a dedicated class).
Works great so far.

Let me know if you have any questions/comments.

File Attachments
Nested_set.zip  (File Size: 6KB - Downloads: 419)
 Signature 

PHP Site Solutions | Nested Set library for CI

Profile
 
 
Posted: 04 November 2008 12:10 PM   [ Ignore ]   [ # 1 ]  
Summer Student
Avatar
Total Posts:  29
Joined  09-14-2008

hello,

Have you updated this for 1.6/7?


anton

 Signature 

” ...the announcement of a vast project is always its betrayal” - Bataille

Profile
 
 
Posted: 10 November 2008 07:22 AM   [ Ignore ]   [ # 2 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  132
Joined  04-16-2007

There is a error at line 605:

public function getTreeNext($tree_handle) {

should be:

public function getTreeNext(&$tree_handle) {


...anyways, its seems to work well under 1.6/1.7.


There could probably be made some improvements. Additional helpers/methods.:

- Rendering out ol/ul of entire tree and/or sub-tree.
- Rendering out other types of important navigation elements, with easy steps. Ex. bredcrumbs etc.

 Signature 

EVERY TIME YOU ASK ABOUT CODEIGNITER 2.0… PHIL STURGEON KILLS A KITTEN

Profile
 
 
Posted: 10 November 2008 08:00 AM   [ Ignore ]   [ # 3 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  132
Joined  04-16-2007

Though.. the AR-statements should be updated, since some of them are deprecated.

 Signature 

EVERY TIME YOU ASK ABOUT CODEIGNITER 2.0… PHIL STURGEON KILLS A KITTEN

Profile
 
 
Posted: 10 November 2008 08:21 AM   [ Ignore ]   [ # 4 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  132
Joined  04-16-2007

There is also an error in function/method getSubTreeAsHTML, somewhere around line 691.

if(isset($nodes[0]) && !is_array($nodes[0])) {
            $nodes
= array($nodes);
        
}

Should be:

if(isset($nodes[0]) && !is_array($nodes[0])) {
            $nodes
= array($this->getNodeFromId($nodes));
        
}
 Signature 

EVERY TIME YOU ASK ABOUT CODEIGNITER 2.0… PHIL STURGEON KILLS A KITTEN

Profile
 
 
Posted: 10 November 2008 09:03 AM   [ Ignore ]   [ # 5 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  132
Joined  04-16-2007

Actually.. here is quite a few errors, If im not mistaken.

 Signature 

EVERY TIME YOU ASK ABOUT CODEIGNITER 2.0… PHIL STURGEON KILLS A KITTEN

Profile
 
 
Posted: 10 February 2009 05:17 PM   [ Ignore ]   [ # 6 ]  
Grad Student
Rank
Total Posts:  40
Joined  02-10-2009

Hi. I think this seems promising (as well as CodeIgniter itself). (Also thanks to Thunder for the first contribution)

I have one issue though: how to generate a valid unordered list/navigation menu. It’s probably similar to this:

public function getSubTreeAsHTML($nodes, $fields = array()) {
        
if(isset($nodes[0]) && !is_array($nodes[0])) {
            $nodes
= array($nodes);
        
}
    
        $retVal
= '';
    
        foreach(
$nodes AS $node) {
    
            $tree_handle
= $this->getTreePreorder($node);
        
            while(
$this->getTreeNext($tree_handle))
            
{
                
// print indentation
                
$retVal .= (str_repeat('&nbsp;', $this->getTreeLevel($tree_handle)*4));

                
// print requested fields
                
$field = reset($fields);
                while(
$field){
                    $retVal
.= $tree_handle['row'][$field] . "\n";
                    
$field = next($fields);
                
}
                $retVal
.= "<br />\n";

            
}
        }

        
return $retVal;
    
}

But other than that, I’m confused, so I would really appreciate any help!

Thanks,

Asylmottaket

 Signature 

I’m Luke Skywalker. I’m here to rescue you.

Profile
 
 
Posted: 13 February 2009 11:08 AM   [ Ignore ]   [ # 7 ]  
Grad Student
Avatar
Rank
Total Posts:  68
Joined  08-03-2007

I’m working with this class outside of CI, and I’m cleaning up any issues I find as I go along.
I’ll be posting back an updated version in a week or so.

Cheers

 Signature 

PHP Site Solutions | Nested Set library for CI

Profile
 
 
Posted: 26 June 2009 02:05 PM   [ Ignore ]   [ # 8 ]  
Summer Student
Total Posts:  12
Joined  06-05-2007

Hello Jon,
I was wondering if you had made any additional progress with this?


Regards,
Todd M. Kimball

Profile
 
 
Posted: 02 October 2009 08:35 AM   [ Ignore ]   [ # 9 ]  
Summer Student
Total Posts:  10
Joined  09-24-2009

Why did you convert it to a library? I think a model is much easier, or not? I mean, if I create a model for nested categories,

class Cat extends Model
, I tend to copy many methods of the nested set library that use the (same) methods in the library. E.g. concerning creation and moving of nodes. If the nested set library was actually a model, I could do
class Cat extends Nested_Set

, and I get many admin methods “for free”. I don’t see benefits of library, why did you make that choice?

Profile
 
 
Posted: 02 October 2009 10:46 AM   [ Ignore ]   [ # 10 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  132
Joined  04-16-2007

Hi Dirkpostma.

I have been thinking about the same thing, to switch it back to a model.

And add some extra query methods, also serve along a extension class to deal with recursion and general generation of navigation lists, dropdowns, breadcrumbs etc. Here I have already started.

I think this library is a good place to start.. but it has to be further developed.

Would you do the honour of making it into a model again?

 Signature 

EVERY TIME YOU ASK ABOUT CODEIGNITER 2.0… PHIL STURGEON KILLS A KITTEN

Profile
 
 
   
1 of 2
1
 
Post Marker Legend
New Topic New posts Hot Topic Hot Topic with new posts New Poll New Poll Moved Topic Moved Topic Sticky Topic Sticky topic
Old Topic No new posts Hot Old Topic Hot Topic with no new posts Old Poll Old Poll Closed Topic Closed Topic Announcement Announcements
Theme
Change Theme
Visitor Statistics
The most visitors ever was 819, on March 11, 2010 11:15 AM
Total Registered Members: 120258 Total Logged-in Users: 35
Total Topics: 126394 Total Anonymous Users: 5
Total Replies: 664713 Total Guests: 334
Total Posts: 791107    
Members ( View Memberlist )