CTreeView nested add delete rename with db

I’m new of YII and it’s my first project with a PHP framework, means that if I can do the things better you can write me suggestions and I’ll be so happy :D

Let’s start…

On my site I want to use in different controllers a CTreeViev that displays different nested elements, and I want to add, delete and rename them, I want also write less code possible and that’s my idea:

for now I want only root>Corporation>Division>Person and I want to add and rename only Corporation and Division, naturally I can nest mor things

View(index.php):

prova.js is the JQuery script and navTree.css is one easy css for creating two div in the same line, now isn’t important




<?php

	$cs=Yii::app()->clientScript;

	$cs->registerCoreScript('jquery');

	$cs->registerScriptFile(Yii::app()->baseUrl.'/js/prova.js');

	$cs->registerCssFile(Yii::app()->baseUrl.'/css/navTree.css');

?>


<div id="left">

<?php

$this->widget('CTreeView',array(

		'id'=>'tree',

        'data'=>$dataTree,

        'animated'=>'fast',

        'collapsed'=>'false',

        'htmlOptions'=>array(

                'class'=>'filetree',//there are some classes that ready to use

        ),


));

?>

</div>


<script>

	//here I write classes array sended by actionIndex

	<?php echo $classes; ?>

	setParams("prova",classes);

</script>



Controller (ProvaController.php):

see the attribute $classes with the list of classes that I’ll nest in order and how I want to manage the operations of add, rename, delete using the id sended by the elements (classname_id -> corporation_10)

there is also the creation the initial tree, the #adders can be avery kind of element, the important that the class is "adder" and the id is right.




<?php


class ProvaController extends Controller

{

	protected $classes = array('tree','corporation','division','person'); //list of classes in order, the first is the name of the tree


	

	public function actionIndex() {

		//$datatree is the array of the tree, $classes contains the string for the istance of the array in javascript

		$this->render('index', array('dataTree'=>$this->createTree($this->classes),'classes'=>'var classes = new Array("'. join($this->classes,'","'). '");'));

	}


	public function actionAddTreeNode() {

		$id=explode("_",$_GET['id']);

		$key = array_search($id[0],$this->classes)+1; //the addercontains the name of upper class, means that i must watch next object on classes

		switch($this->classes[$key])

		{

			case 'corporation';

				$corp=new Corporation;

				$corp->name ='new corporation';

				$corp->concurrency=true;

				$corp->save();

			break;

			case 'division';

				$div=new Division;

				$div->name ='new division';

				$div->corporation_id=$id[1];

				$div->save();

			break;

			default:

				return false;

			break;

		}

		echo Yii::app()->db->lastInsertID; //id to nsert on jtree

	}


	public function actionRenameTreeNode() {

		$id=explode("_",$_GET['id']);

		switch($id[0])

		{

			case 'corporation';

				$model=Corporation::model()->findByPk($id[1]);

			break;

			case 'division';

				$model=Division::model()->findByPk($id[1]);

			break;

			default:

				return false;

			break;

		}

		$model->name =$_GET['name'];

		$model->save();

	}


	public function actionRemoveTreeNode() {

		$id=explode("_",$_GET['id']);

		switch($id[0])

		{

			case 'corporation';

				Division::model()->deleteAll('corporation_id='.$id[1]);

				Corporation::model()->deleteByPk($id[1]);

			break;

			case 'division';

				Division::model()->deleteByPk($id[1]);

			break;

			default:

				return false;

			break;

		}

	}

 

 

	//creation of the tree with arrays, see .adder

	private function createTree()

	{

		$tree=array();

		$addCorporation=array('text'=>'<a class="adder" id="tree">Add</a>'); //adder can be everything, important: class and id

		array_push($tree,$addCorporation);

		$corporations = Corporation::model()->findAll();

		foreach($corporations as $corp)

		{

			$corporationNode=array('text'=>'<span class="node" id="corporation_'.$corp->id.'">'.$corp->name.'</span>'); //class=node, id=class_id

			

			$addDivision=array('text'=>'<a class="adder" id="corporation_'.$corp->id.'">Add</a>');

			$divisions = Division::model()->findAll('corporation_id='.$corp->id);

							

			$corporationNode['children']=array();

			array_push($corporationNode['children'],$addDivision);

			

			foreach($divisions as $div)

				array_push($corporationNode['children'],array('text'=>'<span class="node" id="division_'.$div->id.'">'.$div->name.'</span>'));


			array_push($tree,$corporationNode);

		}

		return $tree;

	}

}

