• Stars
    star
    157
  • Rank 238,399 (Top 5 %)
  • Language
    PHP
  • License
    BSD 3-Clause "New...
  • Created over 13 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

AR models behavior that allows to work with nested sets tree.

Nested Set

Nested Set behavior for Yii 2: https://github.com/creocoder/yii2-nested-sets

This extension allows managing trees stored in database as nested sets. It's implemented as Active Record behavior.

Installing and configuring

First you need to configure model as follows:

public function behaviors()
{
    return array(
        'nestedSetBehavior'=>array(
            'class'=>'ext.yiiext.behaviors.model.trees.NestedSetBehavior',
            'leftAttribute'=>'lft',
            'rightAttribute'=>'rgt',
            'levelAttribute'=>'level',
        ),
    );
}

There is no need to validate fields specified in leftAttribute, rightAttribute, rootAttribute and levelAttribute options. Moreover, there could be problems if there are validation rules for these. Please check if there are no rules for fields mentioned in model's rules() method.

In case of storing a single tree per database, DB structure can be built with extensions/yiiext/behaviors/trees/schema.sql. If you're going to store multiple trees you'll need extensions/yiiext/behaviors/trees/schema_many_roots.sql.

By default leftAttribute, rightAttribute and levelAttribute values are matching field names in default DB schemas so you can skip configuring these.

There are two ways this behavior can work: one tree per table and multiple trees per table. The mode is selected based on the value of hasManyRoots option that is false by default meaning single tree mode. In multiple trees mode you can set rootAttribute option to match existing field in the table storing the tree.

Selecting from a tree

In the following we'll use an example model Category with the following in its DB:

- 1. Mobile phones
	- 2. iPhone
	- 3. Samsung
		- 4. X100
		- 5. C200
	- 6. Motorola
- 7. Cars
	- 8. Audi
	- 9. Ford
	- 10. Mercedes

In this example we have two trees. Tree roots are ones with ID=1 and ID=7.

Getting all roots

Using NestedSetBehavior::roots():

$roots=Category::model()->roots()->findAll();

Result:

Array of Active Record objects corresponding to Mobile phones and Cars nodes.

Getting all descendants of a node

Using NestedSetBehavior::descendants():

$category=Category::model()->findByPk(1);
$descendants=$category->descendants()->findAll();

Result:

Array of Active Record objects corresponding to iPhone, Samsung, X100, C200 and Motorola.

Getting all children of a node

Using NestedSetBehavior::children():

$category=Category::model()->findByPk(1);
$descendants=$category->children()->findAll();

Result:

Array of Active Record objects corresponding to iPhone, Samsung and Motorola.

Getting all ancestors of a node

Using NestedSetBehavior::ancestors():

$category=Category::model()->findByPk(5);
$ancestors=$category->ancestors()->findAll();

Result:

Array of Active Record objects corresponding to Samsung and Mobile phones.

Getting parent of a node

Using NestedSetBehavior::parent():

$category=Category::model()->findByPk(9);
$parent=$category->parent()->find();

Result:

Array of Active Record objects corresponding to Cars.

Getting node siblings

Using NestedSetBehavior::prev() or NestedSetBehavior::next():

$category=Category::model()->findByPk(9);
$nextSibling=$category->next()->find();

Result:

Array of Active Record objects corresponding to Mercedes.

Getting the whole tree

You can get the whole tree using standard AR methods like the following.

For single tree per table:

Category::model()->findAll(array('order'=>'lft'));

For multiple trees per table:

Category::model()->findAll(array('condition'=>'root=?','order'=>'lft'),array($root_id));

Modifying a tree

In this section we'll build a tree like the one used in the previous section.

Creating root nodes

You can create a root node using NestedSetBehavior::saveNode(). In a single tree per table mode you can create only one root node. If you'll attempt to create more there will be CException thrown.

$root=new Category;
$root->title='Mobile Phones';
$root->saveNode();
$root=new Category;
$root->title='Cars';
$root->saveNode();

Result:

- 1. Mobile Phones
- 2. Cars

Adding child nodes

There are multiple methods allowing you adding child nodes. To get more info about these refer to API. Let's use these to add nodes to the tree we have:

$category1=new Category;
$category1->title='Ford';
$category2=new Category;
$category2->title='Mercedes';
$category3=new Category;
$category3->title='Audi';
$root=Category::model()->findByPk(1);
$category1->appendTo($root);
$category2->insertAfter($category1);
$category3->insertBefore($category1);

Result:

- 1. Mobile phones
	- 3. Audi
	- 4. Ford
	- 5. Mercedes
- 2. Cars

Logically the tree above doesn't looks correct. We'll fix it later.

