Yii Framework Forum: Nested set - Yii Framework Forum

Jump to content

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • 4
  • You cannot start a new topic
  • You cannot reply to this topic

Nested set Nested set behavior for AR models Rate Topic: ***** 4 Votes

#41 User is offline   lees 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 40
  • Joined: 04-May 11

Posted 18 July 2011 - 10:57 PM

How can I create a root nodes?

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


where is the Root Class?

Can you give a example? TKS~ :lol:
0

#42 User is offline   phtamas 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 529
  • Joined: 26-February 11
  • Location:Mezőtúr, Hungary

Posted 19 July 2011 - 01:19 PM

View Postlees, on 18 July 2011 - 10:57 PM, said:

How can I create a root nodes?

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


where is the Root Class?

Can you give a example? TKS~ :lol:



I think
$root=new Root

is a typo in the doc. It should be
$root=new Category



0

#43 User is offline   lees 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 40
  • Joined: 04-May 11

Posted 21 July 2011 - 07:46 PM

I was test use

$root=new Category


Is error~

thank you~~~ phtamas ::)
0

#44 User is offline   Spear 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 27
  • Joined: 02-February 09

Posted 03 September 2011 - 08:23 AM

Could you please help me get this clear — how exactly can I display the whole tree via CTreeView widget? What is the right way to get the whole tree, when three has many roots?
E.g I have list of categories, and I need to display the whole categories tree via CTreeView?
0

#45 User is offline   jacmoe 

  • Elite Member
  • Yii
  • Group: Moderators
  • Posts: 2,601
  • Joined: 10-October 10
  • Location:Denmark

Posted 03 September 2011 - 08:56 AM

May I suggest that you take a look at ejNestedTreeActions?
http://www.yiiframew..._20#entry112890
Be sure to grab it from Github, and then apply the fix for the latest nested set as written in the topic I just linked to.
"Less noise - more signal"
0

#46 User is offline   Spear 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 27
  • Joined: 02-February 09

Posted 03 September 2011 - 10:04 AM

Oh, I foud someone else's code and it was buggu, but turns out it just needs a little fix and it now works!
So, this should be added to NestedSetBehavior:
public function getTreeViewData($rootNodeId = null, $isReturnRootNode = true){
        $keyField = 'id';

        if ($rootNodeId == null)
            $rawTree = $this->getTreeWithoutManyRoots();
        else
            $rawTree = $this->getTreeWithManyRoots($rootNodeId);

        // Init variables needed for the array conversion
        $tree = array();
        $node =& $tree;
        $position = array();
        $lastitem = '';
        $depth = 1;

        foreach($rawTree as $rawItem){
            // If its a deeper item, then make it subitems of the current item
            if ($rawItem->getLevelValue() > $depth)
            {
                $position[] =& $node; //$lastitem;
                $depth = $rawItem->getLevelValue();
                $node =& $node[$lastitem]['children'];
            }
            // If its less deep item, then return to a level up
            else
            {
                while ($rawItem->getLevelValue() < $depth)
                {
                    end($position);
                    $node =& $position[key($position)];
                    array_pop($position);
                    $depth = $node[key($node)]['node']->getLevelValue();
                }
            }

            // Add the item to the final array
            $node[$rawItem->$keyField]['node'] = $rawItem;
            $node[$rawItem->$keyField]['id'] = (int) 'node'.$rawItem->owner->id;
            $node[$rawItem->$keyField]['text'] = (string) $rawItem->owner->name;
            // save the last items' name
            $lastitem = $rawItem->$keyField;
        }
        // we don't care about the root node
        if (!$isReturnRootNode){
            reset($tree);
            $tree = $tree[key($tree)]['children'];
            //array_shift($tree);
        }

        return $tree;
    }


    protected function getTreeWithoutManyRoots(){
        $owner=$this->getOwner();
        return $owner->findAll(array('order'=>$this->hasManyRoots
                           ?$this->rootAttribute . ', ' . $this->leftAttribute
                           :$this->leftAttribute));
    }


    protected function getTreeWithManyRoots($rootId){
        $owner=$this->getOwner();
        return $owner->findAll(
            array(
                 'condition' => $this->rootAttribute.'=:rootId',
                 'order'=>$this->leftAttribute,
                 'params' => array(':rootId'=>$rootId)
            ));
    }


    protected function hasChildNodes(){
        return $this->getLeftValue() != ($this->getRightValue() - 1);
    }

    protected function getLeftValue(){
        $fieldName = $this->leftAttribute;
        $owner=$this->getOwner();

        return $owner->$fieldName;
    }

    protected function getRightValue(){
        $fieldName = $this->rightAttribute;
        $owner=$this->getOwner();

        return $owner->$fieldName;
    }


    protected function getLevelValue(){
        $fieldName = $this->levelAttribute;
        $owner=$this->getOwner();

        return $owner->$fieldName;
    }


    protected function getRootValue(){
        $fieldName = $this->rootAttribute;
        $owner=$this->getOwner();

        return $owner->$fieldName;
    }

