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 global $ilBench;
00303
00304 if (!isset($a_node_id))
00305 {
00306 $message = get_class($this)."::getChilds(): No node_id given!";
00307 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00308 }
00309
00310
00311 $childs = array();
00312
00313
00314 $count = 0;
00315
00316
00317 $order_clause = "";
00318
00319
00320 if (!empty($a_order))
00321 {
00322 $order_clause = "ORDER BY ".$a_order." ".$a_direction;
00323 }
00324 else
00325 {
00326 $order_clause = "ORDER BY ".$this->table_tree.".lft";
00327 }
00328
00329
00330 $q = "SELECT * FROM ".$this->table_tree." ".
00331 $this->buildJoin().
00332 "WHERE parent = '".$a_node_id."' ".
00333 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."' ".
00334 $order_clause;
00335
00336
00337 $r = $this->ilDB->query($q);
00338
00339
00340 $count = $r->numRows();
00341
00342
00343 if ($count > 0)
00344 {
00345
00346 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
00347 {
00348 $childs[] = $this->fetchNodeData($row);
00349 }
00350
00351
00352
00353 $childs[$count - 1]["last"] = true;
00354 return $childs;
00355 }
00356 else
00357 {
00358 return $childs;
00359 }
00360 }
00361
00371 function getFilteredChilds($a_filter,$a_node,$a_order = "",$a_direction = "ASC")
00372 {
00373 $childs = $this->getChilds($a_node,$a_order,$a_direction);
00374
00375 foreach($childs as $child)
00376 {
00377 if(!in_array($child["type"],$a_filter))
00378 {
00379 $filtered[] = $child;
00380 }
00381 }
00382 return $filtered ? $filtered : array();
00383 }
00384
00385
00393 function getChildsByType($a_node_id,$a_type)
00394 {
00395 if (!isset($a_node_id) or !isset($a_type))
00396 {
00397 $message = get_class($this)."::getChildsByType(): Missing parameter! node_id:".$a_node_id." type:".$a_type;
00398 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00399 }
00400
00401
00402 $childs = array();
00403
00404 $q = "SELECT * FROM ".$this->table_tree." ".
00405 $this->buildJoin().
00406 "WHERE parent = '".$a_node_id."' ".
00407 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."' ".
00408 "AND ".$this->table_obj_data.".type='".$a_type."' ".
00409 "ORDER BY ".$this->table_tree.".lft";
00410 $r = $this->ilDB->query($q);
00411
00412 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
00413 {
00414 $childs[] = $this->fetchNodeData($row);
00415 }
00416
00417
00418 return $childs;
00419 }
00420
00421
00429 function insertNode($a_node_id, $a_parent_id, $a_pos = IL_LAST_NODE)
00430 {
00431
00432
00433 if($this->__isMainTree())
00434 {
00435 if($a_node_id <= 1 or $a_parent_id <= 0)
00436 {
00437 $message = sprintf('%s::insertNode(): Invalid parameters! $a_node_id: %s $a_parent_id: %s',
00438 get_class($this),
00439 $a_node_id,
00440 $a_parent_id);
00441 $this->log->write($message,$this->log->FATAL);
00442 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00443 }
00444 }
00445
00446
00447 if (!isset($a_node_id) or !isset($a_parent_id))
00448 {
00449 $this->ilErr->raiseError(get_class($this)."::insertNode(): Missing parameter! ".
00450 "node_id: ".$a_node_id." parent_id: ".$a_parent_id,$this->ilErr->WARNING);
00451 }
00452 if ($this->isInTree($a_node_id))
00453 {
00454 $this->ilErr->raiseError(get_class($this)."::insertNode(): Node ".$a_node_id." already in tree ".
00455 $this->table_tree."!",$this->ilErr->WARNING);
00456 }
00457
00458
00459
00460
00461
00462 switch ($a_pos)
00463 {
00464 case IL_FIRST_NODE:
00465
00466 if($this->__isMainTree())
00467 {
00468 ilDBx::_lockTables(array('tree' => 'WRITE'));
00469 }
00470
00471
00472 $q = "SELECT * FROM ".$this->table_tree." ".
00473 "WHERE child = '".$a_parent_id."' ".
00474 "AND ".$this->tree_pk." = '".$this->tree_id."'";
00475 $res = $this->ilDB->query($q);
00476 $r = $res->fetchRow(DB_FETCHMODE_OBJECT);
00477
00478 if ($r->parent == NULL)
00479 {
00480 if($this->__isMainTree())
00481 {
00482 ilDBx::_unlockTables();
00483 }
00484 $this->ilErr->raiseError(get_class($this)."::insertNode(): Parent with ID ".$a_parent_id." not found in ".
00485 $this->table_tree."!",$this->ilErr->WARNING);
00486 }
00487
00488 $left = $r->lft;
00489 $lft = $left + 1;
00490 $rgt = $left + 2;
00491
00492
00493 $q = "UPDATE ".$this->table_tree." SET ".
00494 "lft = CASE ".
00495 "WHEN lft > ".$left." ".
00496 "THEN lft + 2 ".
00497 "ELSE lft ".
00498 "END, ".
00499 "rgt = CASE ".
00500 "WHEN rgt > ".$left." ".
00501 "THEN rgt + 2 ".
00502 "ELSE rgt ".
00503 "END ".
00504 "WHERE ".$this->tree_pk." = '".$this->tree_id."'";
00505 $this->ilDB->query($q);
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 break;
00551
00552 default:
00553 if($this->__isMainTree())
00554 {
00555 ilDBx::_lockTables(array('tree' => 'WRITE'));
00556 }
00557
00558
00559 $q = "SELECT * FROM ".$this->table_tree." ".
00560 "WHERE child = '".$a_pos."' ".
00561 "AND ".$this->tree_pk." = '".$this->tree_id."'";
00562 $res = $this->ilDB->query($q);
00563 $r = $res->fetchRow(DB_FETCHMODE_OBJECT);
00564
00565
00566 if ($r->parent != $a_parent_id)
00567 {
00568 if($this->__isMainTree())
00569 {
00570 ilDBx::_unlockTables();
00571 }
00572 $this->ilErr->raiseError(get_class($this)."::insertNode(): Parents mismatch! ".
00573 "new node parent: ".$a_parent_id." sibling parent: ".$r->parent,$this->ilErr->WARNING);
00574 }
00575
00576 $right = $r->rgt;
00577 $lft = $right + 1;
00578 $rgt = $right + 2;
00579
00580
00581 $q = "UPDATE ".$this->table_tree." SET ".
00582 "lft = CASE ".
00583 "WHEN lft > ".$right." ".
00584 "THEN lft + 2 ".
00585 "ELSE lft ".
00586 "END, ".
00587 "rgt = CASE ".
00588 "WHEN rgt > ".$right." ".
00589 "THEN rgt + 2 ".
00590 "ELSE rgt ".
00591 "END ".
00592 "WHERE ".$this->tree_pk." = '".$this->tree_id."'";
00593 $this->ilDB->query($q);
00594 break;
00595
00596 }
00597
00598
00599 $depth = $this->getDepth($a_parent_id) + 1;
00600
00601
00602 $q = "INSERT INTO ".$this->table_tree." (".$this->tree_pk.",child,parent,lft,rgt,depth) ".
00603 "VALUES ".
00604 "('".$this->tree_id."','".$a_node_id."','".$a_parent_id."','".$lft."','".$rgt."','".$depth."')";
00605
00606 $this->ilDB->query($q);
00607
00608
00609 if($this->__isMainTree())
00610 {
00611 ilDBx::_unlockTables();
00612 }
00613
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
00777 if ($this->table_obj_reference)
00778 {
00779 $leftjoin = "LEFT JOIN ".$this->table_obj_reference." ON T2.child=".$this->table_obj_reference.".".$this->ref_pk." ".
00780 "LEFT JOIN ".$this->table_obj_data." ON ".$this->table_obj_reference.".".$this->obj_pk."=".
00781 $this->table_obj_data.".".$this->obj_pk." ";
00782 $select_obj_id = $this->table_obj_data.".obj_id,";
00783 }
00784 else
00785 {
00786 $leftjoin = "LEFT JOIN ".$this->table_obj_data." ON T2.child=".$this->table_obj_data.".".$this->obj_pk." ";
00787 }
00788
00789 $q = "SELECT ".$select_obj_id.$this->table_obj_data.".title,".$this->table_obj_data.".type,T2.child,(T2.rgt - T2.lft) AS sort_col ".
00790 "FROM ".$this->table_tree." AS T1, ".$this->table_tree." AS T2, ".$this->table_tree." AS T3 ".
00791 $leftjoin.
00792 "WHERE T1.child = '".$a_startnode_id."' ".
00793 "AND T3.child = '".$a_endnode_id."' ".
00794 "AND T2.lft BETWEEN T1.lft AND T1.rgt ".
00795 "AND T3.lft BETWEEN T2.lft AND T2.rgt ".
00796 "AND T1.".$this->tree_pk." = '".$this->tree_id." '".
00797 "AND T2.".$this->tree_pk." = '".$this->tree_id." '".
00798 "AND T3.".$this->tree_pk." = '".$this->tree_id." '".
00799 "ORDER BY sort_col DESC";
00800
00801 $r = $this->ilDB->query($q);
00802
00803 if ($r->numRows() > 0)
00804 {
00805 return $r;
00806 }
00807 else
00808 {
00809
00810 $this->ilErr->raiseError(get_class($this)."::fetchPath: No path found! startnode_id:".$a_startnode_id.", endnode_id:".$a_endnode_id,$this->ilErr->WARNING);
00811 }
00812
00813 }
00814
00823 function getPathFull ($a_endnode_id, $a_startnode_id = 0)
00824 {
00825 if (!isset($a_endnode_id))
00826 {
00827 $this->ilErr->raiseError(get_class($this)."::getPathFull(): No endnode_id given! ",$this->ilErr->WARNING);
00828 }
00829
00830 if (empty($a_startnode_id))
00831 {
00832 $a_startnode_id = $this->root_id;
00833 }
00834
00835 $r = $this->fetchPath($a_endnode_id, $a_startnode_id);
00836
00837 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
00838 {
00839 $path[] = $this->fetchNodeData($row);
00840 }
00841
00842 return $path ? $path : array();
00843 }
00844
00853 function getPathId ($a_endnode_id, $a_startnode_id = 0)
00854 {
00855 if (!isset($a_endnode_id))
00856 {
00857 $this->ilErr->raiseError(get_class($this)."::getPathId(): No endnode_id given! ",$this->ilErr->WARNING);
00858 }
00859
00860
00861 if ($a_startnode_id == 0)
00862 {
00863 $a_startnode_id = $this->root_id;
00864 }
00865
00866 $r = $this->fetchPath($a_endnode_id, $a_startnode_id);
00867
00868 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00869 {
00870 $arr[] = $row->child;
00871 }
00872
00873 return $arr;
00874 }
00875
00882 function checkTree()
00883 {
00884 $q = "SELECT lft,rgt FROM ".$this->table_tree." ".
00885 "WHERE ".$this->tree_pk." = '".$this->tree_id."'";
00886
00887 $r = $this->ilDB->query($q);
00888
00889 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
00890 {
00891 $lft[] = $row->lft;
00892 $rgt[] = $row->rgt;
00893 }
00894
00895 $all = array_merge($lft,$rgt);
00896 $uni = array_unique($all);
00897
00898 if (count($all) != count($uni))
00899 {
00900 $message = sprintf('%s::checkTree(): Tree is corrupted!',
00901 get_class($this));
00902
00903 $this->log->write($message,$this->log->FATAL);
00904 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
00905 }
00906
00907 return true;
00908 }
00909
00913 function checkTreeChilds($a_no_zero_child = true)
00914 {
00915 $q = "SELECT * FROM ".$this->table_tree." ".
00916 "WHERE ".$this->tree_pk." = '".$this->tree_id."' ".
00917 "ORDER BY lft";
00918 $r1 = $this->ilDB->query($q);
00919 while ($row = $r1->fetchRow(DB_FETCHMODE_ASSOC))
00920 {
00921
00922 if (($row["child"] == 0) && $a_no_zero_child)
00923 {
00924 $this->ilErr->raiseError(get_class($this)."::checkTreeChilds(): Tree contains child with ID 0!",$this->ilErr->WARNING);
00925 }
00926
00927 if ($this->table_obj_reference)
00928 {
00929
00930 $q = "SELECT * FROM ".$this->table_obj_reference." WHERE ".$this->ref_pk."='".$row["child"]."'";
00931 $r2 = $this->ilDB->query($q);
00932
00933 if ($r2->numRows() == 0)
00934 {
00935 $this->ilErr->raiseError(get_class($this)."::checkTree(): No Object-to-Reference entry found for ID ".
00936 $row["child"]."!",$this->ilErr->WARNING);
00937 }
00938 if ($r2->numRows() > 1)
00939 {
00940 $this->ilErr->raiseError(get_class($this)."::checkTree(): More Object-to-Reference entries found for ID ".
00941 $row["child"]."!",$this->ilErr->WARNING);
00942 }
00943
00944
00945 $obj_ref = $r2->fetchRow(DB_FETCHMODE_ASSOC);
00946
00947 $q = "SELECT * FROM ".$this->table_obj_data." WHERE ".$this->obj_pk."='".$obj_ref[$this->obj_pk]."'";
00948 $r3 = $this->ilDB->query($q);
00949 if ($r3->numRows() == 0)
00950 {
00951 $this->ilErr->raiseError(get_class($this)."::checkTree(): No child found for ID ".
00952 $obj_ref[$this->obj_pk]."!",$this->ilErr->WARNING);
00953 }
00954 if ($r3->numRows() > 1)
00955 {
00956 $this->ilErr->raiseError(get_class($this)."::checkTree(): More childs found for ID ".
00957 $obj_ref[$this->obj_pk]."!",$this->ilErr->WARNING);
00958 }
00959
00960 }
00961 else
00962 {
00963
00964 $q = "SELECT * FROM ".$this->table_obj_data." WHERE ".$this->obj_pk."='".$row["child"]."'";
00965 $r2 = $this->ilDB->query($q);
00966
00967 if ($r2->numRows() == 0)
00968 {
00969 $this->ilErr->raiseError(get_class($this)."::checkTree(): No child found for ID ".
00970 $row["child"]."!",$this->ilErr->WARNING);
00971 }
00972 if ($r2->numRows() > 1)
00973 {
00974 $this->ilErr->raiseError(get_class($this)."::checkTree(): More childs found for ID ".
00975 $row["child"]."!",$this->ilErr->WARNING);
00976 }
00977 }
00978 }
00979
00980 return true;
00981 }
00982
00988 function getMaximumDepth()
00989 {
00990 $q = "SELECT MAX(depth) FROM ".$this->table_tree;
00991 $r = $this->ilDB->query($q);
00992
00993 $row = $r->fetchRow();
00994
00995 return $row[0];
00996 }
00997
01004 function getDepth($a_node_id)
01005 {
01006 if ($a_node_id)
01007 {
01008 $q = "SELECT depth FROM ".$this->table_tree." ".
01009 "WHERE child = '".$a_node_id."' ".
01010 "AND ".$this->tree_pk." = '".$this->tree_id."'";
01011
01012 $res = $this->ilDB->query($q);
01013 $row = $res->fetchRow(DB_FETCHMODE_OBJECT);
01014
01015 return $row->depth;
01016 }
01017 else
01018 {
01019 return 1;
01020 }
01021 }
01022
01033 function calculateFlatTree()
01034 {
01035 if ($this->table_obj_reference)
01036 {
01037 $leftjoin = "LEFT JOIN ".$this->table_obj_reference." ON s.child=".$this->table_obj_reference.".".$this->ref_pk." ".
01038 "LEFT JOIN ".$this->table_obj_data." ON ".$this->table_obj_reference.".".$this->obj_pk."=".$this->table_obj_data.".".$this->obj_pk." ";
01039 }
01040 else
01041 {
01042 $leftjoin = "LEFT JOIN ".$this->table_obj_data." ON s.child=".$this->table_obj_data.".".$this->obj_pk." ";
01043
01044 }
01045
01046 $q = "SELECT s.child,s.parent,s.lft,s.rgt,title,s.depth,".
01047 "(s.rgt-s.lft-1)/2 AS successor,".
01048 "((min(v.rgt)-s.rgt-(s.lft>1))/2) > 0 AS brother ".
01049 "FROM ".$this->table_tree." v, ".$this->table_tree." s ".
01050 $leftjoin.
01051 "WHERE s.lft BETWEEN v.lft AND v.rgt ".
01052 "AND (v.child != s.child OR s.lft = '1') ".
01053 "AND s.".$this->tree_pk." = '".$this->tree_id."' ".
01054 "AND v.".$this->tree_pk." = '".$this->tree_id."' ".
01055 "GROUP BY s.child ".
01056 "ORDER BY s.lft";
01057 $r = $this->ilDB->query($q);
01058
01059 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
01060 {
01061 $arr[] = array(
01062 "title" => $row->title,
01063 "child" => $row->child,
01064 "successor" => $row->successor,
01065 "depth" => $row->depth,
01066 "brother" => $row->brother,
01067 "lft" => $row->lft,
01068 "rgt" => $row->rgt
01069 );
01070 }
01071
01072 return $arr;
01073 }
01074
01082 function getNodeData($a_node_id)
01083 {
01084 if (!isset($a_node_id))
01085 {
01086 $this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
01087 }
01088 if($this->__isMainTree())
01089 {
01090 if($a_node_id < 1)
01091 {
01092 $message = sprintf('%s::getNodeData(): No valid parameter given! $a_node_id: %s',
01093 get_class($this),
01094 $a_node_id);
01095
01096 $this->log->write($message,$this->log->FATAL);
01097 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01098 }
01099 }
01100
01101 $q = "SELECT * FROM ".$this->table_tree." ".
01102 $this->buildJoin().
01103 "WHERE ".$this->table_tree.".child = '".$a_node_id."' ".
01104 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01105 $r = $this->ilDB->query($q);
01106 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01107 $row[$this->tree_pk] = $this->tree_id;
01108
01109 return $this->fetchNodeData($row);
01110 }
01111
01119 function fetchNodeData($a_row)
01120 {
01121 global $objDefinition, $lng, $ilBench;
01122
01123
01124 $data = $a_row;
01125 $data["desc"] = $a_row["description"];
01126
01127
01128
01129
01130 if (is_object($objDefinition))
01131 {
01132 $translation_type = $objDefinition->getTranslationType($data["type"]);
01133 }
01134
01135
01136 if ($translation_type == "sys")
01137 {
01138
01139 if ($data["type"] == "rolf" and $data["obj_id"] != ROLE_FOLDER_ID)
01140 {
01141 $data["description"] = $lng->txt("obj_".$data["type"]."_local_desc").$data["title"].$data["desc"];
01142 $data["desc"] = $lng->txt("obj_".$data["type"]."_local_desc").$data["title"].$data["desc"];
01143 $data["title"] = $lng->txt("obj_".$data["type"]."_local");
01144 }
01145 else
01146 {
01147 $data["title"] = $lng->txt("obj_".$data["type"]);
01148 $data["description"] = $lng->txt("obj_".$data["type"]."_desc");
01149 $data["desc"] = $lng->txt("obj_".$data["type"]."_desc");
01150 }
01151
01152 }
01153 elseif ($translation_type == "db")
01154 {
01155
01156 $q = "SELECT title,description FROM object_translation ".
01157 "WHERE obj_id = ".$data["obj_id"]." ".
01158 "AND lang_code = '".$this->lang_code."' ".
01159 "AND NOT lang_default = 1";
01160 $r = $this->ilDB->query($q);
01161
01162 $row = $r->fetchRow(DB_FETCHMODE_OBJECT);
01163
01164 if ($row)
01165 {
01166 $data["title"] = $row->title;
01167 $data["description"] = ilUtil::shortenText($row->description,MAXLENGTH_OBJ_DESC,true);
01168 $data["desc"] = $row->description;
01169 }
01170
01171 }
01172
01173 return $data ? $data : array();
01174 }
01175
01176
01184 function isInTree($a_node_id)
01185 {
01186 if (!isset($a_node_id))
01187 {
01188 return false;
01189 #$this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
01190 }
01191
01192 $q = "SELECT * FROM ".$this->table_tree." ".
01193 "WHERE ".$this->table_tree.".child = '".$a_node_id."' ".
01194 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01195 $r = $this->ilDB->query($q);
01196
01197 if ($r->numRows() > 0)
01198 {
01199 return true;
01200 }
01201 else
01202 {
01203 return false;
01204 }
01205
01206 }
01207
01214 function getParentNodeData($a_node_id)
01215 {
01216 if (!isset($a_node_id))
01217 {
01218 $this->ilErr->raiseError(get_class($this)."::getParentNodeData(): No node_id given! ",$this->ilErr->WARNING);
01219 }
01220
01221 if ($this->table_obj_reference)
01222 {
01223 $leftjoin = "LEFT JOIN ".$this->table_obj_reference." ON v.child=".$this->table_obj_reference.".".$this->ref_pk." ".
01224 "LEFT JOIN ".$this->table_obj_data." ON ".$this->table_obj_reference.".".$this->obj_pk."=".$this->table_obj_data.".".$this->obj_pk." ";
01225 }
01226 else
01227 {
01228 $leftjoin = "LEFT JOIN ".$this->table_obj_data." ON v.child=".$this->table_obj_data.".".$this->obj_pk." ";
01229 }
01230
01231 $q = "SELECT * FROM ".$this->table_tree." s,".$this->table_tree." v ".
01232 $leftjoin.
01233 "WHERE s.child = '".$a_node_id."' ".
01234 "AND s.parent = v.child ".
01235 "AND s.lft > v.lft ".
01236 "AND s.rgt < v.rgt ".
01237 "AND s.".$this->tree_pk." = '".$this->tree_id."' ".
01238 "AND v.".$this->tree_pk." = '".$this->tree_id."'";
01239 $r = $this->ilDB->query($q);
01240
01241 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01242
01243 return $this->fetchNodeData($row);
01244 }
01245
01253 function isGrandChild($a_startnode_id,$a_querynode_id)
01254 {
01255 if (!isset($a_startnode_id) or !isset($a_querynode_id))
01256 {
01257 return false;
01258
01259 #$this->ilErr->raiseError(get_class($this)."::isGrandChild(): Missing parameter! startnode: ".$a_startnode_id." querynode: ".
01260 # $a_querynode_id,$this->ilErr->WARNING);
01261 }
01262
01263 $q = "SELECT * FROM ".$this->table_tree." s,".$this->table_tree." v ".
01264 "WHERE s.child = '".$a_startnode_id."' ".
01265 "AND v.child = '".$a_querynode_id."' ".
01266 "AND s.".$this->tree_pk." = '".$this->tree_id."' ".
01267 "AND v.".$this->tree_pk." = '".$this->tree_id."' ".
01268 "AND v.lft BETWEEN s.lft AND s.rgt ".
01269 "AND v.rgt BETWEEN s.lft AND s.rgt";
01270 $r = $this->ilDB->query($q);
01271
01272 return $r->numRows();
01273 }
01274
01283 function addTree($a_tree_id,$a_node_id = -1)
01284 {
01285
01286
01287 if($this->__isMainTree())
01288 {
01289 $message = sprintf('%s::addTree(): Operation not allowed on main tree! $a_tree_if: %s $a_node_id: %s',
01290 get_class($this),
01291 $a_tree_id,
01292 $a_node_id);
01293 $this->log->write($message,$this->log->FATAL);
01294 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01295 }
01296
01297 if (!isset($a_tree_id))
01298 {
01299 $this->ilErr->raiseError(get_class($this)."::addTree(): No tree_id given! ",$this->ilErr->WARNING);
01300 }
01301
01302 if ($a_node_id <= 0)
01303 {
01304 $a_node_id = $a_tree_id;
01305 }
01306
01307 $q = "INSERT INTO ".$this->table_tree." (".$this->tree_pk.", child, parent, lft, rgt, depth) ".
01308 "VALUES ".
01309 "('".$a_tree_id."','".$a_node_id."', 0, 1, 2, 1)";
01310
01311 $this->ilDB->query($q);
01312
01313 return true;
01314 }
01315
01323 function getNodeDataByType($a_type)
01324 {
01325 if (!isset($a_type) or (!is_string($a_type)))
01326 {
01327 $this->ilErr->raiseError(get_class($this)."::getNodeDataByType(): Type not given or wrong datatype!",$this->ilErr->WARNING);
01328 }
01329
01330 $data = array();
01331 $row = "";
01332 $left = "";
01333 $right = "";
01334
01335 $q = "SELECT * FROM ".$this->table_tree." ".
01336 "WHERE ".$this->tree_pk." = '".$this->tree_id."'".
01337 "AND parent = '0'";
01338 $r = $this->ilDB->query($q);
01339
01340 while ($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
01341 {
01342 $left = $row->lft;
01343 $right = $row->rgt;
01344 }
01345
01346 $q = "SELECT * FROM ".$this->table_tree." ".
01347 $this->buildJoin().
01348 "WHERE ".$this->table_obj_data.".type = '".$a_type."' ".
01349 "AND ".$this->table_tree.".lft BETWEEN '".$left."' AND '".$right."' ".
01350 "AND ".$this->table_tree.".rgt BETWEEN '".$left."' AND '".$right."' ".
01351 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01352 $r = $this->ilDB->query($q);
01353
01354 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
01355 {
01356 $data[] = $this->fetchNodeData($row);
01357 }
01358
01359 return $data;
01360 }
01361
01369 function removeTree($a_tree_id)
01370 {
01371
01372 if($this->__isMainTree())
01373 {
01374 $message = sprintf('%s::removeTree(): Operation not allowed on main tree! $a_tree_if: %s',
01375 get_class($this),
01376 $a_tree_id);
01377 $this->log->write($message,$this->log->FATAL);
01378 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01379 }
01380 if (!$a_tree_id)
01381 {
01382 $this->ilErr->raiseError(get_class($this)."::removeTree(): No tree_id given! Action aborted",$this->ilErr->MESSAGE);
01383 }
01384
01385 $q = "DELETE FROM ".$this->table_tree." WHERE ".$this->tree_pk." = '".$a_tree_id."'";
01386 $this->ilDB->query($q);
01387
01388 return true;
01389 }
01390
01398 function saveSubTree($a_node_id)
01399 {
01400 if (!$a_node_id)
01401 {
01402 $message = sprintf('%s::saveSubTree(): No valid parameter given! $a_node_id: %s',
01403 get_class($this),
01404 $a_node_id);
01405 $this->log->write($message,$this->log->FATAL);
01406 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01407 }
01408
01409
01410 if($this->__isMainTree())
01411 {
01412 ilDBx::_lockTables(array('tree' => 'WRITE'));
01413 }
01414
01415
01416 $q = "SELECT * FROM ".$this->table_tree." ".
01417 "WHERE ".$this->tree_pk." = '".$this->tree_id."' ".
01418 "AND child = '".$a_node_id."' ";
01419 $r = $this->ilDB->query($q);
01420
01421 while($row = $r->fetchRow(DB_FETCHMODE_OBJECT))
01422 {
01423 $lft = $row->lft;
01424 $rgt = $row->rgt;
01425 }
01426
01427
01428 $q = "SELECT * FROM ".$this->table_tree." ".
01429 "WHERE ".$this->tree_pk." = '".$this->tree_id."' ".
01430 "AND lft >= '".$lft."' ".
01431 "AND rgt <= '".$rgt."'";
01432 $r = $this->ilDB->query($q);
01433
01434 while($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
01435 {
01436 $subnodes[$row["child"]] = $this->fetchNodeData($row);
01437 }
01438
01439
01440 foreach($subnodes as $node)
01441 {
01442 $q = "INSERT INTO ".$this->table_tree." ".
01443 "VALUES ('".-$a_node_id."','".$node["child"]."','".$node["parent"]."','".
01444 $node["lft"]."','".$node["rgt"]."','".$node["depth"]."')";
01445 $r = $this->ilDB->query($q);
01446 }
01447 if($this->__isMainTree())
01448 {
01449 ilDBX::_unlockTables();
01450 }
01451
01452
01453 return true;
01454 }
01455
01459 function isDeleted($a_node_id)
01460 {
01461 return $this->isSaved($a_node_id);
01462 }
01463
01467 function isSaved($a_node_id)
01468 {
01469 $q = "SELECT * FROM ".$this->table_tree." ".
01470 "WHERE child = '".$a_node_id."'";
01471 $s = $this->ilDB->query($q);
01472 $r = $s->fetchRow(DB_FETCHMODE_ASSOC);
01473
01474 if ($r[$this->tree_pk] < 0)
01475 {
01476 return true;
01477 }
01478 else
01479 {
01480 return false;
01481 }
01482 }
01483
01484
01493 function saveNode($a_node_id,$a_parent_id)
01494 {
01495 if($this->__isMainTree())
01496 {
01497 if($a_node_id <= 1 or $a_parent_id <= 0)
01498 {
01499 $message = sprintf('%s::saveSubTree(): No valid parameter given! $a_node_id: %s $a_parent_id: %s',
01500 get_class($this),
01501 $a_node_id,
01502 $a_parent_id);
01503
01504 $this->log->write($message,$this->log->FATAL);
01505 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01506 }
01507 }
01508 if ($a_node_id < 1 or !isset($a_parent_id))
01509 {
01510 $this->ilErr->raiseError(get_class($this)."::saveNode(): Missing parameter! ".
01511 "node_id: ".$a_node_id." parent_id: ".$a_parent_id,$this->ilErr->WARNING);
01512 }
01513
01514
01515 $q = "INSERT INTO ".$this->table_tree." ".
01516 "VALUES ('".-$a_node_id."','".$a_node_id."','".$a_parent_id."','1','2','1')";
01517 $r = $this->ilDB->query($q);
01518
01519 return true;
01520 }
01521
01528 function getSavedNodeData($a_parent_id)
01529 {
01530 if (!isset($a_parent_id))
01531 {
01532 $this->ilErr->raiseError(get_class($this)."::getSavedNodeData(): No node_id given!",$this->ilErr->WARNING);
01533 }
01534
01535 $q = "SELECT * FROM ".$this->table_tree." ".
01536 $this->buildJoin().
01537 "WHERE ".$this->table_tree.".".$this->tree_pk." < 0 ".
01538 "AND ".$this->table_tree.".parent = '".$a_parent_id."' ";
01539 $r = $this->ilDB->query($q);
01540
01541 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
01542 {
01543 $saved[] = $this->fetchNodeData($row);
01544 }
01545
01546 return $saved ? $saved : array();
01547 }
01548
01555 function getParentId($a_node_id)
01556 {
01557 if (!isset($a_node_id))
01558 {
01559 $this->ilErr->raiseError(get_class($this)."::getParentId(): No node_id given! ",$this->ilErr->WARNING);
01560 }
01561
01562 $q = "SELECT parent FROM ".$this->table_tree." ".
01563 "WHERE child='".$a_node_id."' ".
01564 "AND ".$this->tree_pk."='".$this->tree_id."'";
01565 $r = $this->ilDB->query($q);
01566
01567 $row = $r->fetchRow(DB_FETCHMODE_OBJECT);
01568
01569 return $row->parent;
01570 }
01571
01578 function getChildSequenceNumber($a_node, $type = "")
01579 {
01580 if (!isset($a_node))
01581 {
01582 $this->ilErr->raiseError(get_class($this)."::getChildSequenceNumber(): No node_id given! ",$this->ilErr->WARNING);
01583 }
01584
01585 $type_str = ($type != "")
01586 ? "AND type='$type'"
01587 : "";
01588
01589 $q = "SELECT count(*) AS cnt FROM ".$this->table_tree." ".
01590 $this->buildJoin().
01591 "WHERE lft <=".$this->ilDB->quote($a_node["lft"])." ".
01592 $type_str.
01593 "AND parent=".$this->ilDB->quote($a_node["parent"])." ".
01594 "AND ".$this->table_tree.".".$this->tree_pk."=".$this->ilDB->quote($this->tree_id);
01595 $r = $this->ilDB->query($q);
01596
01597 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01598
01599 return $row["cnt"];
01600 }
01601
01608 function readRootId()
01609 {
01610 $query = "SELECT child FROM $this->table_tree ".
01611 "WHERE parent = '0'".
01612 "AND ".$this->tree_pk." = '".$this->tree_id."'";
01613 $row = $this->ilDB->getRow($query,DB_FETCHMODE_OBJECT);
01614
01615 $this->root_id = $row->child;
01616 return $this->root_id;
01617 }
01618
01624 function getRootId()
01625 {
01626 return $this->root_id;
01627 }
01628 function setRootId($a_root_id)
01629 {
01630 $this->root_id = $a_root_id;
01631 }
01632
01638 function getTreeId()
01639 {
01640 return $this->tree_id;
01641 }
01642
01648 function setTreeId($a_tree_id)
01649 {
01650 $this->tree_id = $a_tree_id;
01651 }
01652
01660 function fetchSuccessorNode($a_node_id, $a_type = "")
01661 {
01662 if (!isset($a_node_id))
01663 {
01664 $this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
01665 }
01666
01667
01668 $q = "SELECT lft FROM ".$this->table_tree." ".
01669 "WHERE ".$this->table_tree.".child = '".$a_node_id."' ".
01670 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01671 $r = $this->ilDB->query($q);
01672 $curr_node = $r->fetchRow(DB_FETCHMODE_ASSOC);
01673
01674
01675 $type_where = ($a_type != "")
01676 ? "AND ".$this->table_obj_data.".type = '$a_type' "
01677 : "";
01678 $q = "SELECT * FROM ".$this->table_tree." ".
01679 $this->buildJoin().
01680 "WHERE lft > '".$curr_node["lft"]."' ".
01681 $type_where.
01682 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'".
01683 "ORDER BY lft LIMIT 1";
01684 $r = $this->ilDB->query($q);
01685
01686 if ($r->numRows() < 1)
01687 {
01688 return false;
01689 }
01690 else
01691 {
01692 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01693 return $this->fetchNodeData($row);
01694 }
01695 }
01696
01704 function fetchPredecessorNode($a_node_id, $a_type = "")
01705 {
01706 if (!isset($a_node_id))
01707 {
01708 $this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
01709 }
01710
01711
01712 $q = "SELECT lft FROM ".$this->table_tree." ".
01713 "WHERE ".$this->table_tree.".child = '".$a_node_id."' ".
01714 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'";
01715 $r = $this->ilDB->query($q);
01716 $curr_node = $r->fetchRow(DB_FETCHMODE_ASSOC);
01717
01718
01719 $type_where = ($a_type != "")
01720 ? "AND ".$this->table_obj_data.".type = '$a_type' "
01721 : "";
01722 $q = "SELECT * FROM ".$this->table_tree." ".
01723 $this->buildJoin().
01724 "WHERE lft < '".$curr_node["lft"]."' ".
01725 $type_where.
01726 "AND ".$this->table_tree.".".$this->tree_pk." = '".$this->tree_id."'".
01727 "ORDER BY lft DESC LIMIT 1";
01728 $r = $this->ilDB->query($q);
01729
01730 if ($r->numRows() < 1)
01731 {
01732 return false;
01733 }
01734 else
01735 {
01736 $row = $r->fetchRow(DB_FETCHMODE_ASSOC);
01737 return $this->fetchNodeData($row);
01738 }
01739 }
01740
01749 function renumber($node_id = 1, $i = 1)
01750 {
01751
01752 if($this->__isMainTree())
01753 {
01754 ilDBx::_lockTables(array($this->table_tree => 'WRITE',
01755 $this->table_obj_data => 'WRITE',
01756 $this->table_obj_reference => 'WRITE',
01757 'object_translation' => 'WRITE'));
01758 }
01759 $return = $this->__renumber($node_id,$i);
01760 if($this->__isMainTree())
01761 {
01762 ilDBx::_unlockTables();
01763 }
01764
01765
01766 return $return;
01767 }
01768
01769
01779 function __renumber($node_id = 1, $i = 1)
01780 {
01781 $q = "UPDATE ".$this->table_tree." SET lft='".$i."' WHERE child='".$node_id."'";
01782 $this->ilDB->query($q);
01783
01784 $childs = $this->getChilds($node_id);
01785
01786 foreach ($childs as $child)
01787 {
01788 $i = $this->__renumber($child["child"],$i+1);
01789 }
01790
01791 $i++;
01792 $q = "UPDATE ".$this->table_tree." SET rgt='".$i."' WHERE child='".$node_id."'";
01793 $this->ilDB->query($q);
01794
01795 return $i;
01796 }
01797
01798
01808 function checkForParentType($a_ref_id,$a_type)
01809 {
01810 if(!$this->isInTree($a_ref_id))
01811 {
01812 return false;
01813 }
01814 $path = array_reverse($this->getPathFull($a_ref_id));
01815
01816 foreach($path as $node)
01817 {
01818 if($node["type"] == $a_type)
01819 {
01820 return $node["child"];
01821 }
01822 }
01823 return 0;
01824 }
01825
01835 function _removeEntry($a_tree,$a_child,$a_db_table = "tree")
01836 {
01837 global $ilDB,$ilLog,$ilErr;
01838
01839 if($a_db_table === 'tree')
01840 {
01841 if($a_tree == 1 and $a_child == ROOT_FOLDER_ID)
01842 {
01843 $message = sprintf('%s::_removeEntry(): Tried to delete root node! $a_tree: %s $a_child: %s',
01844 get_class($this),
01845 $a_tree,
01846 $a_child);
01847 $ilLog->write($message,$ilLog->FATAL);
01848 $ilErr->raiseError($message,$ilErr->WARNING);
01849 }
01850 }
01851
01852 $q = "DELETE from ".$a_db_table." WHERE tree='".$a_tree."' AND child='".$a_child."'";
01853 $ilDB->query($q);
01854 }
01855
01856
01863 function __isMainTree()
01864 {
01865 return $this->table_tree === 'tree';
01866 }
01867
01876 function __checkDelete($a_node)
01877 {
01878
01879 $query = "SELECT * FROM ".$this->table_tree." ".
01880 "WHERE lft >= ".$a_node['lft']." ".
01881 "AND rgt <= ".$a_node['rgt']." ".
01882 "AND ".$this->tree_pk." = '".$a_node[$this->tree_pk]."'";
01883
01884
01885 $res = $this->ilDB->query($query);
01886
01887 $counter = (int) $lft_childs = array();
01888 while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
01889 {
01890 $lft_childs[$row->child] = $row->parent;
01891 ++$counter;
01892 }
01893
01894
01895 if($counter != count($lft_childs))
01896 {
01897 $message = sprintf('%s::__checkTree(): Duplicate entries for "child" in maintree! $a_node_id: %s',
01898 get_class($this),
01899 $a_node['child']);
01900 $this->log->write($message,$this->log->FATAL);
01901 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01902 }
01903
01904
01905 $parent_childs = array();
01906 $this->__getSubTreeByParentRelation($a_node['child'],$parent_childs);
01907 $this->__validateSubtrees($lft_childs,$parent_childs);
01908
01909 return true;
01910 }
01911
01912 function __getSubTreeByParentRelation($a_node_id,&$parent_childs)
01913 {
01914
01915 $query = "SELECT * FROM ".$this->table_tree." ".
01916 "WHERE child = '".$a_node_id."' ".
01917 "AND tree = '".$this->tree_id."'";
01918
01919 $res = $this->ilDB->query($query);
01920 $counter = 0;
01921 while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
01922 {
01923 $parent_childs[$a_node_id] = $row->parent;
01924 ++$counter;
01925 }
01926
01927 if($counter > 1)
01928 {
01929 $message = sprintf('%s::__getSubTreeByParentRelation(): Multiple entries in maintree! $a_node_id: %s',
01930 get_class($this),
01931 $a_node_id);
01932 $this->log->write($message,$this->log->FATAL);
01933 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01934 }
01935
01936
01937 $query = "SELECT * FROM ".$this->table_tree." ".
01938 "WHERE parent = '".$a_node_id."'";
01939
01940 $res = $this->ilDB->query($query);
01941 while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
01942 {
01943
01944 $this->__getSubTreeByParentRelation($row->child,$parent_childs);
01945 }
01946 return true;
01947 }
01948
01949 function __validateSubtrees(&$lft_childs,$parent_childs)
01950 {
01951
01952 ksort($lft_childs);
01953 ksort($parent_childs);
01954
01955 if(count($lft_childs) != count($parent_childs))
01956 {
01957 $message = sprintf('%s::__validateSubtrees(): (COUNT) Tree is corrupted! Left/Right subtree does not comply .'.
01958 'with parent relation',
01959 get_class($this));
01960 $this->log->write($message,$this->log->FATAL);
01961 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01962 }
01963
01964 foreach($lft_childs as $key => $value)
01965 {
01966 if($parent_childs[$key] != $value)
01967 {
01968 $message = sprintf('%s::__validateSubtrees(): (COMPARE) Tree is corrupted! Left/Right subtree does not comply '.
01969 'with parent relation',
01970 get_class($this));
01971 $this->log->write($message,$this->log->FATAL);
01972 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01973 }
01974 if($key == ROOT_FOLDER_ID)
01975 {
01976 $message = sprintf('%s::__validateSubtrees(): (ROOT_FOLDER) Tree is corrupted! Tried to delete root folder',
01977 get_class($this));
01978 $this->log->write($message,$this->log->FATAL);
01979 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
01980 }
01981 }
01982 return true;
01983 }
01984
01985 }
01986 ?>