$category1=new Category;
$category1->title='Samsung';
$category2=new Category;
$category2->title='Motorola';
$category3=new Category;
$category3->title='iPhone';
$root=Category::model()->findByPk(2);
$category1->appendTo($root);
$category2->insertAfter($category1);
$category3->prependTo($root);

Result:

- 1. Mobile phones
	- 3. Audi
	- 4. Ford
	- 5. Mercedes
- 2. Cars
	- 6. iPhone
	- 7. Samsung
	- 8. Motorola
$category1=new Category;
$category1->title='X100';
$category2=new Category;
$category2->title='C200';
$node=Category::model()->findByPk(3);
$category1->appendTo($node);
$category2->prependTo($node);

Result:

- 1. Mobile phones
	- 3. Audi
		- 9. Π‘200
		- 10. X100
	- 4. Ford
	- 5. Mercedes
- 2. Cars
	- 6. iPhone
	- 7. Samsung
	- 8. Motorola

Modifying a tree

In this section we'll finally make our tree logical.

Tree modification methods

There are several methods allowing you to modify a tree. To get more info about these refer to API.

Let's start:

// move phones to the proper place
$x100=Category::model()->findByPk(10);
$c200=Category::model()->findByPk(9);
$samsung=Category::model()->findByPk(7);
$x100->moveAsFirst($samsung);
$c200->moveBefore($x100);
// now move all Samsung phones branch
$mobile_phones=Category::model()->findByPk(1);
$samsung->moveAsFirst($mobile_phones);
// move the rest of phone models
$iphone=Category::model()->findByPk(6);
$iphone->moveAsFirst($mobile_phones);
$motorola=Category::model()->findByPk(8);
$motorola->moveAfter($samsung);
// move car models to appropriate place
$cars=Category::model()->findByPk(2);
$audi=Category::model()->findByPk(3);
$ford=Category::model()->findByPk(4);
$mercedes=Category::model()->findByPk(5);

foreach(array($audi,$ford,$mercedes) as $category)
    $category->moveAsLast($cars);

Result:

- 1. Mobile phones
	- 6. iPhone
	- 7. Samsung
		- 10. X100
		- 9. Π‘200
	- 8. Motorola
- 2. Cars
	- 3. Audi
	- 4. Ford
	- 5. Mercedes

Moving a node making it a new root

There is a special moveAsRoot() method that allows moving a node and making it a new root. All descendants are moved as well in this case.

Example:

$node=Category::model()->findByPk(10);
$node->moveAsRoot();

Identifying node type

There are three methods to get node type: isRoot(), isLeaf(), isDescendantOf().

Example:

$root=Category::model()->findByPk(1);
CVarDumper::dump($root->isRoot()); //true;
CVarDumper::dump($root->isLeaf()); //false;
$node=Category::model()->findByPk(9);
CVarDumper::dump($node->isDescendantOf($root)); //true;
CVarDumper::dump($node->isRoot()); //false;
CVarDumper::dump($node->isLeaf()); //true;
$samsung=Category::model()->findByPk(7);
CVarDumper::dump($node->isDescendantOf($samsung)); //true;

Useful code

Non-recursive tree traversal

$criteria=new CDbCriteria;
$criteria->order='t.lft'; // or 't.root, t.lft' for multiple trees
$categories=Category::model()->findAll($criteria);
$level=0;

foreach($categories as $n=>$category)
{
	if($category->level==$level)
		echo CHtml::closeTag('li')."\n";
	else if($category->level>$level)
		echo CHtml::openTag('ul')."\n";
	else
	{
		echo CHtml::closeTag('li')."\n";

		for($i=$level-$category->level;$i;$i--)
		{
			echo CHtml::closeTag('ul')."\n";
			echo CHtml::closeTag('li')."\n";
		}
	}

	echo CHtml::openTag('li');
	echo CHtml::encode($category->title);
	$level=$category->level;
}

for($i=$level;$i;$i--)
{
	echo CHtml::closeTag('li')."\n";
	echo CHtml::closeTag('ul')."\n";
}

More Repositories

1

imperavi-redactor-widget

Imperavi Redactor WYSIWYG widget (OEM-licensed for Yii)
JavaScript
406
star
2

with-related-behavior

Allows to manage related records
PHP
100
star
3

activerecord-relation-behavior

Inspired by and put together the awesomeness of many yii extensions that aim to improve saving of related records. Comes with 100% test coverage and well structured and clean code so it can savely be used in enterprise production enviroment.
PHP
92
star
4

shopping-cart-component

Allows to put models into shopping cart and do various operations with it.
PHP
80
star
5

twig-renderer

Allows to use Twig template engine in Yii framework views
PHP
70
star
6

smarty-renderer

This extension allows you to use Smarty 3 templates in Yii.
PHP
50
star
7

taggable-behavior

Provides many useful methods and named scopes to work with model tags.
PHP
37
star
8

