views:

52

answers:

1

Hi all,
I am wondering is there an easy way to make a copy of a tree structure that consists of one model with a parent_id that actsAs a tree?

I was thinking it should be easy to recursively go through a given tree, remove all ids and lft, rght fields; however, as I add the new fields parent_id won't match up correctly. I suppose it should be easy enough to write my own function to handle this, but I just wanted to know if there was already something to handle this?

Thanks!!

+1  A: 

First, I used Multi Tree Behaviour ( http://bakery.cakephp.org/articles/view/multitree-behavior ) as it allows several trees to be managed in one table.

My examples are perhaps a little complex and confused with application specific code, but I'm sure you can pick your way through it!

Pretty much anything you do with the tree is going to need a recursive 'tree-walker'. I wrote a task manager with sub-tasks etc. and this is an example of a method I used to walk the tree:

function _walkTasksTree($nodes, $model='Task')
{
    foreach($nodes as $node)
    {
        $task = $node[$model];
        $id = $task['id'];
        $title = $task['name'];
        $level = $task['level'];

        $children = $this->_walkTasksTree($node['children'],$model);

        if(empty($children))
        {
            $data[$id] = array('level'=>$level,'title'=>$title);
        }
        else
        {
            $data[$id] = array('level'=>$level,'title'=>$title,'children' => $children);
        }
    }
    $data = (isset($data))?$data:array();
    return $data;
}

My application has a 'repository' of common tasks which can be cloned into a project. The basic model is ProjectTask [1:1] ProjectTaskDescriptor - the descriptor holding the data, and the task holding the tree position. I use this method to traverse and clone trees and/or branches

function _saveTaskTree($subTasks,$parent_id,$root_id,$projId,$exclude=null)
{
    foreach($subTasks as $node)
    {
        if(@$exclude!=$node['Task']['id'])
        {
            $node['Task']['id'] = null;
            $node['Task']['root_id'] = $root_id;
            $node['Task']['parent_id'] = $parent_id;
            $node['Task']['project_id'] = $projId;
            $this->ProjectTask->create();
            $saved = $this->ProjectTask->save($node['Task']);
            $this->ProjectTaskDescriptor->create();
            $PTD = $node['TaskDescriptor'];
            $PTD['project_task_id'] = $this->ProjectTask->id;
            $this->ProjectTaskDescriptor->save($PTD);
        }
        else
        {
            $saved = true; //skip the first one - we've already done it.
        }
        if($saved)
        {
            if(@$node['children'])
                $children = $this->_saveTaskTree($node['children'],$this->ProjectTask->id,$root_id,$projId);
        }
    }
}

It is a very hands on process and in terms of future understanding and maintenance of the code it is worthwhile fully understanding what is going on.

Leo
Ahhhh, i seee! yea, it makes sense, I had the same concept in my mind! I was hoping it was already automated. Thanks for the example!
Parris