ACC SHELL

Path : /srv/www/vhosts/agroing/web/models/
File Upload :
Current File : /srv/www/vhosts/agroing/web/models/relations_model.php

<?php
/**
 * stara se o ukladani a vypis dat ulozenych ve stromove strukture
 * a vraci infromace o predchozich a nasledujicich prvcich
 * a vraci drobeckovou navigaci
 *
 */
class Relations_model extends Base_model{

	public $table = "relations";
	protected $relations_model = true; // for recognize if model is extending this
//	public $no_bc=false; // kdyz je true tak z drobeckovky vyhodi polozky, ktere maji tag "no_bc"
	public $zero_sitemap=true;// kdyz je true tak vrati vsechny uzly vcetne tech, ktere maji nastaveno sitemap na 0
	public static $repair_on_insert = true; // if its false, it won't be repaired after insert
	/**
	 * root node.
	 * Have influence to relations->breadcrumbs() and sites->tag() NOT TO tree()
	 */
	public $root_relation = array();


	////////    Variables for tree()    ////////
	// limit, order are extended from base_model()
	// where is for sure not used
	public $offset;
	public $range;
	public $idr;
	public function set_offset($offset) { $this->offset = $offset;  return $this; }
	public function set_range($range)   { $this->range = $range;    return $this; }
	public function set_root($root)     { $this->idr = $root;      return $this; }
	public function set_zero_sitemap($zero_sitemap)     { $this->zero_sitemap = $zero_sitemap;      return $this; }

	public function __construct(){
		parent::__construct();
		$this->order = "lft";
		$this->set_useful_columns(array('depth','relations.id as idr','parent_id','lft','rgt'));
		$this->set_joins("LEFT JOIN relations ON relations.id_".$this->table."=".$this->table.".id");
	}

	public $last_inserted_id; // obsahuje id posledniho vytvoreneho zaznamu v tabulce relations
	private $traversal_lft_rgt; // pomucka pri opravach stromu

	/**
	 * docs in Base_model()
	 */
	public function new_one($data=NULL,$call_get_one=false){
		$result = parent::new_one($data,$call_get_one);
		$result->range = $this->range;
		$result->offset = $this->offset;
		return $result;
	}
	
	/**
	 * docs in Base_model()
	 */
	public function load($data=array(),$id=NULL,$idr=NULL){
		parent::load($data,$id);
		if(!empty($data['idr']) && is_numeric($data['idr'])){
			$this->idr = $this->a['idr'];
		}
		if(is_numeric($idr) && $idr){
			$this->idr = $idr;
		}
		return $this;
	}

	/**
	 * vraci strom
	 * @param bool $call_get_one udela/neudělá get_one() na každém prvku
	 * @return array pole objektů
	 */
	final public function tree($call_get_one=false){
		$cond=array();
		$cond[]="relations.table='".$this->table."'";
		//if(empty($this->idr)) $this->idr = $this->root_relation['id'];
		if(!empty($this->idr)){
			$root_rel=$this->get_relation($this->idr);
			if(empty($root_rel)){ Tools::flash("Tree() má chybně definován kořen, idr=$this->idr pravděpodobně neexistuje","critical"); return;}
			$cond[]="relations.lft>=".$root_rel['lft']."";
			$cond[]="relations.rgt<=".$root_rel['rgt']."";
			if(!empty($this->offset)){
				$cond[]="relations.depth>=" . ($root_rel['depth']+$this->offset);
			}
			if(!empty($this->range)){
				$cond[]="relations.depth<=" . ($root_rel['depth']+$this->offset+$this->range-1);
			}
			if(!$this->zero_sitemap){
				$cond[]=$this->table.".sitemap=1";
			}
		}else{
			Tools::critical("tree() was called without \$idr");
			return array();
		}
		if(!empty($this->where)){
			$cond[] = $this->where;
		}
		$this->set_where(implode("&&",$cond));
		return $this->get_all($call_get_one);
	}

	// hepler method, returning tree of childrens
	public function childrens($call_get_one=false)	{ // offset and range in one
		$this->range = 1;
		$this->offset = 1;
		return $this->tree($call_get_one);
	}

