nestedset Nested Set implementation using the ActiveRecord paradigm.

  1. Documentation
  2. Change Log

This extension is an implentation of a Nested Set using the ActiveRecord method. At the moment, this extension only has an implementation using the "modified pre-order tree traversal algorithm" that can be found at this website. More information can also be found at the MySQL website about hierarchical storage.

The extension is implemented as a behavior so you can simply attach it to your own models.

This release may not be ready for production environments and (as every beta release) may need excessive testing. Please let me know if you find a bug or if you want to contribute.

Resources

Documentation

Requirements
  • Yii 1.0 or above
Installation
  • Extract the release file under protected/extensions
Usage
Step 1:

Before you start using it, you must set up a table in your database that can store hierarchical information. Using the "modified pre-order tree traversal algorithm" requires that table has some extra fields that allow us to store the structure of the tree. These columns are: ['id','lft','rgt','level']. Make sure that before you start modifying your tree, you you have one "root node" in your database. The node MUST have depth/level 0, and when it's the only node in the table, it has lft & right values of respectively 0 and 1.

I added a sql file as an example to the extension:

[sql]
CREATE TABLE IF NOT EXISTS `tree` (
  `id` int(11) NOT NULL auto_increment,
  `lft` int(11) NOT NULL,
  `rgt` int(11) NOT NULL,
  `level` int(11) NOT NULL,
  `name` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`id`),
  KEY `lft` (`lft`),
  KEY `rgt` (`rgt`),
  KEY `level` (`level`),
  KEY `name` (`name`)
) 

-- When using MySQL: add this:
-- ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

INSERT INTO `tree` (`id`, `lft`, `rgt`, `level`, `name`) VALUES
(1, 0, 1, 0, 'Root');
Step 2:

Now, we need to make sure the extension is loaded by Yii by adding it to your config file:

return array(
    //...
    'import'=>array(
		//...
		'application.extensions.nestedset.*'
	),
    //...
);
Step 3:

Your third task is to create a model that extends the CActiveTreeRecord class. This is pretty straightforward and works almost the same as the default CActiveRecord class. The only thing thati s different that you add the TreeBehavior to your model:

<?php

class Tree extends CActiveRecord
{
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }
    
    public function behaviors(){
        return array(
            'TreeBehavior' => array(
                'class' => 'application.extensions.nestedset.TreeBehavior'
            )
        );
    }
}

?>

When you use different column-names for your id/left/right/level columns, you can override the default names by setting the behavior parameters in your model:

public function behaviors(){
    return array(
        'TreeBehavior' => array(
            'class' => 'application.extensions.nestedset.TreeBehavior',
            '_idCol' => 'id',
            '_leftCol' => 'left',
            '_rightCol' => 'right',
            '_levelCol' => 'level',
        )
    );
}
Step 4:

When you have created your model, you are ready to use it in your controllers. See the example controller file for more tree manipulations.

$root = Tree::model()->findByPK(1);

$newNode = new Tree();
$newNode->name = "First Node";
$root->appendChild($newNode); //You do not have to use the "save" function here.

$newNode2 = new Tree();
$newNode2->name = "Second Node";
$root->appendChild($newNode2); //You do not have to use the "save" function here.

$newNode3 = new Tree();
$newNode3->name = "GrandChild Node";
$newNode->appendChild($newNode3); //You do not have to use the "save" function here.

// The structure looks like this:
//  * Root
//  -- * First Node
//  -- -- * GrandChild Node
//  -- * Second Node

// Let's do some modifications:
$newNode2->moveLeft();

// The structure now looks like this:
//  * Root
//  -- * Second Node
//  -- * First Node
//  -- -- * GrandChild Node

$newNode3->moveUp();

// And finally, the structure now looks like this:
//  * Root
//  -- * Second Node
//  -- * First Node
//  -- * GrandChild Node

Change Log

April 24, 2009
  • Initial beta release.
April 27, 2009
  • Changed implementation so it works like a behavior
  • Dynamically updates all open objects with the behavior attached so that you don't have to reload every object after manipulating your tree
  • Column names now configurable in the behavior settings array
  • Several minor bugfixes
  • Added more detailed example/test suite.
Januari 03, 2010 (v.0.4 - Quick maintenance release)
  • Fixed several bugs:
    • Moving subtrees sometimes created corrupted database.
    • Fixed bug in hasChildNodes function that delivered incorrect results
  • Now consistently throws exceptions when operating on an unsaved node.
  • In getNestedTree, you can opt to return the root node or not using the $returnrootnode parameter
  • Fixes "root" detection in moveUp()
  • getChildNodes() now returns a sorted list
  • Added debug traces to all methods
25 3
15 followers
3 135 downloads
Yii Version: 1.1
License: BSD-2-Clause
Category: Database
Tags:
Developed by: Remko Nolten
Created on: Apr 24, 2009
Last updated: 14 years ago

Downloads

show all