[EXTENSION] Nested Set implementation using ActiveRecord

The extension is an implementation 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.

Please let me know what you think! It’s my first contribution to a open project like this, so please be kind. :)

More information: http://www.yiiframew…sion/nestedset/

I've been wanting to write such an extension but haven't had the time. It looks good. One thing you might want to consider adding is a 'scope' column. It would allow to create multiple trees in one table. Say you store navigation menus in your table, this would mean you can have more than one hierarchy. Another thing is that having this as a behaviour instead of extending AR is more flexible (e.g. more than one behaviour so you can versionify and treeify a table etc)  albeit a little more complicated.

Don't feel obliged in any way to add this though, just a suggestion. I like how you use the 'level' column, I used a parent_id column for for this but this is more flexible.

Thanks for your reply!

The scope column looks like a nice addition, I will look into that but I want to keep it backwards compatible with this version (without the scope) and I'm not yet sure how to achieve that.

Second, I'm don't really understand what you mean with "behaviours"? I've never created a website with Yii before (I needed this functionality first), and I didn't find anything on it in the documentation.

Behaviours are a way to sort of do multiple inheritance in php. It is discussed in the documentation. Basically you tell the model in this case that it has the behaviour ‘nested sets’ and then Yii (virtually) adds some methods to the model such as findChildren(). This is done through the __call() method. You can also attach a behaviour to an event, so onbeforeSave() do this and that, say set the right timestamp. Such a behaviour can then be applied to multiple models.

See http://www.yiiframew…oc/cookbook/14/ for an example of a behaviour.

Quote

Behaviours are a way to sort of do multiple inheritance in php. It is discussed in the documentation. Basically you tell the model in this case that it has the behaviour 'nested sets' and then Yii (virtually) adds some methods to the model such as findChildren(). This is done through the __call() method. You can also attach a behaviour to an event, so onbeforeSave() do this and that, say set the right timestamp. Such a behaviour can then be applied to multiple models.

See http://www.yiiframew…oc/cookbook/14/ for an example of a behaviour.

Thanks! I will look into that!

Quote

The extension is an implementation 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.

Please let me know what you think! It’s my first contribution to a open project like this, so please be kind. :)

More information: http://www.yiiframew…sion/nestedset/

First of all, thanks for sharing this great extension, it enhances yii in terms of dealing with nestedset data structure.

However, when I tried the example comes with the source, I got some issue, everything is the same as example, I only changed the table name from 'Tree' to 'Category'.

In controller:

Instead of getting

I got this:

Any idea?

I might have an idea, but do not have the time to fix this until sunday afternoon (West-European Time). I think it can be fixed with using $root->refresh() before using appendNode() the second time. (the lft/rgt values are updated in the database, but not yet in the object representation)

I've uploaded a new version.

It's now based on behaviors (as suggested) and it dynamically updates all open tree objects when you modify the structure of your tree (without database operations). This way you don't have to refresh your ActiveRecord objects after every tree modification.

I also added an example file which can also as test suite so I can check that every operation is working as it should. I also found some small bugs in the move**() methods which are now gone.

Enjoy!

Great, I love it.

Quote

I've uploaded a new version.

It's now based on behaviors (as suggested) and it dynamically updates all open tree objects when you modify the structure of your tree (without database operations). This way you don't have to refresh your ActiveRecord objects after every tree modification.

I also added an example file which can also as test suite so I can check that every operation is working as it should. I also found some small bugs in the move**() methods which are now gone.

Enjoy!

Great work!

The bug is gone, and I prefer the behaviors too.

Thank you very much - it really helps during development!

I found a little confusing mistake in the documentation:

And got a suggestion about moveUp() method. When an object checks either it's parent is root or not:

I think the “name” field is not necessary… but we can consider that the root node always has an id less than 1… Correct me if I’am wrong :)

Darmen

Quote

Thank you very much - it really helps during development!

I found a little confusing mistake in the documentation:

And got a suggestion about moveUp() method. When an object checks either it's parent is root or not:

I don't understand what you mean? Can you give a suggestion how to improve it?

Quote

I think the "name" field is not necessary... but we can consider that the root node always has an id less than 1... Correct me if I'am wrong :)

When we add support for scopes (as suggested in this topic), it might not be true in every case that an ID of less than one is always the root node, since multiple trees may be stored in the table. It would be better to check if the "lft" value of the node is equal to zero, which will always hold when it is a root node (even with scopes). I will add this in the next release, but I do not think it necessary to update the current version for this fix.

This is a great extension, but it’d be even better to have a jQuery powered widget comes with it, here is the jQuery plugin I found that could be a good start point http://www.jstree.com/

hi i find 2 error:

1 example file SiteController.php have 2 function nested.

	public function actionIndex()


	{


		public function actionIndex()


    	{

2 when i delete one function, web have php error.



Undefined index: children


00111:         $result = "<strong>".$tree['node']->name."</strong> (".$tree['node']->getLeftValue().",".$tree['node']->getRightValue().")";


00112:         if(is_array($tree['children']))


Yes multpiple trees would be awsome like in doctrine: http://www.doctrine-…:multiple-trees

I have a foreign key (user_id) in the mptt table… only it throws an error:


 Error in executing SQL: INSERT INTO `pages` (`title`, `user_id`, `lft`,

`rght`, `level`, `modified`, `created`) VALUES (:yp0, :yp1, :yp2, :yp3,

:yp4, :yp5, :yp6)


Error appending node, transaction aborted. Exception: CDbCommand failed to

execute the SQL statement: SQLSTATE[23000]: Integrity constraint violation:

1452 Cannot add or update a child row: a foreign key constraint fails

(`yii_cms`.`pages`, CONSTRAINT `fk_pages_users` FOREIGN KEY (`user_id`)

REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION)

Does anybody know what could be wrong?

Great extension, but will there be any new version, or have you stopped developing it?

nestedset can support yii1.1 version?

Most of the functions work in 1.1beta, but i have an error when trying to use getNextSibling() and getPrevSibling():

00237: throw new CException(Yii::t(‘yii’,’{class} does not have a

method named “{name}”.’,

00238: array(’{class}’=>get_class($this), ‘{name}’=>$name))); 00239: }

00240: 00241: /** 00242: * Returns the named behavior object. 00243: *

The name ‘asa’ stands for ‘as a’. 00244: * @param string the behavior

name 00245: * @return IBehavior the behavior object, or null if the

behavior does not exist 00246: * @since 1.0.2 00247: */ 00248: public

function asa($behavior) 00249: {

Seems like the model does not register this treebehavior the right way… have behaviors changed in 1.1?

Small addition:

please add the line

$criteria->order = $this->_lftCol." ASC";

to line 326 in TreeBehavior.php so Child Nodes get sorted when using getChildNodes() in your next release…

Nice work ! I am using this module in an productive Document Management System. Thank you so far!