1

#47 User is offline   Tomas K. 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 17-January 11

Posted 22 September 2011 - 11:09 AM

I have just made simple method to get paths for node(s) as strings. Result is like: [PrimaryKey] => "Root • Node 1 • Node2 • Node 3" Maybe someone will found it useful.

/**
	 * Build the path to node(s)
	 * @param string $column name of model attribute column
	 * @param string $option accept all|leafs|branches|this
	 * @param bool $inclRoot include root to part
	 * @param string $separator path separator
	 * @return array list of paths
	 */
	public function paths($column, $option = 'this', $inclRoot = TRUE, $separator = ' • ') {
		$result = NULL;
		if ($option == 'this') {
			$path = NULL;
			foreach ($this->ancestors()->findAll(array('order' => $this->leftAttribute)) as $node) {
				$path[] = $node->attributes[$column];
			}
			if ($inclRoot) {
				$result[$node->primaryKey] = implode($separator, $path);
			} else {
				$result[$node->primaryKey] = implode($separator, array_slice($path, 1, count($path)));
			}
		} elseif (in_array ($option, array('all','branches','leafs'))) {
			$nodes = $this->findAll(array('order' => $this->leftAttribute));
			$actualLevel = 1;
			$aPath = array();
			foreach ($nodes as $k => $node) {
				$include = FALSE;
				if ($option == 'all') {
					$include = TRUE;
				} elseif ($option == 'branches' && !$node->isLeaf()) {
					$include = TRUE;
				} elseif ($option == 'leafs' && $node->isLeaf()) {
					$include = TRUE;
				}

				if ($node->{$this->levelAttribute} < $actualLevel) {
					$path = array_slice($path, 0, $node->{$this->levelAttribute} - 1);
				}
				$path[$node->{$this->levelAttribute}] = $node[$column];
				$actualLevel = $node->{$this->levelAttribute};

				if ($include) {
					if ($inclRoot) {
						$result[$node->primaryKey] = implode($separator, $path);
					} else {
						$result[$node->primaryKey] = implode($separator, array_slice($path, 1, count($path)));
					}
				}
			}
		}
		return $result;
	}

0

#48 User is offline   terrasoff 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 19
  • Joined: 17-July 11

Posted 25 September 2011 - 05:51 PM

really useful thing!
have tried to find swapNodes($node1,$node2) method, but unluckly :)
write to your to-do list, if you're planning to update you great-behavior!
0

#49 User is offline   R.K. 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 117
  • Joined: 20-September 10

Posted 21 December 2011 - 09:35 AM

Also will be nice to have copy of node function. thx.
0

#50 User is offline   nightmove 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 48
  • Joined: 11-March 12
  • Location:Germany

Posted 03 June 2012 - 05:07 PM

Hello,

can someone provide an sql statement thats fetches multiple trees with its hierachical data?

Cars
- Electro
-- automatic
-- manual
- Gas
Building
- Test1
- Test2

In need the complete structure, correctly sorted within the hierarchy. I just found sql statements for getting only one tree but I need all the trees.

thanks in advance :)
0

#51 User is offline   nightmove 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 48
  • Joined: 11-March 12
  • Location:Germany

Posted 04 June 2012 - 07:35 AM

Anyone got a solution?

I tried the following but did not solve it, as I dont know how to merge the trees :(

    	$roots=Category::model()->roots()->findAll();
    	foreach($roots as $root) {
        	$tree = Category::model()->findAll(
                	array(
                    	'condition'=>'root='.$root->id,
                    	'order'=>'lft'
                	)
        	);
    	}  

  	// I need to merge all the trees, but don't know how

  	$this->renderPartial(
            	'//partials/category/_gridViewCategory',
            	array(
                	'tree'=>$tree,
            	)
    	);

0

#52 User is offline   redguy 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 809
  • Joined: 02-July 10
  • Location:Central Poland

Posted 15 July 2012 - 09:05 AM

Hi,

I was thinking of using this extension but I have few questions about concepts made here. I am not very familiar with nested set using left-right-parent attributes (I did use pattern with extra table containing all relations), so my questions may be silly or my concepts are wrong. In such case simply point me such cases :)

1. Why not using events (beforeSave in this case) to apply specific functionalities and instead providing additional functions like 'saveNode'? I like extensions that do not need any modifications to standard approach when it is not really needed - this is the reason I ask about it. Is there *any* reason for this extra interface methods?