?>



The Jquery script(prova.js):

the important classes are: adder, renamer, deleter, node. The first tree are selfexplained the node is an element that can be changed or deleted.




var controller; //controller name for calling

//actions name for calling

var actionAdd='addTreeNode'; 

var actionDelete='removeTreeNode';

var actionRename='renameTreeNode';

//the class names passed from the view

var nodes;


function setParams(cont,ns){ //give parameters

	controller=cont;

	nodes=ns;

}


function getRow(cl, id){ //obtain rows with id class_id

	return $("#"+cl+"_"+id);

}


function addNode(id, newId){ //add new rows

	var el="";

	var str="";

	id=id.split('_');


	if(id[0]==nodes[0])

		el=$("#"+nodes[0]); //root id=treeName

	else

		el=getRow(id[0],id[1]).parent().children("ul"); //other case example id="classNotRoot_#"

		

	str='<li><span class="node "id="'+nodes[nodes.indexOf(id[0])+1]+'_'+ newId +'">new '+ nodes[nodes.indexOf(id[0])+1] +'</span>';

	

	if(id[0]!=nodes[nodes.length-3]) //isn't one leaf <------------------you decide here where do you watnt stop

		str= str + '<ul><li><a class="adder" id="'+nodes[nodes.indexOf(id[0])+1]+'_'+ newId +'">Add</a></li></ul>';

	str= str + '</li>';

	branches = $(str).appendTo(el); //create new element

	$("#"+nodes[0]).treeview({add: branches}); //added to tree

	return true;

}


function pushRenameDelete(id) //write on the node add and remove the rename/delete options

{

	el = id.split("_");

	el = getRow(el[0],el[1]);

	if(!el.children("a").text())

		el.html(el.html()+' <a href="javascript:inputRename(\''+id+'\')">rename</a> <a class="deleter" id="'+ id +'" href="#">delete</a>');

	else if(el.children("a").text()!="change")

		el.children("a").remove();

}


function inputRename(id) //write the textfield on the node (called by rename, see function pushRenameDelete)

{

	el = id.split("_");

	el = getRow(el[0],el[1]);

	el.children("a").remove(); //remove rename delete

	el.html('<input type="text" value="'+el.text()+'"><a class="renamer" id="'+ id +'"href="#">change</a>');

}


function setName(id,name)

{

	el=id.split("_");

	getRow(el[0],el[1]).html(name);

}


function delNode(id)

{

	id=id.split("_");

	branches = getRow(id[0],id[1]).parent();

	$("#"+nodes[0]).treeview({remove: branches});

}


//here I watch events and I do the actions that interact with controller

$(document).ready(function() {

	$('.adder').live('click',function(e){

		var id=$(this).closest('.adder').attr('id');

		$.get("index.php?r="+controller+"/"+actionAdd,{'id':id},function(newId){

			addNode(id,newId);

		});

	});

	$('.renamer').live('click',function(e){

		var id=$(this).closest('.renamer').attr('id');

		var name=$("#"+id).children("input").val()

		$.get("index.php?r="+controller+"/"+actionRename,{'id':id, 'name':name},function(){

			setName(id,name);

		});

	});

	$('.deleter').live('click',function(e){

		var id=$(this).closest('.deleter').attr('id');

		$.get("index.php?r="+controller+"/"+actionDelete,{'id':id},function(){

			delNode(id);

		});

	});

	$('.node').live('click',function(e){

		pushRenameDelete($(this).closest('.node').attr('id'));

		//here i can add the code for call the pages in another div near this tree

	});

});	



That’s all, I hope that the comments are OK and that’s useful to someone