00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 define("IL_LAST_NODE", -2);
00025 define("IL_FIRST_NODE", -1);
00026
00037 class ilTree
00038 {
00044 var $ilias;
00045
00046
00052 var $log;
00053
00059 var $root_id;
00060
00066 var $tree_id;
00067
00073 var $table_tree;
00074
00080 var $table_obj_data;
00081
00087 var $table_obj_reference;
00088
00094 var $ref_pk;
00095
00101 var $obj_pk;
00102
00108 var $tree_pk;
00109
00116 function ilTree($a_tree_id, $a_root_id = 0)
00117 {
00118 global $ilDB,$ilErr,$ilUser,$ilias,$ilLog;
00119
00120
00121 (isset($ilDB)) ? $this->ilDB =& $ilDB : $this->ilDB =& $ilias->db;
00122
00123 if (!isset($ilErr))
00124 {
00125 $ilErr = new ilErrorHandling();
00126 $ilErr->setErrorHandling(PEAR_ERROR_CALLBACK,array($ilErr,'errorHandler'));
00127 }
00128 else
00129 {
00130 $this->ilErr =& $ilErr;
00131 }
00132
00133
00134 if (!is_object($ilUser))
00135 {
00136 $this->lang_code = "en";
00137 }
00138 else
00139 {
00140 $this->lang_code = $ilUser->getCurrentLanguage();
00141 }
00142
00143 if (!isset($a_tree_id) or (func_num_args() == 0) )
00144 {
00145 $this->ilErr->raiseError(get_class($this)."::Constructor(): No tree_id given!",$this->ilErr->WARNING);
00146 }
00147
00148 if (func_num_args() > 2)
00149 {
00150 $this->ilErr->raiseError(get_class($this)."::Constructor(): Wrong parameter count!",$this->ilErr->WARNING);
00151 }
00152
00153
00154 $this->log =& $ilLog;
00155
00156
00157 if (empty($a_root_id))
00158 {
00159 $a_root_id = ROOT_FOLDER_ID;
00160 }
00161
00162 $this->tree_id = $a_tree_id;
00163 $this->root_id = $a_root_id;
00164 $this->table_tree = 'tree';
00165 $this->table_obj_data = 'object_data';
00166 $this->table_obj_reference = 'object_reference';
00167 $this->ref_pk = 'ref_id';
00168 $this->obj_pk = 'obj_id';
00169 $this->tree_pk = 'tree';
00170 }
00171
00186 function setTableNames($a_table_tree,$a_table_obj_data,$a_table_obj_reference = "")
00187 {
00188 if (!isset($a_table_tree) or !isset($a_table_obj_data))
00189 {
00190 $this->ilErr->raiseError(get_class($this)."::setTableNames(): Missing parameter! ".
00191 "tree table: ".$a_table_tree." object data table: ".$a_table_obj_data,$this->ilErr->WARNING);
00192 }
00193
00194 $this->table_tree = $a_table_tree;
00195 $this->table_obj_data = $a_table_obj_data;
00196 $this->table_obj_reference = $a_table_obj_reference;
00197
00198 return true;
00199 }
00200
00207 function setReferenceTablePK($a_column_name)
00208 {
00209 if (!isset($a_column_name))
00210 {
00211 $this->ilErr->raiseError(get_class($this)."::setReferenceTablePK(): No column name given!",$this->ilErr->WARNING);
00212 }
00213
00214 $this->ref_pk = $a_column_name;
00215 return true;
00216 }
00217
00224 function setObjectTablePK($a_column_name)
00225 {
00226 if (!isset($a_column_name))
00227 {
00228 $this->ilErr->raiseError(get_class($this)."::setObjectTablePK(): No column name given!",$this->ilErr->WARNING);
00229 }
00230
00231 $this->obj_pk = $a_column_name;
00232 return true;
00233 }
00234
00241 function setTreeTablePK($a_column_name)
00242 {
00243 if (!isset($a_column_name))
00244 {
00245 $this->ilErr->raiseError(get_class($this)."::setTreeTablePK(): No column name given!",$this->ilErr->WARNING);
00246 }
00247
00248 $this->tree_pk = $a_column_name;
00249 return true;
00250 }
00251
00257 function buildJoin()
00258 {
00259 if ($this->table_obj_reference)
00260 {
00261 return "LEFT JOIN ".$this->table_obj_reference." ON ".$this->table_tree.".child=".$this->table_obj_reference.".".$this->ref_pk." ".
00262 "LEFT JOIN ".$this->table_obj_data." ON ".$this->table_obj_reference.".".$this->obj_pk."=".$this->table_obj_data.".".$this->obj_pk." ";
00263 }
00264 else
00265 {
00266 return "LEFT JOIN ".$this->table_obj_data." ON ".$this->table_tree.".child=".$this->table_obj_data.".".$this->obj_pk." ";
00267 }
00268 }
00269
00276 function getLeafs()
00277 {
00278 $q = "SELECT * FROM ".$this->table_tree." ".
00279 $this->buildJoin().
00280 "WHERE lft = (rgt -1) ".
00281 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree->id."'";
00282 $r = $this->ilDB->query($q);
00283
00284 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
00285 {
00286 $leafs[] = $this->fetchNodeData($row);
00287 }
00288
00289 return $leafs;
00290 }
00291
00300 function getChilds($a_node_id, $a_order = "", $a_direction = "ASC")
00301 {
00302 if (!isset($a_node_id))
00303 {
00304 $message = get_class($this)."::getChilds(): No node_id given!";
00305 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00306 }
00307
00308
00309 $childs = array();
00310
00311
00312 $count = 0;
00313
00314
00315 $order_clause = "";
00316
00317
00318 if (!empty($a_order))
00319 {
00320 $order_clause = "ORDER BY ".$a_order." ".$a_direction;
00321 }
00322 else
00323 {
00324 $order_clause = "ORDER BY ".$this->table_tree.".lft";
00325 }
00326
00327
00328 $q = "SELECT * FROM ".$this->table_tree." ".
00329 $this->buildJoin().
00330 "WHERE parent = '".$a_node_id."' ".
00331 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."' ".
00332 $order_clause;
00333
00334 $r = $this->ilDB->query($q);
00335
00336 $count = $r->numRows();
00337
00338
00339 if ($count > 0)
00340 {
00341 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
00342 {
00343 $childs[] = $this->fetchNodeData($row);
00344 }
00345
00346
00347 $childs[$count - 1]["last"] = true;
00348 return $childs;
00349 }
00350 else
00351 {
00352 return $childs;
00353 }
00354 }
00355
00365 function getFilteredChilds($a_filter,$a_node,$a_order = "",$a_direction = "ASC")
00366 {
00367 $childs = $this->getChilds($a_node,$a_order,$a_direction);
00368
00369 foreach($childs as $child)
00370 {
00371 if(!in_array($child["type"],$a_filter))
00372 {
00373 $filtered[] = $child;
00374 }
00375 }
00376 return $filtered ? $filtered : array();
00377 }
00378
00379
00387 function getChildsByType($a_node_id,$a_type)
00388 {
00389 if (!isset($a_node_id) or !isset($a_type))
00390 {
00391 $message = get_class($this)."::getChildsByType(): Missing parameter! node_id:".$a_node_id." type:".$a_type;
00392 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00393 }
00394
00395
00396 $childs = array();
00397
00398 $q = "SELECT * FROM ".$this->table_tree." ".
00399 $this->buildJoin().
00400 "WHERE parent = '".$a_node_id."' ".
00401 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."' ".
00402 "AND ".$this->table_obj_data.".type='".$a_type."' ".
00403 "ORDER BY ".$this->table_tree.".lft";
00404 $r = $this->ilDB->query($q);
00405
00406 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
00407 {
00408 $childs[] = $this->fetchNodeData($row);
00409 }
00410
00411
00412 return $childs;
00413 }
00414
00415
00423 function insertNode($a_node_id, $a_parent_id, $a_pos = IL_LAST_NODE)
00424 {
00425
00426
00427 if($this->__isMainTree())
00428 {
00429 if($a_node_id <= 1 or $a_parent_id <= 0)
00430 {
00431 $message = sprintf('%s::insertNode(): Invalid parameters! $a_node_id: %s $a_parent_id: %s',
00432 get_class($this),
00433 $a_node_id,
00434 $a_parent_id);
00435 $this->log->write($message,$this->log->FATAL);
00436 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00437 }
00438 }
00439
00440
00441 if (!isset($a_node_id) or !isset($a_parent_id))
00442 {
00443 $this->ilErr->raiseError(get_class($this)."::insertNode(): Missing parameter! ".
00444 "node_id: ".$a_node_id." parent_id: ".$a_parent_id,$this->ilErr->WARNING);
00445 }
00446 if ($this->isInTree($a_node_id))
00447 {
00448 $this->ilErr->raiseError(get_class($this)."::insertNode(): Node ".$a_node_id." already in tree ".
00449 $this->table_tree."!",$this->ilErr->WARNING);
00450 }
00451
00452
00453
00454
00455
00456 switch ($a_pos)
00457 {
00458 case IL_FIRST_NODE:
00459
00460 if($this->__isMainTree())
00461 {
00462 ilDBx::_lockTables(array('tree' => 'WRITE'));
00463 }
00464
00465
00466 $q = "SELECT * FROM ".$this->table_tree." ".
00467 "WHERE child = '".$a_parent_id."' ".
00468 "AND ".$this->tree_pk." = '".$this->tree_id."'";
00469 $res = $this->ilDB->query($q);
00470 $r = $res->fetchRow(DB_FETCHMODE_OBJECT);
00471
00472 if ($r->parent == NULL)
00473 {
00474 if($this->__isMainTree())
00475 {
00476 ilDBx::_unlockTables();
00477 }
00478 $this->ilErr->raiseError(get_class($this)."::insertNode(): Parent with ID ".$a_parent_id." not found in ".
00479 $this->table_tree."!",$this->ilErr->WARNING);
00480 }
00481
00482 $left = $r->lft;
00483 $lft = $left + 1;
00484 $rgt = $left + 2;
00485
00486
00487 $q = "UPDATE ".$this->table_tree." SET ".
00488 "lft = CASE ".
00489 "WHEN lft > ".$left." ".
00490 "THEN lft + 2 ".
00491 "ELSE lft ".
00492 "END, ".
00493 "rgt = CASE ".
00494 "WHEN rgt > ".$left." ".
00495 "THEN rgt + 2 ".
00496 "ELSE rgt ".
00497 "END ".
00498 "WHERE ".$this->tree_pk." = '".$this->tree_id."'";
00499 $this->ilDB->query($q);
00500
00501 if($this->__isMainTree())
00502 {
00503 ilDBx::_unlockTables();
00504 }
00505
00506 break;
00507
00508 case IL_LAST_NODE:
00509
00510 if($this->__isMainTree())
00511 {
00512 ilDBx::_lockTables(array('tree' => 'WRITE'));
00513 }
00514
00515
00516 $q = "SELECT * FROM ".$this->table_tree." ".
00517 "WHERE child = '".$a_parent_id."' ".
00518 "AND ".$this->tree_pk." = '".$this->tree_id."'";
00519 $res = $this->ilDB->query($q);
00520 $r = $res->fetchRow(DB_FETCHMODE_OBJECT);
00521
00522 if ($r->parent == NULL)
00523 {
00524 if($this->__isMainTree())
00525 {
00526 ilDBx::_unlockTables();
00527 }
00528 $this->ilErr->raiseError(get_class($this)."::insertNode(): Parent with ID ".
00529 $a_parent_id." not found in ".$this->table_tree."!",$this->ilErr->WARNING);
00530 }
00531
00532 $right = $r->rgt;
00533 $lft = $right;
00534 $rgt = $right + 1;
00535
00536
00537 $q = "UPDATE ".$this->table_tree." SET ".
00538 "lft = CASE ".
00539 "WHEN lft > ".$right." ".
00540 "THEN lft + 2 ".
00541 "ELSE lft ".
00542 "END, ".
00543 "rgt = CASE ".
00544 "WHEN rgt >= ".$right." ".
00545 "THEN rgt + 2 ".
00546 "ELSE rgt ".
00547 "END ".
00548 "WHERE ".$this->tree_pk." = '".$this->tree_id."'";
00549 $this->ilDB->query($q);
00550
00551 if($this->__isMainTree())
00552 {
00553 ilDBx::_unlockTables();
00554 }
00555
00556 break;
00557
00558 default:
00559
00560
00561 $q = "SELECT * FROM ".$this->table_tree." ".
00562 "WHERE child = '".$a_pos."' ".
00563 "AND ".$this->tree_pk." = '".$this->tree_id."'";
00564 $res = $this->ilDB->query($q);
00565 $r = $res->fetchRow(DB_FETCHMODE_OBJECT);
00566
00567
00568 if ($r->parent != $a_parent_id)
00569 {
00570 if($this->__isMainTree())
00571 {
00572 ilDBx::_unlockTables();
00573 }
00574 $this->ilErr->raiseError(get_class($this)."::insertNode(): Parents mismatch! ".
00575 "new node parent: ".$a_parent_id." sibling parent: ".$r->parent,$this->ilErr->WARNING);
00576 }
00577
00578 $right = $r->rgt;
00579 $lft = $right + 1;
00580 $rgt = $right + 2;
00581
00582
00583 $q = "UPDATE ".$this->table_tree." SET ".
00584 "lft = CASE ".
00585 "WHEN lft > ".$right." ".
00586 "THEN lft + 2 ".
00587 "ELSE lft ".
00588 "END, ".
00589 "rgt = CASE ".
00590 "WHEN rgt > ".$right." ".
00591 "THEN rgt + 2 ".
00592 "ELSE rgt ".
00593 "END ".
00594 "WHERE ".$this->tree_pk." = '".$this->tree_id."'";
00595 $this->ilDB->query($q);
00596 if($this->__isMainTree())
00597 {
00598 ilDBx::_unlockTables();
00599 }
00600
00601 break;
00602
00603 }
00604
00605
00606 $depth = $this->getDepth($a_parent_id) + 1;
00607
00608
00609 $q = "INSERT INTO ".$this->table_tree." (".$this->tree_pk.",child,parent,lft,rgt,depth) ".
00610 "VALUES ".
00611 "('".$this->tree_id."','".$a_node_id."','".$a_parent_id."','".$lft."','".$rgt."','".$depth."')";
00612
00613 $this->ilDB->query($q);
00614 }
00615
00623 function getSubTree($a_node)
00624 {
00625 if (!is_array($a_node))
00626 {
00627 $this->ilErr->raiseError(get_class($this)."::getSubTree(): Wrong datatype for node_data! ",$this->ilErr->WARNING);
00628 }
00629 if($a_node['lft'] < 1 or $a_node['rgt'] < 2)
00630 {
00631 $message = sprintf('%s::getSubTree(): Invalid node given! $a_node["lft"]: %s $a_node["rgt"]: %s',
00632 get_class($this),
00633 $a_node['lft'],
00634 $a_node['rgt']);
00635
00636 $this->log->write($message,$this->log->FATAL);
00637 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00638 }
00639
00640 $subtree = array();
00641
00642 $q = "SELECT * FROM ".$this->table_tree." ".
00643 $this->buildJoin().
00644 "WHERE ".$this->table_tree.".lft BETWEEN '".$a_node["lft"]."' AND '".$a_node["rgt"]."' ".
00645 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."' ".
00646 "ORDER BY ".$this->table_tree.".lft";
00647
00648 $r = $this->ilDB->query($q);
00649
00650 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
00651 {
00652 $subtree[] = $this->fetchNodeData($row);
00653 }
00654
00655 return $subtree ? $subtree : array();
00656 }
00657
00666 function getSubTreeTypes($a_node,$a_filter = 0)
00667 {
00668 $a_filter = $a_filter ? $a_filter : array();
00669
00670 foreach($this->getSubtree($this->getNodeData($a_node)) as $node)
00671 {
00672 if(in_array($node["type"],$a_filter))
00673 {
00674 continue;
00675 }
00676 $types["$node[type]"] = $node["type"];
00677 }
00678 return $types ? $types : array();
00679 }
00680
00686 function deleteTree($a_node)
00687 {
00688 if (!is_array($a_node))
00689 {
00690 $this->ilErr->raiseError(get_class($this)."::deleteTree(): Wrong datatype for node_data! ",$this->ilErr->WARNING);
00691 }
00692 if($this->__isMainTree() and $a_node[$this->tree_pk] === 1)
00693 {
00694 if($a_node['lft'] <= 1 or $a_node['rgt'] <= 2)
00695 {
00696 $message = sprintf('%s::deleteTree(): Invalid parameters given: $a_node["lft"]: %s, $a_node["rgt"] %s',
00697 get_class($this),
00698 $a_node['lft'],
00699 $a_node['rgt']);
00700
00701 $this->log->write($message,$this->log->FATAL);
00702 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00703 }
00704 else if(!$this->__checkDelete($a_node))
00705 {
00706 $message = sprintf('%s::deleteTree(): Check delete failed: $a_node["lft"]: %s, $a_node["rgt"] %s',
00707 get_class($this),
00708 $a_node['lft'],
00709 $a_node['rgt']);
00710 $this->log->write($message,$this->log->FATAL);
00711 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00712 }
00713
00714 }
00715 $diff = $a_node["rgt"] - $a_node["lft"] + 1;
00716
00717
00718
00719
00720 if($this->__isMainTree())
00721 {
00722 ilDBx::_lockTables(array('tree' => 'WRITE'));
00723 }
00724
00725 $query = "SELECT * FROM ".$this->table_tree." ".
00726 "WHERE child = '".$a_node['child']."' ".
00727 "AND ".$this->tree_pk." = '".$a_node[$this->tree_pk]."'";
00728
00729 $res = $this->ilDB->query($query);
00730 while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
00731 {
00732 $a_node['lft'] = $row->lft;
00733 $a_node['rgt'] = $row->rgt;
00734 $diff = $a_node["rgt"] - $a_node["lft"] + 1;
00735 }
00736
00737
00738 $q = "DELETE FROM ".$this->table_tree." ".
00739 "WHERE lft BETWEEN '".$a_node["lft"]."' AND '".$a_node["rgt"]."' ".
00740 "AND rgt BETWEEN '".$a_node["lft"]."' AND '".$a_node["rgt"]."' ".
00741 "AND ".$this->tree_pk." = '".$a_node[$this->tree_pk]."'";
00742 $this->ilDB->query($q);
00743
00744
00745 $q = "UPDATE ".$this->table_tree." SET ".
00746 "lft = CASE ".
00747 "WHEN lft > '".$a_node["lft"]." '".
00748 "THEN lft - '".$diff." '".
00749 "ELSE lft ".
00750 "END, ".
00751 "rgt = CASE ".
00752 "WHEN rgt > '".$a_node["lft"]." '".
00753 "THEN rgt - '".$diff." '".
00754 "ELSE rgt ".
00755 "END ".
00756 "WHERE ".$this->tree_pk." = '".$a_node[$this->tree_pk]."'";
00757 $this->ilDB->query($q);
00758
00759 if($this->__isMainTree())
00760 {
00761 ilDBx::_unlockTables();
00762 }
00763
00764 }
00765
00774 function fetchPath ($a_endnode_id, $a_startnode_id)
00775 {
00776 if ($this->table_obj_reference)
00777 {
00778 $leftjoin = "LEFT JOIN ".$this->table_obj_reference." ON T2.child=".$this->table_obj_reference.".".$this->ref_pk." ".
00779 "LEFT JOIN ".$this->table_obj_data." ON ".$this->table_obj_reference.".".$this->obj_pk."=".
00780 $this->table_obj_data.".".$this->obj_pk." ";
00781 $select_obj_id = $this->table_obj_data.".obj_id,";
00782 }
00783 else
00784 {
00785 $leftjoin = "LEFT JOIN ".$this->table_obj_data." ON T2.child=".$this->table_obj_data.".".$this->obj_pk." ";
00786 }
00787
00788 $q = "SELECT ".$select_obj_id.$this->table_obj_data.".title,".$this->table_obj_data.".type,T2.child,(T2.rgt - T2.lft) AS sort_col ".
00789 "FROM ".$this->table_tree." AS T1, ".$this->table_tree." AS T2, ".$this->table_tree." AS T3 ".
00790 $leftjoin.
00791 "WHERE T1.child = '".$a_startnode_id."' ".
00792 "AND T3.child = '".$a_endnode_id."' ".
00793 "AND T2.lft BETWEEN T1.lft AND T1.rgt ".
00794 "AND T3.lft BETWEEN T2.lft AND T2.rgt ".
00795 "AND T1.".$this->tree_pk." = '".$this->tree_id." '".
00796 "AND T2.".$this->tree_pk." = '".$this->tree_id." '".
00797 "AND T3.".$this->tree_pk." = '".$this->tree_id." '".
00798 "ORDER BY sort_col DESC";
00799
00800 $r = $this->ilDB->query($q);
00801 if ($r->numRows() > 0)
00802 {
00803 return $r;
00804 }
00805 else
00806 {
00807
00808 $this->ilErr->raiseError(get_class($this)."::fetchPath: No path found! startnode_id:".$a_startnode_id.", endnode_id:".$a_endnode_id,$this->ilErr->WARNING);
00809 }
00810 }
00811
00820 function getPathFull ($a_endnode_id, $a_startnode_id = 0)
00821 {
00822 if (!isset($a_endnode_id))
00823 {
00824 $this->ilErr->raiseError(get_class($this)."::getPathFull(): No endnode_id given! ",$this->ilErr->WARNING);
00825 }
00826
00827 if (empty($a_startnode_id))
00828 {
00829 $a_startnode_id = $this->root_id;
00830 }
00831
00832 $r = $this->fetchPath($a_endnode_id, $a_startnode_id);
00833
00834 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
00835 {
00836 $path[] = $this->fetchNodeData($row);
00837 }
00838
00839 return $path ? $path : array();
00840 }
00841
00850 function getPathId ($a_endnode_id, $a_startnode_id = 0)
00851 {
00852 if (!isset($a_endnode_id))
00853 {
00854 $this->ilErr->raiseError(get_class($this)."::getPathId(): No endnode_id given! ",$this->ilErr->WARNING);
00855 }
00856
00857
00858 if ($a_startnode_id == 0)
00859 {
00860 $a_startnode_id = $this->root_id;
00861 }
00862
00863 $r = $this->fetchPath($a_endnode_id, $a_startnode_id);
00864
00865 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00866 {
00867 $arr[] = $row->child;
00868 }
00869
00870 return $arr;
00871 }
00872
00879 function checkTree()
00880 {
00881 $q = "SELECT lft,rgt FROM ".$this->table_tree." ".
00882 "WHERE ".$this->tree_pk." = '".$this->tree_id."'";
00883
00884 $r = $this->ilDB->query($q);
00885
00886 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00887 {
00888 $lft[] = $row->lft;
00889 $rgt[] = $row->rgt;
00890 }
00891
00892 $all = array_merge($lft,$rgt);
00893 $uni = array_unique($all);
00894
00895 if (count($all) != count($uni))
00896 {
00897 $message = sprintf('%s::checkTree(): Tree is corrupted!',
00898 get_class($this));
00899
00900 $this->log->write($message,$this->log->FATAL);
00901 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00902 }
00903
00904 return true;
00905 }
00906
00910 function checkTreeChilds($a_no_zero_child = true)
00911 {
00912 $q = "SELECT * FROM ".$this->table_tree." ".
00913 "WHERE ".$this->tree_pk." = '".$this->tree_id."' ".
00914 "ORDER BY lft";
00915 $r1 = $this->ilDB->query($q);
00916 while ($row = $r1->fetchRow(DB_FETCHMODE_ASSOC))
00917 {
00918
00919 if (($row["child"] == 0) && $a_no_zero_child)
00920 {
00921 $this->ilErr->raiseError(get_class($this)."::checkTreeChilds(): Tree contains child with ID 0!",$this->ilErr->WARNING);
00922 }
00923
00924 if ($this->table_obj_reference)
00925 {
00926
00927 $q = "SELECT * FROM ".$this->table_obj_reference." WHERE ".$this->ref_pk."='".$row["child"]."'";
00928 $r2 = $this->ilDB->query($q);
00929
00930 if ($r2->numRows() == 0)
00931 {
00932 $this->ilErr->raiseError(get_class($this)."::checkTree(): No Object-to-Reference entry found for ID ".
00933 $row["child"]."!",$this->ilErr->WARNING);
00934 }
00935 if ($r2->numRows() > 1)
00936 {
00937 $this->ilErr->raiseError(get_class($this)."::checkTree(): More Object-to-Reference entries found for ID ".
00938 $row["child"]."!",$this->ilErr->WARNING);
00939 }
00940
00941
00942 $obj_ref = $r2->fetchRow(DB_FETCHMODE_ASSOC);
00943
00944 $q = "SELECT * FROM ".$this->table_obj_data." WHERE ".$this->obj_pk."='".$obj_ref[$this->obj_pk]."'";
00945 $r3 = $this->ilDB->query($q);
00946 if ($r3->numRows() == 0)
00947 {
00948 $this->ilErr->raiseError(get_class($this)."::checkTree(): No child found for ID ".
00949 $obj_ref[$this->obj_pk]."!",$this->ilErr->WARNING);
00950 }
00951 if ($r3->numRows() > 1)
00952 {
00953 $this->ilErr->raiseError(get_class($this)."::checkTree(): More childs found for ID ".
00954 $obj_ref[$this->obj_pk]."!",$this->ilErr->WARNING);
00955 }
00956
00957 }
00958 else
00959 {
00960
00961 $q = "SELECT * FROM ".$this->table_obj_data." WHERE ".$this->obj_pk."='".$row["child"]."'";
00962 $r2 = $this->ilDB->query($q);
00963
00964 if ($r2->numRows() == 0)
00965 {
00966 $this->ilErr->raiseError(get_class($this)."::checkTree(): No child found for ID ".
00967 $row["child"]."!",$this->ilErr->WARNING);
00968 }
00969 if ($r2->numRows() > 1)
00970 {
00971 $this->ilErr->raiseError(get_class($this)."::checkTree(): More childs found for ID ".
00972 $row["child"]."!",$this->ilErr->WARNING);
00973 }
00974 }
00975 }
00976
00977 return true;
00978 }
00979
00985 function getMaximumDepth()
00986 {
00987 $q = "SELECT MAX(depth) FROM ".$this->table_tree;
00988 $r = $this->ilDB->query($q);
00989
00990 $row = $r->fetchRow();
00991
00992 return $row[0];
00993 }
00994
01001 function getDepth($a_node_id)
01002 {
01003 if ($a_node_id)
01004 {
01005 $q = "SELECT depth FROM ".$this->table_tree." ".
01006 "WHERE child = '".$a_node_id."' ".
01007 "AND ".$this->tree_pk." = '".$this->tree_id."'";
01008
01009 $res = $this->ilDB->query($q);
01010 $row = $res->fetchRow(DB_FETCHMODE_OBJECT);
01011
01012 return $row->depth;
01013 }
01014 else
01015 {
01016 return 1;
01017 }
01018 }
01019
01030 function calculateFlatTree()
01031 {
01032 if ($this->table_obj_reference)
01033 {
01034 $leftjoin = "LEFT JOIN ".$this->table_obj_reference." ON s.child=".$this->table_obj_reference.".".$this->ref_pk." ".
01035 "LEFT JOIN ".$this->table_obj_data." ON ".$this->table_obj_reference.".".$this->obj_pk."=".$this->table_obj_data.".".$this->obj_pk." ";
01036 }
01037 else
01038 {
01039 $leftjoin = "LEFT JOIN ".$this->table_obj_data." ON s.child=".$this->table_obj_data.".".$this->obj_pk." ";
01040
01041 }
01042
01043 $q = "SELECT s.child,s.parent,s.lft,s.rgt,title,s.depth,".
01044 "(s.rgt-s.lft-1)/2 AS successor,".
01045 "((min(v.rgt)-s.rgt-(s.lft>1))/2) > 0 AS brother ".
01046 "FROM ".$this->table_tree." v, ".$this->table_tree." s ".
01047 $leftjoin.
01048 "WHERE s.lft BETWEEN v.lft AND v.rgt ".
01049 "AND (v.child != s.child OR s.lft = '1') ".
01050 "AND s.".$this->tree_pk." = '".$this->tree_id."' ".
01051 "AND v.".$this->tree_pk." = '".$this->tree_id."' ".
01052 "GROUP BY s.child ".
01053 "ORDER BY s.lft";
01054 $r = $this->ilDB->query($q);
01055
01056 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
01057 {
01058 $arr[] = array(
01059 "title" => $row->title,
01060 "child" => $row->child,
01061 "successor" => $row->successor,
01062 "depth" => $row->depth,
01063 "brother" => $row->brother,
01064 "lft" => $row->lft,
01065 "rgt" => $row->rgt
01066 );
01067 }
01068
01069 return $arr;
01070 }
01071
01079 function getNodeData($a_node_id)
01080 {
01081 if (!isset($a_node_id))
01082 {
01083 $this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
01084 }
01085 if($this->__isMainTree())
01086 {
01087 if($a_node_id < 1)
01088 {
01089 $message = sprintf('%s::getNodeData(): No valid parameter given! $a_node_id: %s',
01090 get_class($this),
01091 $a_node_id);
01092
01093 $this->log->write($message,$this->log->FATAL);
01094 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01095 }
01096 }
01097
01098 $q = "SELECT * FROM ".$this->table_tree." ".
01099 $this->buildJoin().
01100 "WHERE ".$this->table_tree.".child = '".$a_node_id."' ".
01101 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01102 $r = $this->ilDB->query($q);
01103 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01104 $row[$this->tree_pk] = $this->tree_id;
01105
01106 return $this->fetchNodeData($row);
01107 }
01108
01116 function fetchNodeData($a_row)
01117 {
01118 global $objDefinition, $lng;
01119
01120 $data = $a_row;
01121 $data["desc"] = $a_row["description"];
01122
01123
01124 if (is_object($objDefinition))
01125 {
01126 $translation_type = $objDefinition->getTranslationType($data["type"]);
01127 }
01128
01129 if ($translation_type == "sys")
01130 {
01131 if ($data["type"] == "rolf" and $data["obj_id"] != ROLE_FOLDER_ID)
01132 {
01133 $data["description"] = $lng->txt("obj_".$data["type"]."_local_desc").$data["title"].$data["desc"];
01134 $data["desc"] = $lng->txt("obj_".$data["type"]."_local_desc").$data["title"].$data["desc"];
01135 $data["title"] = $lng->txt("obj_".$data["type"]."_local");
01136 }
01137 else
01138 {
01139 $data["title"] = $lng->txt("obj_".$data["type"]);
01140 $data["description"] = $lng->txt("obj_".$data["type"]."_desc");
01141 $data["desc"] = $lng->txt("obj_".$data["type"]."_desc");
01142 }
01143 }
01144 elseif ($translation_type == "db")
01145 {
01146 $q = "SELECT title,description FROM object_translation ".
01147 "WHERE obj_id = ".$data["obj_id"]." ".
01148 "AND lang_code = '".$this->lang_code."' ".
01149 "AND NOT lang_default = 1";
01150 $r = $this->ilDB->query($q);
01151
01152 $row = $r->fetchRow(DB_FETCHMODE_OBJECT);
01153
01154 if ($row)
01155 {
01156 $data["title"] = $row->title;
01157 $data["description"] = $row->description;
01158 $data["desc"] = $row->description;
01159 }
01160 }
01161
01162 $data["title"] = ilUtil::stripSlashes($data["title"]);
01163 $data["description"] = ilUtil::stripSlashes($data["description"]);
01164 $data["desc"] = ilUtil::stripSlashes($data["desc"]);
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184 return $data ? $data : array();
01185 }
01186
01187
01195 function isInTree($a_node_id)
01196 {
01197 if (!isset($a_node_id))
01198 {
01199 return false;
01200 #$this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
01201 }
01202
01203 $q = "SELECT * FROM ".$this->table_tree." ".
01204 "WHERE ".$this->table_tree.".child = '".$a_node_id."' ".
01205 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01206 $r = $this->ilDB->query($q);
01207
01208 if ($r->numRows() > 0)
01209 {
01210 return true;
01211 }
01212 else
01213 {
01214 return false;
01215 }
01216
01217 }
01218
01225 function getParentNodeData($a_node_id)
01226 {
01227 if (!isset($a_node_id))
01228 {
01229 $this->ilErr->raiseError(get_class($this)."::getParentNodeData(): No node_id given! ",$this->ilErr->WARNING);
01230 }
01231
01232 if ($this->table_obj_reference)
01233 {
01234 $leftjoin = "LEFT JOIN ".$this->table_obj_reference." ON v.child=".$this->table_obj_reference.".".$this->ref_pk." ".
01235 "LEFT JOIN ".$this->table_obj_data." ON ".$this->table_obj_reference.".".$this->obj_pk."=".$this->table_obj_data.".".$this->obj_pk." ";
01236 }
01237 else
01238 {
01239 $leftjoin = "LEFT JOIN ".$this->table_obj_data." ON v.child=".$this->table_obj_data.".".$this->obj_pk." ";
01240 }
01241
01242 $q = "SELECT * FROM ".$this->table_tree." s,".$this->table_tree." v ".
01243 $leftjoin.
01244 "WHERE s.child = '".$a_node_id."' ".
01245 "AND s.parent = v.child ".
01246 "AND s.lft > v.lft ".
01247 "AND s.rgt < v.rgt ".
01248 "AND s.".$this->tree_pk." = '".$this->tree_id."' ".
01249 "AND v.".$this->tree_pk." = '".$this->tree_id."'";
01250 $r = $this->ilDB->query($q);
01251
01252 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01253
01254 return $this->fetchNodeData($row);
01255 }
01256
01264 function isGrandChild($a_startnode_id,$a_querynode_id)
01265 {
01266 if (!isset($a_startnode_id) or !isset($a_querynode_id))
01267 {
01268 $this->ilErr->raiseError(get_class($this)."::isGrandChild(): Missing parameter! startnode: ".$a_startnode_id." querynode: ".
01269 $a_querynode_id,$this->ilErr->WARNING);
01270 }
01271
01272 $q = "SELECT * FROM ".$this->table_tree." s,".$this->table_tree." v ".
01273 "WHERE s.child = '".$a_startnode_id."' ".
01274 "AND v.child = '".$a_querynode_id."' ".
01275 "AND s.".$this->tree_pk." = '".$this->tree_id."' ".
01276 "AND v.".$this->tree_pk." = '".$this->tree_id."' ".
01277 "AND v.lft BETWEEN s.lft AND s.rgt ".
01278 "AND v.rgt BETWEEN s.lft AND s.rgt";
01279 $r = $this->ilDB->query($q);
01280
01281 return $r->numRows();
01282 }
01283
01292 function addTree($a_tree_id,$a_node_id = -1)
01293 {
01294
01295
01296 if($this->__isMainTree())
01297 {
01298 $message = sprintf('%s::addTree(): Operation not allowed on main tree! $a_tree_if: %s $a_node_id: %s',
01299 get_class($this),
01300 $a_tree_id,
01301 $a_node_id);
01302 $this->log->write($message,$this->log->FATAL);
01303 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01304 }
01305
01306 if (!isset($a_tree_id))
01307 {
01308 $this->ilErr->raiseError(get_class($this)."::addTree(): No tree_id given! ",$this->ilErr->WARNING);
01309 }
01310
01311 if ($a_node_id <= 0)
01312 {
01313 $a_node_id = $a_tree_id;
01314 }
01315
01316 $q = "INSERT INTO ".$this->table_tree." (".$this->tree_pk.", child, parent, lft, rgt, depth) ".
01317 "VALUES ".
01318 "('".$a_tree_id."','".$a_node_id."', 0, 1, 2, 1)";
01319
01320 $this->ilDB->query($q);
01321
01322 return true;
01323 }
01324
01332 function getNodeDataByType($a_type)
01333 {
01334 if (!isset($a_type) or (!is_string($a_type)))
01335 {
01336 $this->ilErr->raiseError(get_class($this)."::getNodeDataByType(): Type not given or wrong datatype!",$this->ilErr->WARNING);
01337 }
01338
01339 $data = array();
01340 $row = "";
01341 $left = "";
01342 $right = "";
01343
01344 $q = "SELECT * FROM ".$this->table_tree." ".
01345 "WHERE ".$this->tree_pk." = '".$this->tree_id."'".
01346 "AND parent = '0'";
01347 $r = $this->ilDB->query($q);
01348
01349 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
01350 {
01351 $left = $row->lft;
01352 $right = $row->rgt;
01353 }
01354
01355 $q = "SELECT * FROM ".$this->table_tree." ".
01356 $this->buildJoin().
01357 "WHERE ".$this->table_obj_data.".type = '".$a_type."' ".
01358 "AND ".$this->table_tree.".lft BETWEEN '".$left."' AND '".$right."' ".
01359 "AND ".$this->table_tree.".rgt BETWEEN '".$left."' AND '".$right."' ".
01360 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01361 $r = $this->ilDB->query($q);
01362
01363 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
01364 {
01365 $data[] = $this->fetchNodeData($row);
01366 }
01367
01368 return $data;
01369 }
01370
01378 function removeTree($a_tree_id)
01379 {
01380
01381 if($this->__isMainTree())
01382 {
01383 $message = sprintf('%s::removeTree(): Operation not allowed on main tree! $a_tree_if: %s',
01384 get_class($this),
01385 $a_tree_id);
01386 $this->log->write($message,$this->log->FATAL);
01387 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01388 }
01389 if (!$a_tree_id)
01390 {
01391 $this->ilErr->raiseError(get_class($this)."::removeTree(): No tree_id given! Action aborted",$this->ilErr->MESSAGE);
01392 }
01393
01394 $q = "DELETE FROM ".$this->table_tree." WHERE ".$this->tree_pk." = '".$a_tree_id."'";
01395 $this->ilDB->query($q);
01396
01397 return true;
01398 }
01399
01407 function saveSubTree($a_node_id)
01408 {
01409 if (!$a_node_id)
01410 {
01411 $message = sprintf('%s::saveSubTree(): No valid parameter given! $a_node_id: %s',
01412 get_class($this),
01413 $a_node_id);
01414 $this->log->write($message,$this->log->FATAL);
01415 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01416 }
01417
01418
01419 if($this->__isMainTree())
01420 {
01421 ilDBx::_lockTables(array('tree' => 'WRITE'));
01422 }
01423
01424
01425 $q = "SELECT * FROM ".$this->table_tree." ".
01426 "WHERE ".$this->tree_pk." = '".$this->tree_id."' ".
01427 "AND child = '".$a_node_id."' ";
01428 $r = $this->ilDB->query($q);
01429
01430 while($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
01431 {
01432 $lft = $row->lft;
01433 $rgt = $row->rgt;
01434 }
01435
01436
01437 $q = "SELECT * FROM ".$this->table_tree." ".
01438 "WHERE ".$this->tree_pk." = '".$this->tree_id."' ".
01439 "AND lft >= '".$lft."' ".
01440 "AND rgt <= '".$rgt."'";
01441 $r = $this->ilDB->query($q);
01442
01443 while($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
01444 {
01445 $subnodes[$row["child"]] = $this->fetchNodeData($row);
01446 }
01447
01448
01449 foreach($subnodes as $node)
01450 {
01451 $q = "INSERT INTO ".$this->table_tree." ".
01452 "VALUES ('".-$a_node_id."','".$node["child"]."','".$node["parent"]."','".
01453 $node["lft"]."','".$node["rgt"]."','".$node["depth"]."')";
01454 $r = $this->ilDB->query($q);
01455 }
01456 if($this->__isMainTree())
01457 {
01458 ilDBX::_unlockTables();
01459 }
01460
01461
01462 return true;
01463 }
01464
01468 function isSaved($a_node_id)
01469 {
01470 $q = "SELECT * FROM ".$this->table_tree." ".
01471 "WHERE child = '".$a_node_id."'";
01472 $s = $this->ilDB->query($q);
01473 $r = $s->fetchRow(DB_FETCHMODE_ASSOC);
01474
01475 if ($r[$this->tree_pk] < 0)
01476 {
01477 return true;
01478 }
01479 else
01480 {
01481 return false;
01482 }
01483 }
01484
01485
01494 function saveNode($a_node_id,$a_parent_id)
01495 {
01496 if($this->__isMainTree())
01497 {
01498 if($a_node_id <= 1 or $a_parent_id <= 0)
01499 {
01500 $message = sprintf('%s::saveSubTree(): No valid parameter given! $a_node_id: %s $a_parent_id: %s',
01501 get_class($this),
01502 $a_node_id,
01503 $a_parent_id);
01504
01505 $this->log->write($message,$this->log->FATAL);
01506 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01507 }
01508 }
01509 if ($a_node_id < 1 or !isset($a_parent_id))
01510 {
01511 $this->ilErr->raiseError(get_class($this)."::saveNode(): Missing parameter! ".
01512 "node_id: ".$a_node_id." parent_id: ".$a_parent_id,$this->ilErr->WARNING);
01513 }
01514
01515
01516 $q = "INSERT INTO ".$this->table_tree." ".
01517 "VALUES ('".-$a_node_id."','".$a_node_id."','".$a_parent_id."','1','2','1')";
01518 $r = $this->ilDB->query($q);
01519
01520 return true;
01521 }
01522
01529 function getSavedNodeData($a_parent_id)
01530 {
01531 if (!isset($a_parent_id))
01532 {
01533 $this->ilErr->raiseError(get_class($this)."::getSavedNodeData(): No node_id given!",$this->ilErr->WARNING);
01534 }
01535
01536 $q = "SELECT * FROM ".$this->table_tree." ".
01537 $this->buildJoin().
01538 "WHERE ".$this->table_tree.".".$this->tree_pk." < 0 ".
01539 "AND ".$this->table_tree.".parent = '".$a_parent_id."' ";
01540 $r = $this->ilDB->query($q);
01541
01542 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
01543 {
01544 $saved[] = $this->fetchNodeData($row);
01545 }
01546
01547 return $saved ? $saved : array();
01548 }
01549
01556 function getParentId($a_node_id)
01557 {
01558 if (!isset($a_node_id))
01559 {
01560 $this->ilErr->raiseError(get_class($this)."::getParentId(): No node_id given! ",$this->ilErr->WARNING);
01561 }
01562
01563 $q = "SELECT parent FROM ".$this->table_tree." ".
01564 "WHERE child='".$a_node_id."' ".
01565 "AND ".$this->tree_pk."='".$this->tree_id."'";
01566 $r = $this->ilDB->query($q);
01567
01568 $row = $r->fetchRow(DB_FETCHMODE_OBJECT);
01569
01570 return $row->parent;
01571 }
01572
01579 function getChildSequenceNumber($a_node, $type = "")
01580 {
01581 if (!isset($a_node))
01582 {
01583 $this->ilErr->raiseError(get_class($this)."::getChildSequenceNumber(): No node_id given! ",$this->ilErr->WARNING);
01584 }
01585
01586 $type_str = ($type != "")
01587 ? "AND type='$type'"
01588 : "";
01589
01590 $q = "SELECT count(*) AS cnt FROM ".$this->table_tree." ".
01591 $this->buildJoin().
01592 "WHERE lft <=".$this->ilDB->quote($a_node["lft"])." ".
01593 $type_str.
01594 "AND parent=".$this->ilDB->quote($a_node["parent"])." ".
01595 "AND ".$this->table_tree.".".$this->tree_pk."=".$this->ilDB->quote($this->tree_id);
01596 $r = $this->ilDB->query($q);
01597
01598 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01599
01600 return $row["cnt"];
01601 }
01602
01609 function readRootId()
01610 {
01611 $query = "SELECT child FROM $this->table_tree ".
01612 "WHERE parent = '0'".
01613 "AND ".$this->tree_pk." = '".$this->tree_id."'";
01614 $row = $this->ilDB->getRow($query,DB_FETCHMODE_OBJECT);
01615
01616 $this->root_id = $row->child;
01617 return $this->root_id;
01618 }
01619
01625 function getRootId()
01626 {
01627 return $this->root_id;
01628 }
01629 function setRootId($a_root_id)
01630 {
01631 $this->root_id = $a_root_id;
01632 }
01633
01639 function getTreeId()
01640 {
01641 return $this->tree_id;
01642 }
01643
01649 function setTreeId($a_tree_id)
01650 {
01651 $this->tree_id = $a_tree_id;
01652 }
01653
01661 function fetchSuccessorNode($a_node_id, $a_type = "")
01662 {
01663 if (!isset($a_node_id))
01664 {
01665 $this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
01666 }
01667
01668
01669 $q = "SELECT lft FROM ".$this->table_tree." ".
01670 "WHERE ".$this->table_tree.".child = '".$a_node_id."' ".
01671 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01672 $r = $this->ilDB->query($q);
01673 $curr_node = $r->fetchRow(DB_FETCHMODE_ASSOC);
01674
01675
01676 $type_where = ($a_type != "")
01677 ? "AND ".$this->table_obj_data.".type = '$a_type' "
01678 : "";
01679 $q = "SELECT * FROM ".$this->table_tree." ".
01680 $this->buildJoin().
01681 "WHERE lft > '".$curr_node["lft"]."' ".
01682 $type_where.
01683 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'".
01684 "ORDER BY lft LIMIT 1";
01685 $r = $this->ilDB->query($q);
01686
01687 if ($r->numRows() < 1)
01688 {
01689 return false;
01690 }
01691 else
01692 {
01693 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01694 return $this->fetchNodeData($row);
01695 }
01696 }
01697
01705 function fetchPredecessorNode($a_node_id, $a_type = "")
01706 {
01707 if (!isset($a_node_id))
01708 {
01709 $this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
01710 }
01711
01712
01713 $q = "SELECT lft FROM ".$this->table_tree." ".
01714 "WHERE ".$this->table_tree.".child = '".$a_node_id."' ".
01715 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01716 $r = $this->ilDB->query($q);
01717 $curr_node = $r->fetchRow(DB_FETCHMODE_ASSOC);
01718
01719
01720 $type_where = ($a_type != "")
01721 ? "AND ".$this->table_obj_data.".type = '$a_type' "
01722 : "";
01723 $q = "SELECT * FROM ".$this->table_tree." ".
01724 $this->buildJoin().
01725 "WHERE lft < '".$curr_node["lft"]."' ".
01726 $type_where.
01727 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'".
01728 "ORDER BY lft DESC LIMIT 1";
01729 $r = $this->ilDB->query($q);
01730
01731 if ($r->numRows() < 1)
01732 {
01733 return false;
01734 }
01735 else
01736 {
01737 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01738 return $this->fetchNodeData($row);
01739 }
01740 }
01741
01750 function renumber($node_id = 1, $i = 1)
01751 {
01752
01753 if($this->__isMainTree())
01754 {
01755 ilDBx::_lockTables(array($this->table_tree => 'WRITE',
01756 $this->table_obj_data => 'WRITE',
01757 $this->table_obj_reference => 'WRITE',
01758 'object_translation' => 'WRITE'));
01759 }
01760 $return = $this->__renumber($node_id,$i);
01761 if($this->__isMainTree())
01762 {
01763 ilDBx::_unlockTables();
01764 }
01765
01766
01767 return $return;
01768 }
01769
01770
01780 function __renumber($node_id = 1, $i = 1)
01781 {
01782 $q = "UPDATE ".$this->table_tree." SET lft='".$i."' WHERE child='".$node_id."'";
01783 $this->ilDB->query($q);
01784
01785 $childs = $this->getChilds($node_id);
01786
01787 foreach ($childs as $child)
01788 {
01789 $i = $this->__renumber($child["child"],$i+1);
01790 }
01791
01792 $i++;
01793 $q = "UPDATE ".$this->table_tree." SET rgt='".$i."' WHERE child='".$node_id."'";
01794 $this->ilDB->query($q);
01795
01796 return $i;
01797 }
01798
01799
01809 function checkForParentType($a_ref_id,$a_type)
01810 {
01811 if(!$this->isInTree($a_ref_id))
01812 {
01813 return false;
01814 }
01815 $path = array_reverse($this->getPathFull($a_ref_id));
01816
01817 foreach($path as $node)
01818 {
01819 if($node["type"] == $a_type)
01820 {
01821 return $node["child"];
01822 }
01823 }
01824 return 0;
01825 }
01826
01836 function _removeEntry($a_tree,$a_child,$a_db_table = "tree")
01837 {
01838 global $ilDB,$ilLog,$ilErr;
01839
01840 if($a_db_table === 'tree')
01841 {
01842 if($a_tree == 1 and $a_child == ROOT_FOLDER_ID)
01843 {
01844 $message = sprintf('%s::_removeEntry(): Tried to delete root node! $a_tree: %s $a_child: %s',
01845 get_class($this),
01846 $a_tree,
01847 $a_child);
01848 $ilLog->write($message,$ilLog->FATAL);
01849 $ilErr->raiseError($message,$ilErr->WARNING);
01850 }
01851 }
01852
01853 $q = "DELETE from ".$a_db_table." WHERE tree='".$a_tree."' AND child='".$a_child."'";
01854 $ilDB->query($q);
01855 }
01856
01857
01864 function __isMainTree()
01865 {
01866 return $this->table_tree === 'tree';
01867 }
01868
01877 function __checkDelete($a_node)
01878 {
01879
01880 $query = "SELECT * FROM ".$this->table_tree." ".
01881 "WHERE lft >= ".$a_node['lft']." ".
01882 "AND rgt <= ".$a_node['rgt']." ".
01883 "AND ".$this->tree_pk." = '".$a_node[$this->tree_pk]."'";
01884
01885
01886 $res = $this->ilDB->query($query);
01887
01888 $counter = (int) $lft_childs = array();
01889 while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
01890 {
01891 $lft_childs[$row->child] = $row->parent;
01892 ++$counter;
01893 }
01894
01895
01896 if($counter != count($lft_childs))
01897 {
01898 $message = sprintf('%s::__checkTree(): Duplicate entries for "child" in maintree! $a_node_id: %s',
01899 get_class($this),
01900 $a_node['child']);
01901 $this->log->write($message,$this->log->FATAL);
01902 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01903 }
01904
01905
01906 $parent_childs = array();
01907 $this->__getSubTreeByParentRelation($a_node['child'],$parent_childs);
01908 $this->__validateSubtrees($lft_childs,$parent_childs);
01909
01910 return true;
01911 }
01912
01913 function __getSubTreeByParentRelation($a_node_id,&$parent_childs)
01914 {
01915
01916 $query = "SELECT * FROM ".$this->table_tree." ".
01917 "WHERE child = '".$a_node_id."' ".
01918 "AND tree = '".$this->tree_id."'";
01919
01920 $res = $this->ilDB->query($query);
01921 $counter = 0;
01922 while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
01923 {
01924 $parent_childs[$a_node_id] = $row->parent;
01925 ++$counter;
01926 }
01927
01928 if($counter > 1)
01929 {
01930 $message = sprintf('%s::__getSubTreeByParentRelation(): Multiple entries in maintree! $a_node_id: %s',
01931 get_class($this),
01932 $a_node_id);
01933 $this->log->write($message,$this->log->FATAL);
01934 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01935 }
01936
01937
01938 $query = "SELECT * FROM ".$this->table_tree." ".
01939 "WHERE parent = '".$a_node_id."'";
01940
01941 $res = $this->ilDB->query($query);
01942 while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
01943 {
01944
01945 $this->__getSubTreeByParentRelation($row->child,$parent_childs);
01946 }
01947 return true;
01948 }
01949
01950 function __validateSubtrees(&$lft_childs,$parent_childs)
01951 {
01952
01953 ksort($lft_childs);
01954 ksort($parent_childs);
01955
01956 if(count($lft_childs) != count($parent_childs))
01957 {
01958 $message = sprintf('%s::__validateSubtrees(): (COUNT) Tree is corrupted! Left/Right subtree does not comply .'.
01959 'with parent relation',
01960 get_class($this));
01961 $this->log->write($message,$this->log->FATAL);
01962 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01963 }
01964
01965 foreach($lft_childs as $key => $value)
01966 {
01967 if($parent_childs[$key] != $value)
01968 {
01969 $message = sprintf('%s::__validateSubtrees(): (COMPARE) Tree is corrupted! Left/Right subtree does not comply '.
01970 'with parent relation',
01971 get_class($this));
01972 $this->log->write($message,$this->log->FATAL);
01973 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01974 }
01975 if($key == ROOT_FOLDER_ID)
01976 {
01977 $message = sprintf('%s::__validateSubtrees(): (ROOT_FOLDER) Tree is corrupted! Tried to delete root folder',
01978 get_class($this));
01979 $this->log->write($message,$this->log->FATAL);
01980 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01981 }
01982 }
01983 return true;
01984 }
01985
01986 }
01987 ?>