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

Generated on Fri Dec 13 2013 09:06:35 for ILIAS Release_3_4_x_branch .rev 46804 by  doxygen 1.7.1