	/**
	 * vraci data pro drobeckovou navigaci
	 *
	 * @param integer $idr [optional]
	 * @param boolean $zero_sitemap [optional] false - vynecha polozky, ktere maji nastavene sitemap na 0; true - vrati vse
	 * @return mixed pokud je co vratit tak array, jinak false
	 */
	public function breadcrumbs($idr=false,$zero_sitemap=false){
		$idr=($idr ? $idr : $this->idr);
		$return=array();
		if($idr){
			$relation=$this->get_relation($idr,false,false);
			$bc = $this->new_one()->set_where(" relations.table='".$this->table."' &&
				relations.lft<='".$relation['lft']."'
				AND relations.rgt>='".$relation['rgt'] . "'" .
				(!empty($this->root_relation)?"&& relations.lft > '".$this->root_relation['lft']."' &&
				relations.rgt<'".$this->root_relation['rgt']."'":"") .
				(!$zero_sitemap ? " AND ".$this->table.".sitemap=1 " : false)
			);
			$bc->set_order("depth");
			return $bc->get_all();
		}
		return $return;
	}

	// returns array width idr like keys
	public function breadcrumbs_enum(){
		foreach($this->breadcrumbs() as $b){
			$result[$b->idr] = true;
		}
		return @$result;
	}

	public function parent(){
		if(!empty($this->a['parent'])){
			if($this->a['parent']->idr == $this->a['parent_id']) return $this->a['parent'];
		}
		if(empty($this->a['parent_id'])){
			Tools::debug("relations_model::parent() callet without \$this->a['parent_id']. Probably it's root and returned \$this");
			return $this;
		}
		Tools::log("relations_model::parent() of idr=".$this->a['parent_id']." calling get_one()");
		$this->a['parent'] = $this->new_one()->get_one($this->a['parent_id']);
		return $this->a['parent'];
	}

	public function children_count($idr=null){
		if(!$idr) $idr = $this->idr;
		$c = $this->db->query("select count(id) as c from relations where parent_id='$idr'")->row_array();
		return @$c['c'];
	}

        // returns count of relations related with site of this id
	public function relations_count($id_table=null){
		if(!$id_table) $id_table = $this->id;
		$c = $this->db->query("select count(id) as c from relations where id_$this->table = '$id_table' && `table` = '$this->table'")->row_array();
		return @$c['c'];
	}

	/**
	 * doplni/opravi nalezitosi potrebne k traverzovani - level, lft, rgt
	 * i ostatni, pokud nejsou - list
	 * povinne jsou jen id a parent_id
	 *
	 * todo: zredukovat parametry
	 * todo: dělá chybu pokud se spouští repair tree z constructu
	 *
	 * @param boolean $transaction [optional] zda se ma provest ve vlastni transakci
	 * @param integer $root_idr [optional] kdyz je zadano tak se opravi strom jen od zadaneho id
	 * @return boolean
	 */
	final public function repair_tree($transaction=true,$root_idr=false){
		$debug=false;
		$return=false;
		$root_idr=($root_idr ? intval($root_idr) : false);
		$root_relation=($root_idr ? $this->get_relation($root_idr,false,false) : false);
		$root_lft=(!empty($root_relation) ? $root_relation['lft'] : false);
		$root_depth=(!empty($root_relation) ? $root_relation['depth'] : 0);
		$query="
			# zjisti detaily jednotlivych zaznamu - rozdil je pokud zdroj neni traverzovaci tabulka, ale jina plosna se zdrojovymi daty
			SELECT
				id, id_".$this->table.",
				IFNULL(parent_id,'NULL') AS parent_id,
				IFNULL(parent_site_id,'NULL') AS parent_site_id,
				list,
				'' AS depth,
				'' AS lft,
				'' AS rgt
			FROM relations WHERE `table`='".$this->table."'".(!empty($root_relation) ? "AND `lft`>=".$root_relation['lft']." AND `rgt`<=".$root_relation['rgt'] : false)."
			ORDER BY (list),(id)";
//		Tools::debug($query);
//		echo '<pre>'.$query.'</pre>';
		$linear_traversal_structure=$this->prepare_linear_traversal_structure($this->db->query($query)->result_array(),$root_lft,$root_depth);
		// samotna oprava
		if(is_array($linear_traversal_structure) && count($linear_traversal_structure)){
			if($transaction){
				$this->db->query('START TRANSACTION');
			}
			$result=array();
			$result['ok']=0;
			$result['bad']=0;
			$last_inserted_id=array();
			foreach($linear_traversal_structure as $item){
				$query=false;
				$query="
					UPDATE relations
					SET
						parent_site_id=".$item['parent_site_id'].",
						list=".$item['list'].",
						depth=".$item['depth'].",
						lft=".$item['lft'].",
						rgt=".$item['rgt']."
					WHERE id=".$item['id'].";";
				// pocita uspesne/neuspesne updaty
				if($this->db->query($query)){
					$result['ok']++;
					// protoze id predka v tabulce result nemusi byt id predka v odkazovane tabulce (plati pri pocatecnim plneni daty)
					$last_inserted=$this->db->query("SELECT LAST_INSERT_ID() AS id")->row_array();
					$last_inserted_id[$item['id']]=$last_inserted['id'];
				}
				else{
					$result['bad']++;
					break;
				}
				echo ($debug ? '<hr>' : false);
			}
			// pokud nastala nejaka chyba tak vrati vse zpet
			if($result['bad']){
				if($transaction){
					$this->db->query('ROLLBACK');
				}
			}
			else{
				if($transaction){
					$this->db->query('COMMIT');
				}
				$return=true;
			}
		}
		return $return;
	}

	/**
	 * @param array $data array containing id_table, parent_id, list (table should be in $this->table)
	 */
	public function save_relation($data=NULL,$idr=null){
		$this->load($data,NULL,$idr);
		$return=null;
		// pri insertu vynulluju idr
		if($idr==='0'){$this->idr=null;}
		if(!empty($this->idr)){
			$return=$this->move_relation($this->idr,$this->a['parent_id'],@$this->a['list']);
			// k proměnným se přistupuje např takto: $this->a['parent_id']
		}else{
			$return=$this->insert_relation($this->id,$this->a['parent_id']);

			$this->idr=$this->last_inserted_id;
		}
		if($return){
			return $this->idr;
		}
		return false;
	}

	/**
	* delete relations with all childrens
	* working with $this->table.... calling $this->del_{$this->table} method
	*
	* @param type $idr
	* @param type $lang TODO: passing to tree()
	* @param type $force TODO: delete all sites in tree, even they are also in other relation
	* @return array formated array with results. Example: array{deleted_relations=>10; deleted_table_items=>8; diff=2}
	*/
	public function del_relations($idr=NULL,$lang=NULL,$force=false){
		$result = array('deleted_relations'=>0,'deleted_table_items'=>0); // result init
		$this_rel = $this->get_relation($idr);
		if(!empty($this_rel)){
			$tree = $this->load(NULL,NULL,$idr)->tree();
			foreach($tree as $rel){ // go throw the tree
				$result['deleted_relations']++;
				if($rel->relations_count()<=1){
					$del_method_name = "del_".$this->table;
					$rel->$del_method_name(); // call for example del_sites()
					$result['deleted_table_items']++;
				}elseif($force){ // todo: vychytat podmínku... pokud relations_count()==1 neznamená to ještě, že se nenachází v jiné větvi!

				}
				// in InnoDB delete this node and all childrens
				$this->db->query("delete from relations  where id='$rel->idr'");
			}
			$diff = $this_rel['rgt']-$this_rel['lft']+1;
			$this->db->query("update relations set lft=(lft-$diff), rgt=(rgt-$diff)
					where lft>".$this_rel['lft']." && rgt>".$this_rel['rgt']." && relations.table='$this->table'");
			$result['diff'] = $result['deleted_relations'] - $result['deleted_table_items'];
			Tools::debug("deleted relation with this result: ".var_export($result,1));
			return $result;
		}else{
			Tools::critical("Delete relation id=$this->idr failed.");
			return false;
		}
	}

	/**
	 * novy uzel stromu
	 *
	 * @param integer $id_sites id pridavane polozky (id ze zdrojove tabulky)
	 * @param integer $parent_id id uzlu predka (id v tabulce relations)
	 * @param integer $list [optional] poradi null/false/0 - zaradi na konec
	 * @return boolean
	 *
	 * @todo Vlahovic, 22.12.11 15:33: nedela pomoci repair tree, ale jen pomoci sql
	 */
	public function insert_relation($id_sites,$parent_id=null,$list=false){
		$return=false;
		$res=array();
		$list=intval($list);
		$lid=false;
		// vytvoreni rootu
		if(!$parent_id){
			$c=$this->db->query(" # select in insert_relation()
				SELECT COUNT(*) AS count FROM relations WHERE `table`='".$this->table."';")->row_array();
			if(!$c['count']){
				$query="# vytvoreni rootu
					INSERT INTO relations
					(id_".$this->table.",`table`,list,depth,lft,rgt) VALUES
					(".$id_sites.",'".$this->table."',1,0,1,2);";

				if($this->db->query($query)){
					$lid=$this->db->insert_id();
					$return=($lid ? true : false);
				}
			}
		}
		// jakykoliv zanoreny uzel
		else{
			$parent=$this->get_relation($parent_id,false,false);
			$transaction=$this->db->query("START TRANSACTION");
			if($transaction && !empty($parent)){
				// vlozi na prvni pozici v dane vetvi
				if($list){
					$query="# uvolni misto pro novy uzel na konkretni pozici
						UPDATE `relations` SET `list`=(`list`+1)
						WHERE `table`='".$this->table."' AND `parent_id`=".$parent_id." AND `list`>=".$list;
					$res[]=$this->db->query($query);
				}
				else{
					$list=($this->children_count($parent_id))+1;
				}

				$query="# vytvori novy uzel
				INSERT INTO relations
					(id_".$this->table.",parent_id,parent_site_id,`table`,list) VALUES
					(".$id_sites.",".$parent['id'].",".$parent['id_'.$this->table].",'".$this->table."',".$list.")";
				$res[]=$this->db->query($query);
				$res[]=$lid=$this->db->insert_id();
				if(self::$repair_on_insert){
					$res[]=$this->repair_tree(false);
				}

				// ukonceni transakce
				if(in_array(false, $res)){
					$this->db->query("ROLLBACK");
				}
				else{
					$return=true;
					$return=$this->db->query("COMMIT");
				}
			}
		}
		if($return){
			$this->last_inserted_id=$lid;
		}
		else{
			$this->last_inserted_id=false;
		}
		return $return;
	}

	/**
	 * presunuti uzlu
	 *
	 * @param integer $idr presouvany uzel
	 * @param type $parent_id novy rodic
	 * @param integer $list [optional] poradi null/false/0 - zaradi na konec
	 * @return boolean
	 */
	final public function move_relation($idr,$parent_id,$list=false){
		if(empty($parent_id)){
			Tools::debug("move_relation() with no parent_id was called. If you were saving root, it's ok");
			return true;
		}
		$debug=false;
		$return=false;
		$res=array();
		$list=intval($list);
		$actual=$this->get_relation($idr,false,false);
		$actual_parent=$this->get_relation($actual['parent_id'],false,false);
		$parent=$this->get_relation($parent_id,false,false);
		$transaction=$this->db->query("START TRANSACTION");
		if($transaction && !empty($parent) && !empty($actual)){
			// pripravi konkreni umisteni na vetvi
			if($list){
				$query="# uvolni misto pro novy uzel na konkretni pozici
					UPDATE `relations` SET `list`=(`list`+1) WHERE `table`='".$this->table."' AND `parent_id`=".$parent_id." AND `list`>=".$list;
				$res['create_free_place']=$this->db->query($query);
			}
			// umisti na konec vetve
			else{
				$list=($this->children_count($parent_id))+1;
			}

			// presune uzel na nove misto
			$query="# presune uzel
				UPDATE `relations` SET `parent_id`=".$parent_id.",`list`=".$list." WHERE `id`=".$idr.";";
			$res['move_node']=$this->db->query($query);

			// opravi cely strom, pokud jeden z rodicu je root
			if(!$actual_parent['depth'] || !$parent['depth']){
				$res['repair_tree_1']=$this->repair_tree(false);
				echo ($debug ? 'repair_tree 1' : false);
			}
			// pokud jsou stejni
			elseif($actual_parent['id']==$parent['id']){
				$res['repair_tree_2']=$this->repair_tree(false, $parent['id']);
				echo ($debug ? 'repair_tree 2 > root_idr: '.$parent['id'] : false);
			}
			// stavajici rodic je potomkem nastavacijiho
			elseif($parent['lft']<$actual_parent['lft'] && $parent['rgt']>$actual_parent['rgt']){
				$res['repair_tree_3']=$this->repair_tree(false, $parent['id']);
				echo ($debug ? 'repair_tree 3' : false);
			}
			// stavajici rodic je predkem nastavacijiho
			elseif($parent['lft']>$actual_parent['lft'] && $parent['rgt']<$actual_parent['rgt']){
				$res['repair_tree_4']=$this->repair_tree(false, $actual_parent['id']);
				echo ($debug ? 'repair_tree 4' : false);
			}
			// rodice k sobe nemaji vztah :-) opravi se strom od prvniho spolecneho predka
			else{
				$res['common_node']=$common_node=$this->common_node($parent['id'],$actual_parent['id']);
				$res['repair_tree_5']=$this->repair_tree(false, $common_node);
				echo ($debug ? 'repair_tree 5' : false);
			}

			if($debug){
				exit('<hr>exit in file '.__FILE__.', line '.__LINE__);
			}

			// ukonceni transakce
			if(in_array(false, $res)){
				foreach($res as $err => $value){
					if(!$value){
						Tools::log('error during moving node - '.$err.' (file: '.__FILE__.'; line: '.__LINE__.')');
					}
				}
				$this->db->query("ROLLBACK");
			}
			else{
				$return=($this->db->query("COMMIT") ? true : false);
			}
		}
		return $return;
	}

	/**
	 * najde prvni spolecny uzel dvou zadanych
	 *
	 * @param integer $node1
	 * @param integer $node2
	 * @return integer id spolecneho predka, v pripade nejakeho neuspechu false
	 */
	public function common_node($node1, $node2){
		$return=false;
		$index=false;
		$i=false;
		$bc1=false;
		$bc2=false;
		$node1=intval($node1);
		$node2=intval($node2);
		if($node1 && $node2){
			$bc1=$this->breadcrumbs($node1,true);
			$bc2=$this->breadcrumbs($node2,true);
			foreach($bc1 as $i => $o){
				$o;
				if($o->idr == $bc2[$i]->idr){
					$index=$i;
				}
				else{
					break;
				}
			}
			if($index!==false){
				$return=$bc1[$index]->idr;
			}
		}
		return $return;
	}

	/**
	 * * from relation by id_sites
	 * nedava moc smysl, protoze id_sites muze byt v tabulce relations nekolikrat
	 *
	 * nasel jsem pouziti pri unit testech (Vlahovic) - nemazat, ale ani nepouzivat jinde
	 */
	public function get_relation_by_site($id,$table=false){
		if(!$id) return false;
		$table=($table ? $table : $this->table);
		return $this->db->query(" # select in get_relation_by_site();
			SELECT * FROM relations WHERE `table`='".$table."' AND id_".$table."='".$id."'")->row_array();
	}

	/** return lft,rgt,depth from relation and set $this->id
	 *
	 * @param integer $idr
	 * @param string $table
	 * @param boolean $load
	 * @return array
	 */
	public function get_relation($idr=null,$table=false,$load=true){
		$table = ($table ? $table : $this->table);
		$idr = ($idr ? $idr : $this->idr);
		if($idr){
			$data = $this->db->query(" # get relation
				SELECT id,lft,rgt,depth,id_".$table.",parent_id,list FROM relations WHERE relations.id=".$idr)->row_array();
			if($load){
				$this->load(NULL,@$data['id_'.$table],$idr);
				foreach($data as $i=>$d){
					$this->a[$i] = $d;
				}
			} // set $this->id
			return $data;
		}else{
			Tools::debug("relations_model::get_relation() get no parameter \$idr. This might be a problem!");
			return false;
		}
	}

	public function relations_join(){
		return 'LEFT JOIN '.$this->table.' ON '.$this->table.'.id=relations.id_'.$this->table;
	}

	/**
	 * ze stromove strukturovaneho pole udela linearni
	 *
	 * @param array $tree
	 * @return mixed pokud nedostane na vstupu pole pak vrati false jinak array
	 */
	protected function tree_to_linear($tree){
		$return=array();
		if(is_array($tree)){
			foreach($tree as $item){
				// potomky si schovam, abych je pripojil za rodice
				$childrens=false;
				if(isset($item['childrens']) && is_array($item['childrens']) && count($item['childrens'])){
					$childrens=$item['childrens'];
					unset($item['childrens']);
				}
				// rodic
				$return[]=$item;
				// pripojeni potomku
				if($childrens!==false){
					$return=array_merge($return,$this->tree_to_linear($childrens));
				}
			}
			return $return;
		}
		return false;
	}

	/**
	 * dodane pole doplni o polozky potrebne k traverzovani
	 *
	 * @param array $tree_items
	 * @param integer $first_lft [optional]
	 * @param integer $first_depth [optional]
	 * @return array
	 */
	protected function create_traversal_structure($tree_items,$first_lft=false,$first_depth=0){
		$return=$this->create_tree_structure($tree_items);
		$return=$this->add_depth_and_list_to_tree_structure($return,$first_depth);
		$this->traversal_lft_rgt=($first_lft ? $first_lft : 1);
		$return=$this->add_lft_rgt_to_tree_structure($return);
		return $return;
	}

	/**
	 * do pole se stromovou strukturou ke kazdemu prvku doplni informaci o levem a pravem prvku
	 * podminkou je aby vstupni pole melo jen jeden korenovy prvek
	 *
	 * @param array $tree
	 * @return mixed pokud vstupni pole nesplnuje podminky pak vraci false jinak array
	 */
	private function add_lft_rgt_to_tree_structure($tree){
		$return=array();
		if(is_array($tree)){
			foreach($tree as $index => $arr){
				$arr['lft']=$this->traversal_lft_rgt;
				$this->traversal_lft_rgt++;
				// neni koncovym bodem
				if(isset($arr['childrens']) && is_array($arr['childrens']) && count($arr['childrens'])){
					$arr['childrens']=$this->add_lft_rgt_to_tree_structure($arr['childrens']);
				}
				$arr['rgt']=$this->traversal_lft_rgt;
				$return[$index]=$arr;
				$this->traversal_lft_rgt++;
			}
			return $return;
		}
		return false;
	}

	/**
	 * do pole doplni informaci o hloube zanoreni jednotlivych prvku
	 *
	 * @param array $tree
	 * @param integer $depth [optional]
	 * @return mixed pokud nedostane ke zpracovani pole pak vrati false, jinak array
	 */
	private function add_depth_and_list_to_tree_structure($tree, $depth=0){
		$return=array();
		$list=1;
		if(is_array($tree) && count($tree)){
			foreach($tree as $index => $arr){
				$arr['depth']=$depth;
				$arr['list']=$list;
				if(isset($arr['childrens']) && is_array($arr['childrens']) && count($arr['childrens'])){
					$arr['childrens']=$this->add_depth_and_list_to_tree_structure($arr['childrens'],$depth+1);
				}
				$return[$index]=$arr;
				$list++;
			}
			return $return;
		}
		return false;
	}

	/**
	 * vytvori stromovou strukturu z pole kde kazda polozka ma svoje id a id predka
	 *
	 * @param array $tree_items
	 * @return array
	 */
	private function create_tree_structure($tree_items){
		$return=array();
		if(is_array($tree_items) && count($tree_items)){
			foreach($tree_items as $index => $tree_item){
				// spojuje po parech
				if(isset($tree_items[$tree_item['parent_id']])){
					// aby se neprepisovalo novejsim zaznamem
					$return[$tree_item['parent_id']]=(!isset($return[$tree_item['parent_id']]) ? $tree_items[$tree_item['parent_id']] : $return[$tree_item['parent_id']]);
					if(!isset($return[$tree_item['parent_id']]['childrens'])){
						$return[$tree_item['parent_id']]['childrens']=array();
					}
					// doplni poradi korenoveho prvku
					if(!$return[$tree_item['parent_id']]['list']){
						$return[$tree_item['parent_id']]['list']=1;
					}
					// spoji do pole s predkem
					$return[$tree_item['parent_id']]['childrens'][$index]=$tree_item;
				}
			}
		}
		if(count($return)>1){
			$return=$this->create_tree_structure($return);
		}
		return $return;
	}


	/**
	 * pripravi pole s daty traverzovaneho stromu
	 *
	 * @param array $tree_items
	 * @param integer $root_lft lft hodnota korenove polozky
	 * @param integer $root_depth zanoreni korenove polozky
	 * @return array
	 */
	protected function prepare_linear_traversal_structure($tree_items,$root_lft,$root_depth){
		$tree_items_id_index=array();
		$linear_traversal_structure=array();
		if(is_array($tree_items) && count($tree_items)){
			foreach($tree_items as $tree_item){
				$tree_items_id_index[$tree_item['id']]=$tree_item;
			}
			$tree_traversal_structure=$this->create_traversal_structure($tree_items_id_index,$root_lft,$root_depth);
//			echo '<pre>'.print_r($tree_traversal_structure,true).'</pre>';
			$linear_traversal_structure=$this->tree_to_linear($tree_traversal_structure);
		}
		return $linear_traversal_structure;
	}
}
?>

ACC SHELL 2018