2. Why there is additional attribute 'root' that is used in multi-root scenario? why can't you just get roots by 'id_parent = NULL' or 'level = 0'?
red
0

#53 User is offline   redguy 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 809
  • Joined: 02-July 10
  • Location:Central Poland

Posted 20 July 2012 - 05:40 AM

ping...
red
0

#54 User is offline   samdark 

  • Having fun
  • Yii
  • Group: Yii Dev Team
  • Posts: 3,588
  • Joined: 17-January 09
  • Location:Russia

Posted 21 July 2012 - 06:30 AM

1. Yes, there is. It wasn't possible to proceed with standard API.
2. What is id_parent? If 10 trees are stored how to get tree #8?
Yii 1.1 Application Development Cookbook

Enjoying Yii? Star us at github: 1.1 and 2.0.
0

#55 User is offline   redguy 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 809
  • Joined: 02-July 10
  • Location:Central Poland

Posted 23 July 2012 - 01:09 AM

View Postsamdark, on 21 July 2012 - 06:30 AM, said:

1. Yes, there is. It wasn't possible to proceed with standard API.
2. What is id_parent? If 10 trees are stored how to get tree #8?


1. could you be more specific? What is default 'save' used for now?
2. if I find elements with level=0 or id_parent=null I can easily sort them by 'lft' and get 8th element of such list, or I can find interesting root with more specific query (by other columns). Consider such data:

node  , lft, rgh, level, id_parent
root 1,   1,   2,     0,      null
root 2,   3,   4,     0,      null
root 3,   5,   6,     0,      null
root 4,   7,   8,     0,      null
root 5,   9,  10,     0,      null

red
0

#56 User is offline   omp 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 12-August 12

Posted 12 August 2012 - 06:28 AM

Say you had a tree like this with its accompanying representation in the database.

   R
N1   N2

lft, rgh, level
1,   6,     0     
2,   3,     0      
4,   5,     0     


If I want to insert a child node under N1, then all the rows in the database have to be updated.

However, say you changed the database so the tree was represented like this:

lft, rgh, level
100,   600,     0     
200,   300,     0      
400,   500,     0     


Now if I want to insert under N1, you don't have to alter the root or N2.


So, would it be possible to introduce "gaps" like this to reduce the number of records that need to be touched when altering the tree structure?
0

#57 User is offline   johonunu 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 26-November 10

Posted 15 September 2012 - 12:58 PM

Can someone tell me is there any way to arrange roots ?

For example, I have model pages that uses multiple trees forstructure:

=============================
HOME (ROOT)
NEWS (ROOT)
ABOUT (ROOT)
PORTFOLIO (ROOT)
--- WEBSITES (LEAF)
--- APPLICATIONS (LEAF)
SERVICES (ROOT)
=============================

And I would like to put "About" page at the end, and page "Services" above "News" page ?

=============================
ROOT (ROOT)
--- HOME (LEAF)
--- NEWS (LEAF)
--- ABOUT (LEAF)
--- PORTFOLIO (LEAF)
--- --- WEBSITES (LEAF)
--- --- APPLICATIONS (LEAF)
--- SERVICES (LEAF)
=============================

I am using this at the moment, but I don't like to have page "Root" that don't get any use.

Thanks ;)
0

#58 User is offline   Ben 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 270
  • Joined: 15-March 09

Posted 15 September 2012 - 01:35 PM

Since the moveNode method disallows target to be a root node, I'd guess this is not supported. :(

However, when loading pages, you can easily exclude the root:

$root  = Page::model()->findByPk( $rootId );
$pages = $root->descendants()->findAll();

Don't like ads in my sig...
1

#59 User is offline   johonunu 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 26-November 10

Posted 15 September 2012 - 05:24 PM

View PostBen, on 15 September 2012 - 01:35 PM, said:

Since the moveNode method disallows target to be a root node, I'd guess this is not supported. :(

However, when loading pages, you can easily exclude the root:

$root  = Page::model()->findByPk( $rootId );
$pages = $root->descendants()->findAll();



Thank you Ben for reply! I've been doing that already ;)
I just wanted to know if there is a way to not have a "root" page in the table at all.

Thanks anyway ;)
0

#60 User is offline   Boaz 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 367
  • Joined: 23-January 11

Posted 20 September 2012 - 02:50 PM

Hi,

Similar to the curiosity raised in this comment on this thread, I'd also be happy to know why there is the 'root' and 'level' columns in the schema. AFAIK, they are not strictly needed in nested set implementation. Is that for performance enhancement?

I've looked at the couple of resources linked in the mentioned comment: the first is a 404 now and the second doesn't answer the question as well (though I've skimmed it).

Thanks!
Boaz.
Therapeutic PHP sessions My LinkedIn Profile
0

Share this topic:


  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • 4
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users