github-api

implementation of github api v3
PHP
36
star
9

migrate-command

This is an enhanced version of the Yii Database Migration Tool that adds module support and many more usefull features.
PHP
35
star
10

comment-module

Module that adds comments to your application. You can add comments on any AR Model you like.
PHP
29
star
11

yii

This is a read-only mirror of the yiiframework svn repository. It is updated by a jenkins-ci job every 20 minutes. IMPORTANT NOTE: Yii is on github now: https://github.com/yiisoft/yii fork their repo instead of this, will keep this thing up for a while but not sure how long...
PHP
29
star
12

eav-behavior

Implements entity-attribute-value pattern.
PHP
24
star
13

yii2-yii-bridge

Yii bridge between v1.1.x and v2.0
PHP
23
star
14

file-upload-action

Action for file uploads handling.
PHP
21
star
15

trash-bin-behavior

AR models behavior that allows to mark models as deleted and then restore them.
PHP
19
star
16

yiiext.github.com

github pages for yiiext
CSS
17
star
17

webshell-module

A web shell that allows to run yiic commands and create your own commands.
JavaScript
16
star
18

ratchetio-component

This component is the way to integrate ratchet.io service with your Yii app.
PHP
15
star
19

core

the development yii application for all yiiext extensions
PHP
13
star
20

image-component

Image processing with Imagine.
PHP
13
star
21

fancybox-widget

Wrapper around fancybox.
JavaScript
12
star
22

uploadify-widget

Allows to use jQuery uploadify plugin as a widget.
JavaScript
11
star
23

status-behavior

Provides methods and named scopes to work with model statuses.
PHP
11
star
24

chart

A set of charting widgets
PHP
11
star
25

slug-behavior

PHP
10
star
26

transliterator-component

PHP
9
star
27

pdf

Extension for PDF management
PHP
8
star
28

mobile-detect-component

Mobile devices detecting with Mobile_Detect.
PHP
6
star
29

ckeditor-widget

This extension allows to add CKEditor in a view.
PHP
5
star
30

form-component

Automated form generator.
PHP
5
star
31

zend-autoloader-component

Fast autoloader for Zend Framework classes.
PHP
5
star
32

markitup-widget

Allows to use markItUp as a widget.
JavaScript
5
star
33

filesystem-component

PHP
5
star
34

lipsum-widget

Lorem Ipsum placeholder text generator
PHP
4
star
35

zii-image-column

allows to render images inside zii CGridView.
PHP
4
star
36

commentable-behavior

PHP
3
star
37

simplemodal-widget

Wrapper around SimpleModal jQuery plugin.
JavaScript
3
star
38

set-return-url-filter

Extends default Yii returnUrl functionality.
PHP
3
star
39

blueprint-widget

A way to inject blueprint CSS framework into the page.
PHP
3
star
40

active-data-provider

PHP
3
star
41

get-url-behavior

Helps getting resource URLs.
PHP
3
star
42

phpdoc-component

Allows reading phpDoc.
PHP
3
star
43

swf-object-widget

embedding Adobe Flash Player content using SWFObject 2
JavaScript
3
star
44

shorturl-component

This extensions allows you to short url by the http://goo.gl service.
PHP
2
star
45

iconized-menu-widget

Menu with favicons for each item.
PHP
2
star
46

breadcrumbs-component

displays a list of links indicating the position of the current page in the whole website.
PHP
2
star
47

ensure-null-behavior

Forces NULL to be used instead of empty varchar.
PHP
2
star
48

extension-template

YiiExt extension template
2
star
49

forgery-session-filter

Automatically loads session specified via PHP_SESSION_ID.
PHP
2
star
50

active-form-validation-filter

Automated validation filter for CActiveForm.
PHP
2
star
51

menu-widget

PHP
1
star
52

yii-more-pager

PHP
1
star
53

dwoo-renderer

This extension allows you to use Dwoo templates in Yii.
PHP
1
star
54

cycle-widget

wraps jquery.cycle.js
JavaScript
1
star
55

quicky-renderer

This extension allows you to use Quicky templates in Yii.
PHP
1
star
56

last-value-behavior

PHP
1
star
57

chm-component

generate .chm files from html
PHP
1
star
58

adjacency-list-behavior

Adjacency list behavior
1
star
59

image-validator-component

Validatior for images, validates width, height, mime type, file size, extension
PHP
1
star
60

elfinder-widget

Helps integrating http://elrte.org/elfinder filemanager with WYSIWYG
PHP
1
star
61

multilang

Yii Components to create multi-language applications
1
star
62

tinybutstrong-renderer

Allows using tinybutstrong template engine in Yii-based projects
1
star
63

reversed-pagination

Provides the ability to create 9 to 1 navigation as bash.org.ru
PHP
1
star