4define(
"IL_LAST_NODE", -2);
 
    5define(
"IL_FIRST_NODE", -1);
 
    7include_once 
'./Services/Tree/exceptions/class.ilInvalidTreeStructureException.php';
 
  157        $this->lang_code = 
"en";
 
  162        if (!isset($a_tree_id) or (func_num_args() == 0)) {
 
  163            $this->log->error(
"No tree_id given!");
 
  165            throw new InvalidArgumentException(
"No tree_id given!");
 
  168        if (func_num_args() > 2) {
 
  169            $this->log->error(
"Wrong parameter count!");
 
  170            throw new InvalidArgumentException(
"Wrong parameter count!");
 
  174        if (empty($a_root_id)) {
 
  175            $a_root_id = ROOT_FOLDER_ID;
 
  178        $this->tree_id = $a_tree_id;
 
  179        $this->root_id = $a_root_id;
 
  180        $this->table_tree = 
'tree';
 
  181        $this->table_obj_data = 
'object_data';
 
  182        $this->table_obj_reference = 
'object_reference';
 
  183        $this->ref_pk = 
'ref_id';
 
  184        $this->obj_pk = 
'obj_id';
 
  185        $this->tree_pk = 
'tree';
 
  187        $this->use_cache = 
true;
 
  190        $this->translation_cache = array();
 
  191        $this->parent_type_cache = array();
 
  208        if (!
$DIC->isDependencyAvailable(
'settings') || 
$DIC->settings()->getModule() != 
'common') {
 
  209            include_once 
'./Services/Administration/classes/class.ilSetting.php';
 
  212            $setting = 
$DIC->settings();
 
  216            if ($setting->get(
'main_tree_impl', 
'ns') == 
'ns') {
 
  217                #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Using nested set.'); 
  218                include_once 
'./Services/Tree/classes/class.ilNestedSetTree.php';
 
  221                #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Using materialized path.'); 
  222                include_once 
'./Services/Tree/classes/class.ilMaterializedPathTree.php';
 
  226            #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Using netsted set for non main tree.'); 
  227            include_once 
'./Services/Tree/classes/class.ilNestedSetTree.php';
 
  246        $this->use_cache = $a_use;
 
  287            $this->lang_code = 
$ilUser->getCurrentLanguage();
 
  288        } 
catch (\InvalidArgumentException $e) {
 
  289            $this->lang_code = 
"en";
 
  341        $this->in_tree_cache = array();
 
  361    public function setTableNames($a_table_tree, $a_table_obj_data, $a_table_obj_reference = 
"")
 
  363        if (!isset($a_table_tree) or !isset($a_table_obj_data)) {
 
  365                                "tree table: " . $a_table_tree . 
" object data table: " . $a_table_obj_data;
 
  367            throw new InvalidArgumentException(
$message);
 
  370        $this->table_tree = $a_table_tree;
 
  371        $this->table_obj_data = $a_table_obj_data;
 
  372        $this->table_obj_reference = $a_table_obj_reference;
 
  388        if (!isset($a_column_name)) {
 
  391            throw new InvalidArgumentException(
$message);
 
  394        $this->ref_pk = $a_column_name;
 
  407        if (!isset($a_column_name)) {
 
  410            throw new InvalidArgumentException(
$message);
 
  413        $this->obj_pk = $a_column_name;
 
  426        if (!isset($a_column_name)) {
 
  429            throw new InvalidArgumentException(
$message);
 
  432        $this->tree_pk = $a_column_name;
 
  443        if ($this->table_obj_reference) {
 
  445            return "JOIN " . $this->table_obj_reference . 
" ON " . $this->table_tree . 
".child=" . $this->table_obj_reference . 
"." . $this->ref_pk . 
" " .
 
  446                   "JOIN " . $this->table_obj_data . 
" ON " . $this->table_obj_reference . 
"." . $this->obj_pk . 
"=" . $this->table_obj_data . 
"." . $this->obj_pk . 
" ";
 
  449            return "JOIN " . $this->table_obj_data . 
" ON " . $this->table_tree . 
".child=" . $this->table_obj_data . 
"." . $this->obj_pk . 
" ";
 
  489        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
  490                'WHERE parent = ' . 
$ilDB->quote($a_node, 
'integer') . 
' ' .
 
  491                'AND tree = ' . 
$ilDB->quote($this->tree_id, 
'integer' . 
' ' .
 
  497            $childs[] = 
$row->child;
 
  511    public function getChilds($a_node_id, $a_order = 
"", $a_direction = 
"ASC")
 
  517        $ilObjDataCache = 
$DIC[
'ilObjDataCache'];
 
  520        if (!isset($a_node_id)) {
 
  523            throw new InvalidArgumentException(
$message);
 
  536        if (!empty($a_order)) {
 
  537            $order_clause = 
"ORDER BY " . $a_order . 
" " . $a_direction;
 
  539            $order_clause = 
"ORDER BY " . $this->table_tree . 
".lft";
 
  544            'SELECT * FROM ' . $this->table_tree . 
' ' .
 
  546                "WHERE parent = %s " .
 
  547                "AND " . $this->table_tree . 
"." . $this->tree_pk . 
" = %s " .
 
  549            $ilDB->quote($a_node_id, 
'integer'),
 
  550            $ilDB->quote($this->tree_id, 
'integer')
 
  555        if (!$count = 
$res->numRows()) {
 
  563            $obj_ids[] = 
$r[
"obj_id"];
 
  568            is_object(
$ilUser) && $this->lang_code == 
$ilUser->getLanguage() && !$this->oc_preloaded[$a_node_id]) {
 
  570            $ilObjDataCache->preloadObjectCache($obj_ids, $this->lang_code);
 
  572            $this->oc_preloaded[$a_node_id] = 
true;
 
  580                #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child'].' = true'); 
  581                $this->in_tree_cache[
$row[
'child']] = 
$row[
'tree'] == 1;
 
  584        $childs[$count - 1][
"last"] = 
true;
 
  599        $childs = $this->
getChilds($a_node, $a_order, $a_direction);
 
  601        foreach ($childs as $child) {
 
  602            if (!in_array($child[
"type"], $a_filter)) {
 
  603                $filtered[] = $child;
 
  606        return $filtered ? $filtered : array();
 
  624        if (!isset($a_node_id) or !isset(
$a_type)) {
 
  625            $message = 
"Missing parameter! node_id:" . $a_node_id . 
" type:" . 
$a_type;
 
  627            throw new InvalidArgumentException(
$message);
 
  630        if (
$a_type == 
'rolf' && $this->table_obj_reference) {
 
  634            $ilDB->setLimit(1, 0);
 
  636                "SELECT * FROM " . $this->table_tree . 
" " .
 
  638                "WHERE parent = %s " .
 
  639                "AND " . $this->table_tree . 
"." . $this->tree_pk . 
" = %s " .
 
  640                "AND " . $this->table_obj_data . 
".type = %s ",
 
  641                $ilDB->quote($a_node_id, 
'integer'),
 
  642                $ilDB->quote($this->tree_id, 
'integer'),
 
  647                "SELECT * FROM " . $this->table_tree . 
" " .
 
  649                "WHERE parent = %s " .
 
  650                "AND " . $this->table_tree . 
"." . $this->tree_pk . 
" = %s " .
 
  651                "AND " . $this->table_obj_data . 
".type = %s " .
 
  652                "ORDER BY " . $this->table_tree . 
".lft",
 
  653                $ilDB->quote($a_node_id, 
'integer'),
 
  654                $ilDB->quote($this->tree_id, 
'integer'),
 
  666        return $childs ? $childs : array();
 
  684        if (!isset($a_node_id) or !$a_types) {
 
  685            $message = 
"Missing parameter! node_id:" . $a_node_id . 
" type:" . $a_types;
 
  687            throw new InvalidArgumentException(
$message);
 
  692            $filter = 
'AND ' . $this->table_obj_data . 
'.type IN(' . implode(
',', 
ilUtil::quoteArray($a_types)) . 
') ';
 
  696        if (!empty($a_order)) {
 
  697            $order_clause = 
"ORDER BY " . $a_order . 
" " . $a_direction;
 
  699            $order_clause = 
"ORDER BY " . $this->table_tree . 
".lft";
 
  702        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
  704            'WHERE parent = ' . 
$ilDB->quote($a_node_id, 
'integer') . 
' ' .
 
  705            'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = ' . 
$ilDB->quote($this->tree_id, 
'integer') . 
' ' .
 
  714        return $childs ? $childs : array();
 
  735            if ($a_source_id <= 1 or $a_target_id <= 0) {
 
  737                throw new InvalidArgumentException(
'Invalid parameter given for ilTree::insertNodeFromTrash');
 
  740        if (!isset($a_source_id) or !isset($a_target_id)) {
 
  742            throw new InvalidArgumentException(
'Missing parameter for ilTree::insertNodeFromTrash');
 
  744        if ($this->
isInTree($a_source_id)) {
 
  747            throw new InvalidArgumentException(
'Node already in tree.');
 
  750        $query = 
'DELETE from tree ' .
 
  751                'WHERE tree = ' . 
$ilDB->quote($a_tree_id, 
'integer') . 
' ' .
 
  752                'AND child = ' . 
$ilDB->quote($a_source_id, 
'integer');
 
  776            if ($a_node_id <= 1 or $a_parent_id <= 0) {
 
  778                    'Invalid parameters! $a_node_id: %s $a_parent_id: %s',
 
  783                throw new InvalidArgumentException(
$message);
 
  788        if (!isset($a_node_id) or !isset($a_parent_id)) {
 
  790            throw new InvalidArgumentException(
"Missing parameter! " .
 
  791                "node_id: " . $a_node_id . 
" parent_id: " . $a_parent_id);
 
  794            throw new InvalidArgumentException(
"Node " . $a_node_id . 
" already in tree " .
 
  795                                     $this->table_tree . 
"!");
 
  800        $this->in_tree_cache[$a_node_id] = 
true;
 
  803        if ($a_reset_deletion_date) {
 
  808            $GLOBALS[
'DIC'][
'ilAppEventHandler']->raise(
 
  812                        'tree' => $this->table_tree,
 
  813                        'node_id' => $a_node_id,
 
  814                        'parent_id' => $a_parent_id)
 
  837        foreach ($this->
getSubTree($node) as $subnode) {
 
  838            if ($depth and $subnode[
'depth'] > $depth) {
 
  841            if (!$first and in_array($subnode[
'type'], $a_filter)) {
 
  842                $depth = $subnode[
'depth'];
 
  848            $filtered[] = $subnode;
 
  850        return $filtered ? $filtered : array();
 
  879        if (!is_array($a_node)) {
 
  881            throw new InvalidArgumentException(__METHOD__ . 
': wrong datatype for node data given');
 
  903                $subtree[] = 
$row[
'child'];
 
  906            if ($this->
__isMainTree() || $this->table_tree == 
"lm_tree") {
 
  907                $this->in_tree_cache[
$row[
'child']] = 
true;
 
  910        return $subtree ? $subtree : array();
 
  923        $a_filter = $a_filter ? $a_filter : array();
 
  925        foreach ($this->getSubtree($this->
getNodeData($a_node)) as $node) {
 
  926            if (in_array($node[
"type"], $a_filter)) {
 
  929            $types[
"$node[type]"] = $node[
"type"];
 
  931        return $types ? $types : array();
 
  947        $this->log->debug(
'Delete tree with node ' . $a_node);
 
  949        if (!is_array($a_node)) {
 
  951            throw new InvalidArgumentException(__METHOD__ . 
': Wrong datatype for node data!');
 
  954        $this->log->debug($this->tree_pk);
 
  991        $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
 
  999        if (count($pathIds) == 0) {
 
 1003        $inClause = 
'child IN (';
 
 1004        for (
$i = 0; 
$i < count($pathIds); 
$i++) {
 
 1008            $inClause .= 
$ilDB->quote($pathIds[
$i], 
'integer');
 
 1013            'FROM ' . $this->table_tree . 
' ' .
 
 1015            'WHERE ' . $inClause . 
' ' .
 
 1016            'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = ' . $this->ilDB->quote($this->tree_id, 
'integer') . 
' ' .
 
 1020        $pathFull = array();
 
 1026                #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child']); 
 1027                $this->in_tree_cache[
$row[
'child']] = 
$row[
'tree'] == 1;
 
 1050        $res = 
$ilDB->query(
'SELECT t.depth, t.parent, t.child ' .
 
 1051            'FROM ' . $this->table_tree . 
' t ' .
 
 1052            'WHERE ' . 
$ilDB->in(
"child", $a_node_ids, 
false, 
"integer") .
 
 1053            'AND ' . $this->tree_pk . 
' = ' . 
$ilDB->quote($this->tree_id, 
"integer"));
 
 1055            $this->depth_cache[
$row[
"child"]] = 
$row[
"depth"];
 
 1056            $this->parent_cache[
$row[
"child"]] = 
$row[
"parent"];
 
 1069    public function getPathId($a_endnode_id, $a_startnode_id = 0)
 
 1071        if (!$a_endnode_id) {
 
 1073            throw new InvalidArgumentException(__METHOD__ . 
': No endnode given!');
 
 1077        if ($this->
isCacheUsed() && isset($this->path_id_cache[$a_endnode_id][$a_startnode_id])) {
 
 1079            return $this->path_id_cache[$a_endnode_id][$a_startnode_id];
 
 1086            $this->path_id_cache[$a_endnode_id][$a_startnode_id] = $pathIds;
 
 1118        if ($titlePath == 
null || count($titlePath) == 0) {
 
 1119            if ($a_startnode_id == 0) {
 
 1127        if ($a_startnode_id != 
null && $a_startnode_id != 0) {
 
 1130            $parent = $a_startnode_id;
 
 1133            $nodePath = array();
 
 1141        require_once(
'include/Unicode/UtfNormal.php');
 
 1142        include_once 
'./Services/Utilities/classes/class.ilStr.php';
 
 1143        $inClause = 
'd.title IN (';
 
 1144        for (
$i = 0; 
$i < count($titlePath); 
$i++) {
 
 1149            $inClause .= 
$ilDB->quote($titlePath[
$i], 
'text');
 
 1154        if ($this->table_obj_reference) {
 
 1155            $joinClause = 
'JOIN ' . $this->table_obj_reference . 
'  r ON t.child = r.' . $this->ref_pk . 
' ' .
 
 1156                'JOIN ' . $this->table_obj_data . 
' d ON r.' . $this->obj_pk . 
' = d.' . 
$this->obj_pk;
 
 1158            $joinClause = 
'JOIN ' . $this->table_obj_data . 
'  d ON t.child = d.' . 
$this->obj_pk;
 
 1165        $q = 
'SELECT t.depth, t.parent, t.child, d.' . $this->obj_pk . 
' obj_id, d.type, d.title ' .
 
 1166            'FROM ' . $this->table_tree . 
'  t ' .
 
 1168            'WHERE ' . $inClause . 
' ' .
 
 1169            'AND t.depth <= ' . (count($titlePath) + count($nodePath)) . 
' ' .
 
 1171            'ORDER BY t.depth, t.child ASC';
 
 1182        for (
$i = 0; 
$i < count($titlePath); 
$i++) {
 
 1183            $pathElementFound = 
false;
 
 1185                if (
$row[
'parent'] == $parent &&
 
 1190                    $parent = 
$row[
'child'];
 
 1191                    $pathElementFound = 
true;
 
 1196            if (!$pathElementFound) {
 
 1229        $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
 
 1232        if (count($pathIds) == 0) {
 
 1239        for (
$i = 0; 
$i < count($pathIds); 
$i++) {
 
 1240            $types[] = 
'integer';
 
 1244        $query = 
'SELECT t.depth,t.parent,t.child,d.obj_id,d.type,d.title ' .
 
 1245            'FROM ' . $this->table_tree . 
' t ' .
 
 1246            'JOIN ' . $this->table_obj_reference . 
' r ON r.ref_id = t.child ' .
 
 1247            'JOIN ' . $this->table_obj_data . 
' d ON d.obj_id = r.obj_id ' .
 
 1248            'WHERE ' . 
$ilDB->in(
't.child', 
$data, 
false, 
'integer') . 
' ' .
 
 1249            'ORDER BY t.depth ';
 
 1253        $titlePath = array();
 
 1255            $titlePath[] = 
$row;
 
 1274        $types = array(
'integer');
 
 1275        $query = 
'SELECT lft,rgt FROM ' . $this->table_tree . 
' ' .
 
 1276            'WHERE ' . $this->tree_pk . 
' = %s ';
 
 1284        $all = array_merge($lft, $rgt);
 
 1285        $uni = array_unique($all);
 
 1287        if (count($all) != count($uni)) {
 
 1310        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 1311                'WHERE ' . $this->tree_pk . 
' = %s ' .
 
 1313        $r1 = 
$ilDB->queryF(
$query, array(
'integer'), array($this->tree_id));
 
 1317            if ((
$row[
"child"] == 0) && $a_no_zero_child) {
 
 1318                $message = 
"Tree contains child with ID 0!";
 
 1323            if ($this->table_obj_reference) {
 
 1325                $query = 
'SELECT * FROM ' . $this->table_obj_reference . 
' WHERE ' . $this->ref_pk . 
' = %s ';
 
 1329                if ($r2->numRows() == 0) {
 
 1330                    $message = 
"No Object-to-Reference entry found for ID " . 
$row[
"child"] . 
"!";
 
 1334                if ($r2->numRows() > 1) {
 
 1335                    $message = 
"More Object-to-Reference entries found for ID " . 
$row[
"child"] . 
"!";
 
 1341                $obj_ref = 
$ilDB->fetchAssoc($r2);
 
 1343                $query = 
'SELECT * FROM ' . $this->table_obj_data . 
' WHERE ' . $this->obj_pk . 
' = %s';
 
 1344                $r3 = 
$ilDB->queryF(
$query, array(
'integer'), array($obj_ref[$this->obj_pk]));
 
 1345                if ($r3->numRows() == 0) {
 
 1350                if ($r3->numRows() > 1) {
 
 1357                $query = 
'SELECT * FROM ' . $this->table_obj_data . 
' WHERE ' . $this->obj_pk . 
' = %s';
 
 1360                if ($r2->numRows() == 0) {
 
 1361                    $message = 
"No child found for ID " . 
$row[
"child"] . 
"!";
 
 1365                if ($r2->numRows() > 1) {
 
 1366                    $message = 
"More childs found for ID " . 
$row[
"child"] . 
"!";
 
 1391        return $row[
'depth'];
 
 1407            $query = 
'SELECT depth FROM ' . $this->table_tree . 
' ' .
 
 1408                'WHERE child = %s ' .
 
 1409                'AND ' . $this->tree_pk . 
' = %s ';
 
 1410            $res = 
$ilDB->queryF(
$query, array(
'integer',
'integer'), array($a_node_id,$this->tree_id));
 
 1434            throw new InvalidArgumentException(
'Missing or empty parameter $a_node_id: ' . $a_node_id);
 
 1437        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 1438                'WHERE child = ' . 
$ilDB->quote($a_node_id, 
'integer');
 
 1464        if (!isset($a_node_id)) {
 
 1466            throw new InvalidArgumentException(
"No node_id given!");
 
 1469            if ($a_node_id < 1) {
 
 1470                $message = 
'No valid parameter given! $a_node_id: %s' . $a_node_id;
 
 1473                throw new InvalidArgumentException(
$message);
 
 1478        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 1480            'WHERE ' . $this->table_tree . 
'.child = %s ' .
 
 1481            'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s ';
 
 1484            $a_tree_pk === 
null ? $this->tree_id : $a_tree_pk));
 
 1503        $objDefinition = 
$DIC[
'objDefinition'];
 
 1510        $data[
"desc"] = $a_row[
"description"];  
 
 1515        if (is_object($objDefinition)) {
 
 1516            $translation_type = $objDefinition->getTranslationType(
$data[
"type"]);
 
 1520        if ($translation_type == 
"sys") {
 
 1522            if (
$data[
"type"] == 
"rolf" and 
$data[
"obj_id"] != ROLE_FOLDER_ID) {
 
 1528                $data[
"description"] = 
$lng->txt(
"obj_" . 
$data[
"type"] . 
"_desc");
 
 1532        } elseif ($translation_type == 
"db") {
 
 1536                array_key_exists(
$data[
"obj_id"] . 
'.' . $lang_code, $this->translation_cache)) {
 
 1537                $key = 
$data[
"obj_id"] . 
'.' . $lang_code;
 
 1538                $data[
"title"] = $this->translation_cache[
$key][
'title'];
 
 1539                $data[
"description"] = $this->translation_cache[
$key][
'description'];
 
 1540                $data[
"desc"] = $this->translation_cache[
$key][
'desc'];
 
 1544                $query = 
'SELECT title,description FROM object_translation ' .
 
 1545                    'WHERE obj_id = %s ' .
 
 1546                    'AND lang_code = %s ' .
 
 1547                    'AND NOT lang_default = %s';
 
 1549                $res = 
$ilDB->queryF(
$query, array(
'integer',
'text',
'integer'), array(
 
 1563                if ($this->
isCacheUsed() && count($this->translation_cache) < 1000) {
 
 1564                    $key = 
$data[
"obj_id"] . 
'.' . $lang_code;
 
 1565                    $this->translation_cache[
$key] = array();
 
 1566                    $this->translation_cache[
$key][
'title'] = 
$data[
"title"] ;
 
 1567                    $this->translation_cache[
$key][
'description'] = 
$data[
"description"];
 
 1568                    $this->translation_cache[
$key][
'desc'] = 
$data[
"desc"];
 
 1574        if (
$data[
'type'] == 
'crsr' or 
$data[
'type'] == 
'catr' or 
$data[
'type'] == 
'grpr') {
 
 1575            include_once(
'./Services/ContainerReference/classes/class.ilContainerReference.php');
 
 1591        $ilObjDataCache = 
$DIC[
'ilObjDataCache'];
 
 1593        if ($this->
isCacheUsed() && is_array($a_obj_ids) && is_object($ilObjDataCache)) {
 
 1594            foreach ($a_obj_ids as 
$id) {
 
 1595                $this->translation_cache[
$id . 
'.'][
'title'] = $ilObjDataCache->lookupTitle(
$id);
 
 1596                $this->translation_cache[
$id . 
'.'][
'description'] = $ilObjDataCache->lookupDescription(
$id);
 
 1598                $this->translation_cache[
$id . 
'.'][
'desc'] =
 
 1599                    $this->translation_cache[
$id . 
'.'][
'description'];
 
 1618        if (!isset($a_node_id)) {
 
 1620            #$this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
 
 1623        if ($this->
isCacheUsed() && isset($this->in_tree_cache[$a_node_id])) {
 
 1624            #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Using in tree cache '.$a_node_id); 
 1626            return $this->in_tree_cache[$a_node_id];
 
 1629        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 1630            'WHERE ' . $this->table_tree . 
'.child = %s ' .
 
 1631            'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s';
 
 1637        if (
$res->numRows() > 0) {
 
 1639                #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = true'); 
 1640                $this->in_tree_cache[$a_node_id] = 
true;
 
 1645                #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = false'); 
 1646                $this->in_tree_cache[$a_node_id] = 
false;
 
 1668        if (!isset($a_node_id)) {
 
 1670            throw new InvalidArgumentException(__METHOD__ . 
': No node_id given!');
 
 1673        if ($this->table_obj_reference) {
 
 1675            $innerjoin = 
"JOIN " . $this->table_obj_reference . 
" ON v.child=" . $this->table_obj_reference . 
"." . $this->ref_pk . 
" " .
 
 1676                        "JOIN " . $this->table_obj_data . 
" ON " . $this->table_obj_reference . 
"." . $this->obj_pk . 
"=" . $this->table_obj_data . 
"." . $this->obj_pk . 
" ";
 
 1679            $innerjoin = 
"JOIN " . $this->table_obj_data . 
" ON v.child=" . $this->table_obj_data . 
"." . $this->obj_pk . 
" ";
 
 1682        $query = 
'SELECT * FROM ' . $this->table_tree . 
' s, ' . $this->table_tree . 
' v ' .
 
 1684            'WHERE s.child = %s ' .
 
 1685            'AND s.parent = v.child ' .
 
 1686            'AND s.' . $this->tree_pk . 
' = %s ' .
 
 1687            'AND v.' . $this->tree_pk . 
' = %s';
 
 1688        $res = 
$ilDB->queryF(
$query, array(
'integer',
'integer',
'integer'), array(
 
 1717    public function addTree($a_tree_id, $a_node_id = -1)
 
 1726                'Operation not allowed on main tree! $a_tree_if: %s $a_node_id: %s',
 
 1731            throw new InvalidArgumentException(
$message);
 
 1734        if (!isset($a_tree_id)) {
 
 1737            throw new InvalidArgumentException(
$message);
 
 1740        if ($a_node_id <= 0) {
 
 1741            $a_node_id = $a_tree_id;
 
 1744        $query = 
'INSERT INTO ' . $this->table_tree . 
' (' .
 
 1745            $this->tree_pk . 
', child,parent,lft,rgt,depth) ' .
 
 1747            '(%s,%s,%s,%s,%s,%s)';
 
 1748        $res = 
$ilDB->manipulateF(
$query, array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'), array(
 
 1776            throw new InvalidArgumentException(
'Type not given or wrong datatype');
 
 1779        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 1781            'WHERE ' . $this->table_obj_data . 
'.type = ' . $this->ilDB->quote(
$a_type, 
'text') .
 
 1782            'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = ' . $this->ilDB->quote($this->tree_id, 
'integer');
 
 1810            throw new InvalidArgumentException(
'Operation not allowed on main tree');
 
 1814            throw new InvalidArgumentException(
'Missing parameter tree id');
 
 1817        $query = 
'DELETE FROM ' . $this->table_tree .
 
 1818            ' WHERE ' . $this->tree_pk . 
' = %s ';
 
 1819        $ilDB->manipulateF(
$query, array(
'integer'), array($a_tree_id));
 
 1838            throw new InvalidArgumentException(
'No valid parameter given! $a_node_id: ' . $a_node_id);
 
 1845        $subnodes = array();
 
 1847            $subnodes[] = 
$row[
'child'];
 
 1850        if (!count($subnodes)) {
 
 1855        if ($a_set_deleted) {
 
 1856            include_once 
'./Services/Object/classes/class.ilObject.php';
 
 1878        return $this->
moveToTrash($a_node_id, $a_set_deleted);
 
 1887        return $this->
isSaved($a_node_id);
 
 1902        if ($this->
isCacheUsed() && isset($this->is_saved_cache[$a_node_id])) {
 
 1904            return $this->is_saved_cache[$a_node_id];
 
 1907        $query = 
'SELECT ' . $this->tree_pk . 
' FROM ' . $this->table_tree . 
' ' .
 
 1908            'WHERE child = %s ';
 
 1912        if (
$row[$this->tree_pk] < 0) {
 
 1914                $this->is_saved_cache[$a_node_id] = 
true;
 
 1919                $this->is_saved_cache[$a_node_id] = 
false;
 
 1937        if (!is_array($a_node_ids) || !$this->
isCacheUsed()) {
 
 1941        $query = 
'SELECT ' . $this->tree_pk . 
', child FROM ' . $this->table_tree . 
' ' .
 
 1942            'WHERE ' . 
$ilDB->in(
"child", $a_node_ids, 
false, 
"integer");
 
 1946            if (
$row[$this->tree_pk] < 0) {
 
 1948                    $this->is_saved_cache[
$row[
"child"]] = 
true;
 
 1952                    $this->is_saved_cache[
$row[
"child"]] = 
false;
 
 1972        if (!isset($a_parent_id)) {
 
 1975            throw new InvalidArgumentException(
$message);
 
 1978        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 1980            'WHERE ' . $this->table_tree . 
'.' . $this->tree_pk . 
' < %s ' .
 
 1981            'AND ' . $this->table_tree . 
'.parent = %s';
 
 1990        return $saved ? $saved : array();
 
 2005        $query = 
'SELECT ' . $this->table_obj_data . 
'.obj_id FROM ' . $this->table_tree . 
' ' .
 
 2007            'WHERE ' . $this->table_tree . 
'.' . $this->tree_pk . 
' < ' . 
$ilDB->quote(0, 
'integer') . 
' ' .
 
 2008            'AND ' . 
$ilDB->in($this->table_obj_data . 
'.obj_id', $a_obj_ids, 
'', 
'integer');
 
 2011            $saved[] = 
$row[
'obj_id'];
 
 2014        return $saved ? $saved : array();
 
 2030        if (!isset($a_node_id)) {
 
 2033            throw new InvalidArgumentException(
$message);
 
 2036        $query = 
'SELECT parent FROM ' . $this->table_tree . 
' ' .
 
 2037            'WHERE child = %s ' .
 
 2038            'AND ' . $this->tree_pk . 
' = %s ';
 
 2044        return $row->parent;
 
 2060        if (!isset($a_node_id)) {
 
 2063            throw new InvalidArgumentException(
$message);
 
 2066        $query = 
'SELECT lft FROM ' . $this->table_tree . 
' ' .
 
 2067            'WHERE child = %s ' .
 
 2068            'AND ' . $this->tree_pk . 
' = %s ';
 
 2089        if (!isset($a_node)) {
 
 2092            throw new InvalidArgumentException(
$message);
 
 2096            $query = 
'SELECT count(*) cnt FROM ' . $this->table_tree . 
' ' .
 
 2098                'WHERE lft <= %s ' .
 
 2100                'AND parent = %s ' .
 
 2101                'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s ';
 
 2103            $res = 
$ilDB->queryF(
$query, array(
'integer',
'text',
'integer',
'integer'), array(
 
 2109            $query = 
'SELECT count(*) cnt FROM ' . $this->table_tree . 
' ' .
 
 2111                'WHERE lft <= %s ' .
 
 2112                'AND parent = %s ' .
 
 2113                'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s ';
 
 2115            $res = 
$ilDB->queryF(
$query, array(
'integer',
'integer',
'integer'), array(
 
 2136        $query = 
'SELECT child FROM ' . $this->table_tree . 
' ' .
 
 2137            'WHERE parent = %s ' .
 
 2138            'AND ' . $this->tree_pk . 
' = %s ';
 
 2143        $this->root_id = 
$row->child;
 
 2158        $this->root_id = $a_root_id;
 
 2178        $this->tree_id = $a_tree_id;
 
 2195        if (!isset($a_node_id)) {
 
 2198            throw new InvalidArgumentException(
$message);
 
 2202        $query = 
'SELECT lft FROM ' . $this->table_tree . 
' ' .
 
 2203            'WHERE ' . $this->table_tree . 
'.child = %s ' .
 
 2204            'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s ';
 
 2211            $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 2214                'AND ' . $this->table_obj_data . 
'.type = %s ' .
 
 2215                'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s ' .
 
 2218            $res = 
$ilDB->queryF(
$query, array(
'integer',
'text',
'integer'), array(
 
 2223            $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 2226                'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s ' .
 
 2234        if (
$res->numRows() < 1) {
 
 2256        if (!isset($a_node_id)) {
 
 2259            throw new InvalidArgumentException(
$message);
 
 2263        $query = 
'SELECT lft FROM ' . $this->table_tree . 
' ' .
 
 2264            'WHERE ' . $this->table_tree . 
'.child = %s ' .
 
 2265            'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s ';
 
 2273            $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 2276                'AND ' . $this->table_obj_data . 
'.type = %s ' .
 
 2277                'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s ' .
 
 2278                'ORDER BY lft DESC';
 
 2280            $res = 
$ilDB->queryF(
$query, array(
'integer',
'text',
'integer'), array(
 
 2285            $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 2288                'AND ' . $this->table_tree . 
'.' . $this->tree_pk . 
' = %s ' .
 
 2289                'ORDER BY lft DESC';
 
 2296        if (
$res->numRows() < 1) {
 
 2324            $ilAtomQuery = 
$ilDB->buildAtomQuery();
 
 2325            $ilAtomQuery->addTableLock($this->table_tree);
 
 2327            $ilAtomQuery->addQueryCallable($renumber_callable);
 
 2328            $ilAtomQuery->run();
 
 2330            $renumber_callable(
$ilDB);
 
 2351        $query = 
'UPDATE ' . $this->table_tree . 
' SET lft = %s WHERE child = %s AND tree = %s';
 
 2352        $res = 
$ilDB->manipulateF(
$query, array(
'integer',
'integer',
'integer'), array(
 
 2361        foreach ($childs as $child) {
 
 2367        if (count($childs) > 0) {
 
 2368            $i += $this->gap * 2;
 
 2372        $query = 
'UPDATE ' . $this->table_tree . 
' SET rgt = %s WHERE child = %s AND tree = %s';
 
 2373        $res = 
$ilDB->manipulateF(
$query, array(
'integer',
'integer', 
'integer'), array(
 
 2394        $cache_key = $a_ref_id . 
'.' . 
$a_type . 
'.' . ((int) $a_exclude_source_check);
 
 2398            array_key_exists($cache_key, $this->parent_type_cache)) {
 
 2399            return $this->parent_type_cache[$cache_key];
 
 2403        $do_cache = ($this->
__isMainTree() && count($this->parent_type_cache) < 1000);
 
 2408                $this->parent_type_cache[$cache_key] = 
false;
 
 2416        if ($a_exclude_source_check) {
 
 2420        foreach (
$path as $node) {
 
 2422            if ($node[
"type"] == 
$a_type) {
 
 2424                    $this->parent_type_cache[$cache_key] = $node[
"child"];
 
 2426                return $node[
"child"];
 
 2431            $this->parent_type_cache[$cache_key] = 
false;
 
 2446    public static function _removeEntry($a_tree, $a_child, $a_db_table = 
"tree")
 
 2452        if ($a_db_table === 
'tree') {
 
 2453            if ($a_tree == 1 and $a_child == ROOT_FOLDER_ID) {
 
 2455                    'Tried to delete root node! $a_tree: %s $a_child: %s',
 
 2460                throw new InvalidArgumentException(
$message);
 
 2464        $query = 
'DELETE FROM ' . $a_db_table . 
' ' .
 
 2465            'WHERE tree = %s ' .
 
 2480        return $this->table_tree === 
'tree';
 
 2502        $this->log->debug(
$query);
 
 2505        $counter = (int) $lft_childs = array();
 
 2507            $lft_childs[
$row->child] = 
$row->parent;
 
 2512        if ($counter != count($lft_childs)) {
 
 2513            $message = 
'Duplicate entries for "child" in maintree! $a_node_id: ' . $a_node[
'child'];
 
 2520        $parent_childs = array();
 
 2543        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 2544            'WHERE child = %s ' .
 
 2552            $parent_childs[$a_node_id] = 
$row->parent;
 
 2557            $message = 
'Multiple entries in maintree! $a_node_id: ' . $a_node_id;
 
 2564        $query = 
'SELECT * FROM ' . $this->table_tree . 
' ' .
 
 2565            'WHERE parent = %s ';
 
 2586        ksort($parent_childs);
 
 2588        $this->log->debug(
'left childs ' . print_r($lft_childs, 
true));
 
 2589        $this->log->debug(
'parent childs ' . print_r($parent_childs, 
true));
 
 2591        if (count($lft_childs) != count($parent_childs)) {
 
 2592            $message = 
'(COUNT) Tree is corrupted! Left/Right subtree does not comply with parent relation';
 
 2598        foreach ($lft_childs as 
$key => $value) {
 
 2599            if ($parent_childs[
$key] != $value) {
 
 2600                $message = 
'(COMPARE) Tree is corrupted! Left/Right subtree does not comply with parent relation';
 
 2604            if (
$key == ROOT_FOLDER_ID) {
 
 2605                $message = 
'(ROOT_FOLDER) Tree is corrupted! Tried to delete root folder';
 
 2622    public function moveTree($a_source_id, $a_target_id, $a_location = self::POS_LAST_NODE)
 
 2624        $old_parent_id = $this->
getParentId($a_source_id);
 
 2627            $GLOBALS[
'DIC'][
'ilAppEventHandler']->raise(
 
 2631                        'tree' => $this->table_tree,
 
 2632                        'source_id' => $a_source_id,
 
 2633                        'target_id' => $a_target_id,
 
 2634                        'old_parent_id' => $old_parent_id
 
 2664    public function getSubTreeQuery($a_node_id, $a_fields = array(), $a_types = 
'', $a_force_join_reference = 
false)
 
 2669            $a_force_join_reference,
 
 2690        if (!
sizeof($node)) {
 
 2699        if (count($a_fields)) {
 
 2700            $fields = implode(
',', $a_fields);
 
 2703        $query = 
"SELECT " . $fields .
 
 2709        while (
$row = 
$ilDB->fetchAssoc($set)) {
 
 2721        $ilAppEventHandler = 
$DIC[
'ilAppEventHandler'];
 
 2723        $query = 
'DELETE FROM tree where ' .
 
 2724                'child = ' . 
$ilDB->quote($a_node_id, 
'integer') . 
' ' .
 
 2725                'AND tree = ' . 
$ilDB->quote($a_tree_id, 
'integer');
 
 2728        $ilAppEventHandler->raise(
 
 2731            array(
'tree' => $this->table_tree,
 
 2732                          'node_id' => $a_node_id,
 
 2733                          'tree_id' => $a_tree_id
 
 2749        $query = 
'SELECT DISTINCT(o.type) ' . 
$ilDB->quoteIdentifier(
'type') . 
' FROM tree t JOIN object_reference r ON child = r.ref_id ' .
 
 2750                'JOIN object_data o on r.obj_id = o.obj_id ' .
 
 2751                'WHERE tree < ' . 
$ilDB->quote(0, 
'integer') . 
' ' .
 
 2752                'AND child = -tree ' .
 
 2756        $types_deleted = array();
 
 2758            $types_deleted[] = 
$row->type;
 
 2760        return $types_deleted;
 
An exception for terminatinating execution or to throw for unit testing.
static toNFC($string)
Convert a UTF-8 string to normal form C, canonical composition.
static _lookupTitle($a_obj_id)
Overwitten from base class.
Thrown if invalid tree strucutes are found.
static getLogger($a_component_id)
Get component logger.
Base class for materialize path based trees Based on implementation of Werner Randelshofer.
Base class for nested set path based trees.
static setDeletedDates($a_ref_ids)
Set deleted date.
static _resetDeletedDate($a_ref_id)
only called in ilObjectGUI::insertSavedNodes
static strToLower($a_string)
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
isCacheUsed()
Check if cache is active.
fetchPredecessorNode($a_node_id, $a_type="")
get node data of predecessor node
lookupTrashedObjectTypes()
Lookup object types in trash @global type $ilDB.
getRelation($a_node_a, $a_node_b)
Get relation of two nodes.
moveToTrash($a_node_id, $a_set_deleted=false)
Wrapper for saveSubTree.
getSubTree($a_node, $a_with_data=true, $a_type="")
get all nodes in the subtree under specified node
getFilteredChilds($a_filter, $a_node, $a_order="", $a_direction="ASC")
get child nodes of given node (exclude filtered obj_types) @access public
isGrandChild($a_startnode_id, $a_querynode_id)
checks if a node is in the path of an other node @access public
getSubTreeTypes($a_node, $a_filter=0)
get types of nodes in the subtree under specified node
getRelationOfNodes($a_node_a_arr, $a_node_b_arr)
get relation of two nodes by node data
setObjectTablePK($a_column_name)
set column containing primary key in object table @access public
getTreePk()
Get tree primary key.
getParentId($a_node_id)
get parent id of given node @access public
getRbacSubtreeInfo($a_endnode_id)
This method is used for change existing objects and returns all necessary information for this action...
getParentCache()
Get parent cache.
setReferenceTablePK($a_column_name)
set column containing primary key in reference table @access public
saveSubTree($a_node_id, $a_set_deleted=false)
Use the wrapper moveToTrash save subtree: delete a subtree (defined by node_id) to a new tree with $t...
checkTreeChilds($a_no_zero_child=true)
check, if all childs of tree nodes exist in object table
getDepth($a_node_id)
return depth of a node in tree @access private
getSavedNodeData($a_parent_id)
get data saved/deleted nodes
getChildSequenceNumber($a_node, $type="")
get sequence number of node in sibling sequence @access public
insertNodeFromTrash($a_source_id, $a_target_id, $a_tree_id, $a_pos=IL_LAST_NODE, $a_reset_deleted_date=false)
Insert node from trash deletes trash entry.
useCache($a_use=true)
Use Cache (usually activated)
deleteTree($a_node)
delete node and the whole subtree under this node @access public
getLeftValue($a_node_id)
get left value of given node @access public
__checkDelete($a_node)
Check for deleteTree() compares a subtree of a given node by checking lft, rgt against parent relatio...
fetchSuccessorNode($a_node_id, $a_type="")
get node data of successor node
getDepthCache()
Get depth cache.
getTreeId()
get tree id @access public
getChildIds($a_node)
Get node child ids @global type $ilDB.
getNodeDataByType($a_type)
get nodes by type
getTreeTable()
Get tree table name.
static _removeEntry($a_tree, $a_child, $a_db_table="tree")
STATIC METHOD Removes a single entry from a tree.
getSubTreeQuery($a_node_id, $a_fields=array(), $a_types='', $a_force_join_reference=false)
Get tree subtree query.
__renumber($node_id=1, $i=1)
This method is private.
setTreeTablePK($a_column_name)
set column containing primary key in tree table @access public
isDeleted($a_node_id)
This is a wrapper for isSaved() with a more useful name.
getNodeTreeData($a_node_id)
return all columns of tabel tree
setTableNames($a_table_tree, $a_table_obj_data, $a_table_obj_reference="")
set table names The primary key of the table containing your object_data must be 'obj_id' You may use...
getTableReference()
Get reference table if available.
fetchTranslationFromObjectDataCache($a_obj_ids)
Get translation data from object cache (trigger in object cache on preload)
readRootId()
read root id from database
removeTree($a_tree_id)
remove an existing tree
fetchNodeData($a_row)
get data of parent node from tree and object_data @access private
checkTree()
check consistence of tree all left & right values are checked if they are exists only once @access pu...
getSubTreeFilteredByObjIds($a_node_id, array $a_obj_ids, array $a_fields=array())
get all node ids in the subtree under specified node id, filter by object ids
renumber($node_id=1, $i=1)
Wrapper for renumber.
getNodePath($a_endnode_id, $a_startnode_id=0)
Returns the node path for the specified object reference.
getChildsByType($a_node_id, $a_type)
get child nodes of given node by object type @access public
getNodeData($a_node_id, $a_tree_pk=null)
get all information of a node.
setTreeId($a_tree_id)
set tree id @access public
getSavedNodeObjIds(array $a_obj_ids)
get object id of saved/deleted nodes
getChildsByTypeFilter($a_node_id, $a_types, $a_order="", $a_direction="ASC")
get child nodes of given node by object type @access public
deleteNode($a_tree_id, $a_node_id)
getMaximumDepth()
Return the current maximum depth in the tree @access public.
moveTree($a_source_id, $a_target_id, $a_location=self::POS_LAST_NODE)
Move Tree Implementation.
preloadDepthParent($a_node_ids)
Preload depth/parent.
isSaved($a_node_id)
Use method isDeleted check if node is saved.
initLangCode()
Store user language.
buildJoin()
build join depending on table settings @access private
getTreeImplementation()
Get tree implementation.
getNodePathForTitlePath($titlePath, $a_startnode_id=null)
Converts a path consisting of object titles into a path consisting of tree nodes.
initTreeImplementation()
Init tree implementation.
preloadDeleted($a_node_ids)
Preload deleted information.
__construct($a_tree_id, $a_root_id=0)
Constructor @access public.
getFilteredSubTree($a_node_id, $a_filter=array())
get filtered subtree
getObjectDataTable()
Get object data table.
getRootId()
get the root id of tree @access public
insertNode($a_node_id, $a_parent_id, $a_pos=IL_LAST_NODE, $a_reset_deletion_date=false)
insert new node with node_id under parent node with parent_id @access public
checkForParentType($a_ref_id, $a_type, $a_exclude_source_check=false)
Check for parent type e.g check if a folder (ref_id 3) is in a parent course obj => checkForParentTyp...
__isMainTree()
Check if operations are done on main tree.
__getSubTreeByParentRelation($a_node_id, &$parent_childs)
@global type $ilDB
isInTree($a_node_id)
get all information of a node.
getGap()
Get default gap *.
__validateSubtrees(&$lft_childs, $parent_childs)
getPathId($a_endnode_id, $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
addTree($a_tree_id, $a_node_id=-1)
create a new tree to do: ???
getPathFull($a_endnode_id, $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
getParentNodeData($a_node_id)
get data of parent node from tree and object_data @access public
getChilds($a_node_id, $a_order="", $a_direction="ASC")
get child nodes of given node @access public
validateParentRelations()
Validate parent relations of tree.
getSubTreeIds($a_ref_id)
Get all ids of subnodes.
static quoteArray($a_array)
Quotes all members of an array for usage in DB query statement.
static shortenText( $a_str, $a_len, $a_dots=false, $a_next_blank=false, $a_keep_extension=false)
shorten a string to given length.
if(!array_key_exists('StateId', $_REQUEST)) $id
catch(Exception $e) $message
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
foreach($_POST as $key=> $value) $res