• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

classes/class.ilTree.php

Go to the documentation of this file.
00001 <?php
00002 /*
00003         +-----------------------------------------------------------------------------+
00004         | ILIAS open source                                                           |
00005         +-----------------------------------------------------------------------------+
00006         | Copyright (c) 1998-2001 ILIAS open source, University of Cologne            |
00007         |                                                                             |
00008         | This program is free software; you can redistribute it and/or               |
00009         | modify it under the terms of the GNU General Public License                 |
00010         | as published by the Free Software Foundation; either version 2              |
00011         | of the License, or (at your option) any later version.                      |
00012         |                                                                             |
00013         | This program is distributed in the hope that it will be useful,             |
00014         | but WITHOUT ANY WARRANTY; without even the implied warranty of              |
00015         | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               |
00016         | GNU General Public License for more details.                                |
00017         |                                                                             |
00018         | You should have received a copy of the GNU General Public License           |
00019         | along with this program; if not, write to the Free Software                 |
00020         | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. |
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                 // set db & error handler
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                 // lang_code is only required in $this->fetchnodedata
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                 // CREATE LOGGER INSTANCE
00154                 $this->log =& $ilLog;
00155 
00156                 //init variables
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                 // init childs
00311                 $childs = array();
00312 
00313                 // number of childs
00314                 $count = 0;
00315 
00316                 // init order_clause
00317                 $order_clause = "";
00318 
00319                 // set order_clause if sort order parameter is given
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         //666
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                 //$ilBench->start("Tree", "getChilds_Query");
00337                 $r = $this->ilDB->query($q);
00338                 //$ilBench->stop("Tree", "getChilds_Query");
00339 
00340                 $count = $r->numRows();
00341                 
00342 
00343                 if ($count > 0)
00344                 {
00345                         //$ilBench->start("Tree", "getChilds_fetchNodeData");
00346                         while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
00347                         {
00348                                 $childs[] = $this->fetchNodeData($row);
00349                         }
00350                         //$ilBench->stop("Tree", "getChilds_fetchNodeData");
00351 
00352                         // mark the last child node (important for display)
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                 // init childs
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 //echo "+$a_node_id+$a_parent_id+";
00432                 // CHECK node_id and parent_id > 0 if in main tree
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                 // i changed the processing here.
00460                 // mail any errors to alex.killing@gmx.de (22.5.2003)
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                                 // get left value of parent
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                                 // spread tree
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                                 // get right value of parent
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                                 // spread tree
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                                 // get right value of preceeding child
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                                 // crosscheck parents of sibling and new node (must be identical)
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                                 // update lft/rgt values
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                 // get depth
00599                 $depth = $this->getDepth($a_parent_id) + 1;
00600 
00601                 // insert node
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                 // finally unlock tables
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                 // LOCKED ###########################################################
00719                 // get lft and rgt values. Don't trust parameter lft/rgt values of $a_node
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                 // delete subtree
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                 // close gaps
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                 // LOCKED ###########################################################
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                 //if (!isset($a_startnode_id))
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 //echo "tree:".$row[$this->tree_pk].":lft:".$row["lft"].":rgt:".$row["rgt"].":child:".$row["child"].":<br>";
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                                 // get object reference data
00930                                 $q = "SELECT * FROM ".$this->table_obj_reference." WHERE ".$this->ref_pk."='".$row["child"]."'";
00931                                 $r2 = $this->ilDB->query($q);
00932 //echo "num_childs:".$r2->numRows().":<br>";
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                                 // get object data
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                                 // get only object data
00964                                 $q = "SELECT * FROM ".$this->table_obj_data." WHERE ".$this->obj_pk."='".$row["child"]."'";
00965                                 $r2 = $this->ilDB->query($q);
00966 //echo "num_childs:".$r2->numRows().":<br>";
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                 //$ilBench->start("Tree", "fetchNodeData_getRow");
01124                 $data = $a_row;
01125                 $data["desc"] = $a_row["description"];  // for compability
01126                 //$ilBench->stop("Tree", "fetchNodeData_getRow");
01127 
01128                 // multilingual support systemobjects (sys) & categories (db)
01129                 //$ilBench->start("Tree", "fetchNodeData_readDefinition");
01130                 if (is_object($objDefinition))
01131                 {
01132                         $translation_type = $objDefinition->getTranslationType($data["type"]);
01133                 }
01134                 //$ilBench->stop("Tree", "fetchNodeData_readDefinition");
01135                 
01136                 if ($translation_type == "sys")
01137                 {
01138                         //$ilBench->start("Tree", "fetchNodeData_getLangData");
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                         //$ilBench->stop("Tree", "fetchNodeData_getLangData");
01152                 }
01153                 elseif ($translation_type == "db")
01154                 {
01155                         //$ilBench->start("Tree", "fetchNodeData_getTranslation");
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                         //$ilBench->stop("Tree", "fetchNodeData_getTranslation");
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                         // No raise error, since it is a already a check function
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                 // FOR SECURITY addTree() IS NOT ALLOWED ON MAIN TREE
01286                 // IF SOMEONE WILL NEED FEATURES LIKE $tree->addTree(2) ON THE MAIN TREE PLEASE CONTACT ME (smeyer@databay.de)
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();        // node_data
01331                 $row = "";                      // fetched row
01332                 $left = "";                     // tree_left
01333                 $right = "";            // tree_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                 // OPERATION NOT ALLOWED ON MAIN TREE
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                 // LOCKED ###############################################
01410                 if($this->__isMainTree())
01411                 {
01412                         ilDBx::_lockTables(array('tree' => 'WRITE'));
01413                 }
01414 
01415                 // GET LEFT AND RIGHT VALUE
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                 // GET ALL SUBNODES
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                 // SAVE SUBTREE
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                 // LOCKED ###############################################
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                 // SAVE NODE
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                 // get lft value for current node
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                 // get data of successor node
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                 // get lft value for current node
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                 // get data of predecessor node
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                 // LOCKED ###################################
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                 // LOCKED ###################################
01765 
01766                 return $return;
01767         }
01768 
01769         // PRIVATE
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         // PRIVATE METHODS
01863         function __isMainTree()
01864         {
01865                 return $this->table_tree === 'tree';
01866         }
01867 
01876         function __checkDelete($a_node)
01877         {
01878                 // get subtree by lft,rgt
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                 // CHECK FOR DUPLICATE CHILD IDS
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                 // GET SUBTREE BY PARENT RELATION
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                 // GET PARENT ID
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                 // MULTIPLE ENTRIES
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                 // GET ALL CHILDS
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                         // RECURSION
01944                         $this->__getSubTreeByParentRelation($row->child,$parent_childs);
01945                 }
01946                 return true;
01947         }
01948 
01949         function __validateSubtrees(&$lft_childs,$parent_childs)
01950         {
01951                 // SORT BY KEY
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 } // END class.tree
01986 ?>

Generated on Fri Dec 13 2013 10:18:28 for ILIAS Release_3_5_x_branch .rev 46805 by  doxygen 1.7.1