4 define(
"IL_LAST_NODE", -2);
5 define(
"IL_FIRST_NODE", -1);
7 include_once
'./Services/Tree/exceptions/class.ilInvalidTreeStructureException.php';
147 function ilTree($a_tree_id, $a_root_id = 0)
164 $this->lang_code =
"en";
166 if (!isset($a_tree_id) or (func_num_args() == 0) )
168 $this->ilErr->raiseError(get_class($this).
"::Constructor(): No tree_id given!",$this->ilErr->WARNING);
171 if (func_num_args() > 2)
173 $this->ilErr->raiseError(get_class($this).
"::Constructor(): Wrong parameter count!",$this->ilErr->WARNING);
180 if (empty($a_root_id))
182 $a_root_id = ROOT_FOLDER_ID;
185 $this->tree_id = $a_tree_id;
186 $this->root_id = $a_root_id;
187 $this->table_tree =
'tree';
188 $this->table_obj_data =
'object_data';
189 $this->table_obj_reference =
'object_reference';
190 $this->ref_pk =
'ref_id';
191 $this->obj_pk =
'obj_id';
192 $this->tree_pk =
'tree';
194 $this->use_cache =
true;
197 $this->translation_cache = array();
198 $this->parent_type_cache = array();
216 if(!is_object(
$GLOBALS[
'ilSetting']) or
$GLOBALS[
'ilSetting']->getModule() !=
'common')
218 include_once
'./Services/Administration/classes/class.ilSetting.php';
228 if($setting->get(
'main_tree_impl',
'ns') ==
'ns')
230 #$GLOBALS['ilLog']->write(__METHOD__.': Using nested set.'); 231 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
236 #$GLOBALS['ilLog']->write(__METHOD__.': Using materialized path.'); 237 include_once
'./Services/Tree/classes/class.ilMaterializedPathTree.php';
243 #$GLOBALS['ilLog']->write(__METHOD__.': Using netsted set for non main tree.'); 244 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
263 $this->use_cache = $a_use;
302 if (!is_object($ilUser))
304 $this->lang_code =
"en";
308 $this->lang_code = $ilUser->getCurrentLanguage();
360 $this->in_tree_cache = array();
378 function setTableNames($a_table_tree,$a_table_obj_data,$a_table_obj_reference =
"")
380 if (!isset($a_table_tree) or !isset($a_table_obj_data))
382 $this->ilErr->raiseError(get_class($this).
"::setTableNames(): Missing parameter! ".
383 "tree table: ".$a_table_tree.
" object data table: ".$a_table_obj_data,$this->ilErr->WARNING);
386 $this->table_tree = $a_table_tree;
387 $this->table_obj_data = $a_table_obj_data;
388 $this->table_obj_reference = $a_table_obj_reference;
403 if (!isset($a_column_name))
405 $this->ilErr->raiseError(get_class($this).
"::setReferenceTablePK(): No column name given!",$this->ilErr->WARNING);
408 $this->ref_pk = $a_column_name;
420 if (!isset($a_column_name))
422 $this->ilErr->raiseError(get_class($this).
"::setObjectTablePK(): No column name given!",$this->ilErr->WARNING);
425 $this->obj_pk = $a_column_name;
437 if (!isset($a_column_name))
439 $this->ilErr->raiseError(get_class($this).
"::setTreeTablePK(): No column name given!",$this->ilErr->WARNING);
442 $this->tree_pk = $a_column_name;
453 if ($this->table_obj_reference)
456 return "JOIN ".$this->table_obj_reference.
" ON ".$this->table_tree.
".child=".$this->table_obj_reference.
".".$this->ref_pk.
" ".
457 "JOIN ".$this->table_obj_data.
" ON ".$this->table_obj_reference.
".".$this->obj_pk.
"=".$this->table_obj_data.
".".$this->obj_pk.
" ";
462 return "JOIN ".$this->table_obj_data.
" ON ".$this->table_tree.
".child=".$this->table_obj_data.
".".$this->obj_pk.
" ";
500 $query =
'SELECT * FROM tree '.
501 'WHERE parent = '.$ilDB->quote($a_node,
'integer').
' '.
502 'AND tree > '.$ilDB->quote(0,
'integer');
508 $childs[] =
$row->child;
521 function getChilds($a_node_id, $a_order =
"", $a_direction =
"ASC")
525 if (!isset($a_node_id))
527 $message = get_class($this).
"::getChilds(): No node_id given!";
528 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
541 if (!empty($a_order))
543 $order_clause =
"ORDER BY ".$a_order.
" ".$a_direction;
547 $order_clause =
"ORDER BY ".$this->table_tree.
".lft";
551 $query = sprintf(
'SELECT * FROM '.$this->table_tree.
' '.
553 "WHERE parent = %s " .
554 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
556 $ilDB->quote($a_node_id,
'integer'),
557 $ilDB->quote($this->tree_id,
'integer'));
561 if(!$count = $res->numRows())
568 while(
$r = $ilDB->fetchAssoc($res))
571 $obj_ids[] =
$r[
"obj_id"];
576 is_object($ilUser) && $this->lang_code == $ilUser->getLanguage() && !$this->oc_preloaded[$a_node_id])
579 $ilObjDataCache->preloadObjectCache($obj_ids, $this->lang_code);
581 $this->oc_preloaded[$a_node_id] =
true;
584 foreach ($rows as
$row)
591 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child'].' = true'); 592 $this->in_tree_cache[$row[
'child']] = $row[
'tree'] == 1;
595 $childs[$count - 1][
"last"] =
true;
610 $childs = $this->
getChilds($a_node,$a_order,$a_direction);
612 foreach($childs as $child)
614 if(!in_array($child[
"type"],$a_filter))
616 $filtered[] = $child;
619 return $filtered ? $filtered : array();
634 if (!isset($a_node_id) or !isset($a_type))
636 $message = get_class($this).
"::getChildsByType(): Missing parameter! node_id:".$a_node_id.
" type:".$a_type;
637 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
640 if ($a_type==
'rolf' && $this->table_obj_reference) {
644 $ilDB->setLimit(1,0);
645 $query = sprintf(
"SELECT * FROM ".$this->table_tree.
" ".
647 "WHERE parent = %s ".
648 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
649 "AND ".$this->table_obj_data.
".type = %s ",
650 $ilDB->quote($a_node_id,
'integer'),
651 $ilDB->quote($this->tree_id,
'integer'),
652 $ilDB->quote($a_type,
'text'));
654 $query = sprintf(
"SELECT * FROM ".$this->table_tree.
" ".
656 "WHERE parent = %s ".
657 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
658 "AND ".$this->table_obj_data.
".type = %s ".
659 "ORDER BY ".$this->table_tree.
".lft",
660 $ilDB->quote($a_node_id,
'integer'),
661 $ilDB->quote($this->tree_id,
'integer'),
662 $ilDB->quote($a_type,
'text'));
668 while(
$row = $ilDB->fetchAssoc($res))
673 return $childs ? $childs : array();
688 if (!isset($a_node_id) or !$a_types)
690 $message = get_class($this).
"::getChildsByType(): Missing parameter! node_id:".$a_node_id.
" type:".$a_types;
691 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
697 $filter =
'AND '.$this->table_obj_data.
'.type IN('.implode(
',',
ilUtil::quoteArray($a_types)).
') ';
701 if (!empty($a_order))
703 $order_clause =
"ORDER BY ".$a_order.
" ".$a_direction;
707 $order_clause =
"ORDER BY ".$this->table_tree.
".lft";
710 $query =
'SELECT * FROM '.$this->table_tree.
' '.
712 'WHERE parent = '.$ilDB->quote($a_node_id,
'integer').
' '.
713 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = '.$ilDB->quote($this->tree_id,
'integer').
' '.
718 while(
$row = $ilDB->fetchAssoc(
$res))
723 return $childs ? $childs : array();
741 if($a_source_id <= 1 or $a_target_id <= 0)
747 if (!isset($a_source_id) or !isset($a_target_id))
759 $query =
'DELETE from tree '.
760 'WHERE tree = '.$ilDB->quote($a_tree_id,
'integer').
' '.
761 'AND child = '.$ilDB->quote($a_source_id,
'integer');
762 $ilDB->manipulate(
$query);
783 if($a_node_id <= 1 or $a_parent_id <= 0)
786 $message = sprintf(
'%s::insertNode(): Invalid parameters! $a_node_id: %s $a_parent_id: %s',
790 $this->log->write($message,$this->log->FATAL);
791 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
796 if (!isset($a_node_id) or !isset($a_parent_id))
799 $this->ilErr->raiseError(get_class($this).
"::insertNode(): Missing parameter! ".
800 "node_id: ".$a_node_id.
" parent_id: ".$a_parent_id,$this->ilErr->WARNING);
804 $this->ilErr->raiseError(get_class($this).
"::insertNode(): Node ".$a_node_id.
" already in tree ".
805 $this->table_tree.
"!",$this->ilErr->WARNING);
810 $this->in_tree_cache[$a_node_id] =
true;
813 if ($a_reset_deletion_date)
819 $GLOBALS[
'ilAppEventHandler']->raise(
823 'tree' => $this->table_tree,
824 'node_id' => $a_node_id,
825 'parent_id' => $a_parent_id)
850 if($depth and $subnode[
'depth'] > $depth)
854 if(!$first and in_array($subnode[
'type'],$a_filter))
856 $depth = $subnode[
'depth'];
862 $filtered[] = $subnode;
864 return $filtered ? $filtered : array();
887 function getSubTree($a_node,$a_with_data =
true, $a_type =
"")
891 if (!is_array($a_node))
912 while(
$row = $ilDB->fetchAssoc(
$res))
920 $subtree[] =
$row[
'child'];
923 if($this->
__isMainTree() || $this->table_tree ==
"lm_tree")
925 $this->in_tree_cache[
$row[
'child']] =
true;
928 return $subtree ? $subtree : array();
941 $a_filter = $a_filter ? $a_filter : array();
943 foreach($this->getSubtree($this->
getNodeData($a_node)) as $node)
945 if(in_array($node[
"type"],$a_filter))
949 $types[
"$node[type]"] = $node[
"type"];
951 return $types ? $types : array();
964 $GLOBALS[
'ilLog']->write(__METHOD__.
': Delete tree with node '. $a_node);
966 if (!is_array($a_node))
972 $GLOBALS[
'ilLog']->write(__METHOD__.
': '. $this->tree_pk);
1012 $pathIds =& $this->
getPathId($a_endnode_id, $a_startnode_id);
1018 if (count($pathIds) == 0)
1023 $inClause =
'child IN (';
1024 for ($i=0; $i < count($pathIds); $i++)
1026 if ($i > 0) $inClause .=
',';
1027 $inClause .= $ilDB->quote($pathIds[$i],
'integer');
1032 'FROM '.$this->table_tree.
' '.
1034 'WHERE '.$inClause.
' '.
1035 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = '.$this->
ilDB->
quote($this->tree_id,
'integer').
' '.
1037 $r = $ilDB->query($q);
1039 $pathFull = array();
1047 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child']); 1048 $this->in_tree_cache[
$row[
'child']] = $row[
'tree'] == 1;
1070 $res = $ilDB->query(
'SELECT t.depth, t.parent, t.child '.
1071 'FROM '.$this->table_tree.
' t '.
1072 'WHERE '.$ilDB->in(
"child", $a_node_ids,
false,
"integer").
1073 'AND '.$this->tree_pk.
' = '.$ilDB->quote($this->tree_id,
"integer"));
1074 while (
$row = $ilDB->fetchAssoc(
$res))
1076 $this->depth_cache[
$row[
"child"]] = $row[
"depth"];
1077 $this->parent_cache[$row[
"child"]] = $row[
"parent"];
1090 public function getPathId($a_endnode_id, $a_startnode_id = 0)
1099 if ($this->
isCacheUsed() && isset($this->path_id_cache[$a_endnode_id][$a_startnode_id]))
1102 return $this->path_id_cache[$a_endnode_id][$a_startnode_id];
1110 $this->path_id_cache[$a_endnode_id][$a_startnode_id] = $pathIds;
1139 if ($titlePath == null || count($titlePath) == 0)
1141 if ($a_startnode_id == 0)
1152 if ($a_startnode_id != null && $a_startnode_id != 0)
1156 $parent = $a_startnode_id;
1161 $nodePath = array();
1169 require_once(
'include/Unicode/UtfNormal.php');
1170 include_once
'./Services/Utilities/classes/class.ilStr.php';
1171 $inClause =
'd.title IN (';
1172 for ($i=0; $i < count($titlePath); $i++)
1175 if ($i > 0) $inClause .=
',';
1176 $inClause .= $ilDB->quote($titlePath[$i],
'text');
1181 if ($this->table_obj_reference)
1183 $joinClause =
'JOIN '.$this->table_obj_reference.
' r ON t.child = r.'.$this->ref_pk.
' '.
1184 'JOIN '.$this->table_obj_data.
' d ON r.'.$this->obj_pk.
' = d.'.
$this->obj_pk;
1188 $joinClause =
'JOIN '.$this->table_obj_data.
' d ON t.child = d.'.
$this->obj_pk;
1195 $q =
'SELECT t.depth, t.parent, t.child, d.'.$this->obj_pk.
' obj_id, d.type, d.title '.
1196 'FROM '.$this->table_tree.
' t '.
1198 'WHERE '.$inClause.
' '.
1199 'AND t.depth <= '.(count($titlePath)+count($nodePath)).
' '.
1201 'ORDER BY t.depth, t.child ASC';
1202 $r = $ilDB->query($q);
1213 for ($i = 0; $i < count($titlePath); $i++) {
1214 $pathElementFound =
false;
1215 foreach ($rows as
$row) {
1216 if ($row[
'parent'] == $parent &&
1222 $parent = $row[
'child'];
1223 $pathElementFound =
true;
1228 if (! $pathElementFound)
1260 $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
1263 if (count($pathIds) == 0)
1271 for ($i = 0; $i < count($pathIds); $i++)
1273 $types[] =
'integer';
1274 $data[] = $pathIds[$i];
1277 $query =
'SELECT t.depth,t.parent,t.child,d.obj_id,d.type,d.title '.
1278 'FROM '.$this->table_tree.
' t '.
1279 'JOIN '.$this->table_obj_reference.
' r ON r.ref_id = t.child '.
1280 'JOIN '.$this->table_obj_data.
' d ON d.obj_id = r.obj_id '.
1281 'WHERE '.$ilDB->in(
't.child',
$data,
false,
'integer').
' '.
1282 'ORDER BY t.depth ';
1286 $titlePath = array();
1287 while (
$row = $ilDB->fetchAssoc(
$res))
1289 $titlePath[] =
$row;
1305 $types = array(
'integer');
1306 $query =
'SELECT lft,rgt FROM '.$this->table_tree.
' '.
1307 'WHERE '.$this->tree_pk.
' = %s ';
1309 $res = $ilDB->queryF(
$query,$types,array($this->tree_id));
1310 while (
$row = $ilDB->fetchObject(
$res))
1316 $all = array_merge($lft,$rgt);
1317 $uni = array_unique($all);
1319 if (count($all) != count($uni))
1321 $message = sprintf(
'%s::checkTree(): Tree is corrupted!',
1324 $this->log->write($message,$this->log->FATAL);
1325 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
1338 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1339 'WHERE '.$this->tree_pk.
' = %s '.
1341 $r1 = $ilDB->queryF(
$query,array(
'integer'),array($this->tree_id));
1343 while (
$row = $ilDB->fetchAssoc($r1))
1346 if ((
$row[
"child"] == 0) && $a_no_zero_child)
1348 $this->ilErr->raiseError(get_class($this).
"::checkTreeChilds(): Tree contains child with ID 0!",$this->ilErr->WARNING);
1351 if ($this->table_obj_reference)
1354 $query =
'SELECT * FROM '.$this->table_obj_reference.
' WHERE '.$this->ref_pk.
' = %s ';
1355 $r2 = $ilDB->queryF(
$query,array(
'integer'),array(
$row[
'child']));
1358 if ($r2->numRows() == 0)
1360 $this->ilErr->raiseError(get_class($this).
"::checkTree(): No Object-to-Reference entry found for ID ".
1361 $row[
"child"].
"!",$this->ilErr->WARNING);
1363 if ($r2->numRows() > 1)
1365 $this->ilErr->raiseError(get_class($this).
"::checkTree(): More Object-to-Reference entries found for ID ".
1366 $row[
"child"].
"!",$this->ilErr->WARNING);
1370 $obj_ref = $ilDB->fetchAssoc($r2);
1372 $query =
'SELECT * FROM '.$this->table_obj_data.
' WHERE '.$this->obj_pk.
' = %s';
1373 $r3 = $ilDB->queryF(
$query,array(
'integer'),array($obj_ref[$this->obj_pk]));
1374 if ($r3->numRows() == 0)
1376 $this->ilErr->raiseError(get_class($this).
"::checkTree(): No child found for ID ".
1377 $obj_ref[$this->obj_pk].
"!",$this->ilErr->WARNING);
1379 if ($r3->numRows() > 1)
1381 $this->ilErr->raiseError(get_class($this).
"::checkTree(): More childs found for ID ".
1382 $obj_ref[$this->obj_pk].
"!",$this->ilErr->WARNING);
1389 $query =
'SELECT * FROM '.$this->table_obj_data.
' WHERE '.$this->obj_pk.
' = %s';
1390 $r2 = $ilDB->queryF(
$query,array(
'integer'),array(
$row[
'child']));
1392 if ($r2->numRows() == 0)
1394 $this->ilErr->raiseError(get_class($this).
"::checkTree(): No child found for ID ".
1395 $row[
"child"].
"!",$this->ilErr->WARNING);
1397 if ($r2->numRows() > 1)
1399 $this->ilErr->raiseError(get_class($this).
"::checkTree(): More childs found for ID ".
1400 $row[
"child"].
"!",$this->ilErr->WARNING);
1417 $query =
'SELECT MAX(depth) depth FROM '.$this->table_tree;
1421 return $row[
'depth'];
1436 $query =
'SELECT depth FROM '.$this->table_tree.
' '.
1437 'WHERE child = %s '.
1438 'AND '.$this->tree_pk.
' = %s ';
1439 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array($a_node_id,$this->tree_id));
1467 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1468 'WHERE child = '.$ilDB->quote($a_node_id,
'integer');
1492 if (!isset($a_node_id))
1495 $this->ilErr->raiseError(get_class($this).
"::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
1501 $message = sprintf(
'%s::getNodeData(): No valid parameter given! $a_node_id: %s',
1505 $this->log->write($message,$this->log->FATAL);
1506 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
1511 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1513 'WHERE '.$this->table_tree.
'.child = %s '.
1514 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
1515 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
1517 $a_tree_pk === null ? $this->tree_id : $a_tree_pk));
1538 $data[
"desc"] = $a_row[
"description"];
1543 if (is_object($objDefinition))
1545 $translation_type = $objDefinition->getTranslationType(
$data[
"type"]);
1549 if ($translation_type ==
"sys")
1552 if (
$data[
"type"] ==
"rolf" and
$data[
"obj_id"] != ROLE_FOLDER_ID)
1554 $data[
"description"] = $lng->txt(
"obj_".
$data[
"type"].
"_local_desc").$data[
"title"].$data[
"desc"];
1555 $data[
"desc"] = $lng->txt(
"obj_".
$data[
"type"].
"_local_desc").$data[
"title"].$data[
"desc"];
1556 $data[
"title"] = $lng->txt(
"obj_".
$data[
"type"].
"_local");
1560 $data[
"title"] = $lng->txt(
"obj_".
$data[
"type"]);
1561 $data[
"description"] = $lng->txt(
"obj_".
$data[
"type"].
"_desc");
1562 $data[
"desc"] = $lng->txt(
"obj_".
$data[
"type"].
"_desc");
1566 elseif ($translation_type ==
"db")
1571 array_key_exists(
$data[
"obj_id"].
'.'.$lang_code, $this->translation_cache)) {
1573 $key =
$data[
"obj_id"].
'.'.$lang_code;
1574 $data[
"title"] = $this->translation_cache[$key][
'title'];
1575 $data[
"description"] = $this->translation_cache[$key][
'description'];
1576 $data[
"desc"] = $this->translation_cache[$key][
'desc'];
1582 $query =
'SELECT title,description FROM object_translation '.
1583 'WHERE obj_id = %s '.
1584 'AND lang_code = %s '.
1585 'AND NOT lang_default = %s';
1587 $res = $ilDB->queryF(
$query,array(
'integer',
'text',
'integer'),array(
1602 if ($this->
isCacheUsed() && count($this->translation_cache) < 1000)
1604 $key =
$data[
"obj_id"].
'.'.$lang_code;
1605 $this->translation_cache[$key] = array();
1606 $this->translation_cache[$key][
'title'] =
$data[
"title"] ;
1607 $this->translation_cache[$key][
'description'] =
$data[
"description"];
1608 $this->translation_cache[$key][
'desc'] =
$data[
"desc"];
1614 if(
$data[
'type'] ==
'crsr' or
$data[
'type'] ==
'catr')
1616 include_once(
'./Services/ContainerReference/classes/class.ilContainerReference.php');
1630 global $ilObjDataCache;
1632 if ($this->
isCacheUsed() && is_array($a_obj_ids) && is_object($ilObjDataCache))
1634 foreach ($a_obj_ids as $id)
1636 $this->translation_cache[$id.
'.'][
'title'] = $ilObjDataCache->lookupTitle($id);
1637 $this->translation_cache[$id.
'.'][
'description'] = $ilObjDataCache->lookupDescription($id);;
1638 $this->translation_cache[$id.
'.'][
'desc'] =
1639 $this->translation_cache[$id.
'.'][
'description'];
1656 if (!isset($a_node_id))
1659 #$this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING); 1662 if ($this->
isCacheUsed() && isset($this->in_tree_cache[$a_node_id]))
1664 #$GLOBALS['ilLog']->write(__METHOD__.': Using in tree cache '.$a_node_id); 1666 return $this->in_tree_cache[$a_node_id];
1669 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1670 'WHERE '.$this->table_tree.
'.child = %s '.
1671 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s';
1673 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
1677 if (
$res->numRows() > 0)
1681 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = true'); 1682 $this->in_tree_cache[$a_node_id] =
true;
1690 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = false'); 1691 $this->in_tree_cache[$a_node_id] =
false;
1709 if (!isset($a_node_id))
1715 if ($this->table_obj_reference)
1718 $innerjoin =
"JOIN ".$this->table_obj_reference.
" ON v.child=".$this->table_obj_reference.
".".$this->ref_pk.
" ".
1719 "JOIN ".$this->table_obj_data.
" ON ".$this->table_obj_reference.
".".$this->obj_pk.
"=".$this->table_obj_data.
".".$this->obj_pk.
" ";
1724 $innerjoin =
"JOIN ".$this->table_obj_data.
" ON v.child=".$this->table_obj_data.
".".$this->obj_pk.
" ";
1727 $query =
'SELECT * FROM '.$this->table_tree.
' s, '.$this->table_tree.
' v '.
1729 'WHERE s.child = %s '.
1730 'AND s.parent = v.child '.
1731 'AND s.'.$this->tree_pk.
' = %s '.
1732 'AND v.'.$this->tree_pk.
' = %s';
1733 $res = $ilDB->queryF(
$query,array(
'integer',
'integer',
'integer'),array(
1750 return $this->
getRelation($a_startnode_id, $a_querynode_id) == self::RELATION_PARENT;
1768 $message = sprintf(
'%s::addTree(): Operation not allowed on main tree! $a_tree_if: %s $a_node_id: %s',
1772 $this->log->write($message,$this->log->FATAL);
1773 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
1776 if (!isset($a_tree_id))
1778 $this->ilErr->raiseError(get_class($this).
"::addTree(): No tree_id given! ",$this->ilErr->WARNING);
1781 if ($a_node_id <= 0)
1783 $a_node_id = $a_tree_id;
1786 $query =
'INSERT INTO '.$this->table_tree.
' ('.
1787 $this->tree_pk.
', child,parent,lft,rgt,depth) '.
1789 '(%s,%s,%s,%s,%s,%s)';
1790 $res = $ilDB->manipulateF(
$query,array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),array(
1813 if(!isset($a_type) or (!is_string($a_type)))
1819 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1821 'WHERE ' . $this->table_obj_data .
'.type = ' . $this->
ilDB->
quote($a_type,
'text').
1822 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = ' . $this->
ilDB->
quote($this->tree_id,
'integer');
1826 while(
$row = $ilDB->fetchAssoc(
$res))
1857 $query =
'DELETE FROM '.$this->table_tree.
1858 ' WHERE '.$this->tree_pk.
' = %s ';
1859 $ilDB->manipulateF(
$query,array(
'integer'),array($a_tree_id));
1871 return $this->
saveSubTree($a_node_id, $a_set_deleted);
1906 $subnodes = array();
1909 $subnodes[] =
$row[
'child'];
1912 if(!count($subnodes))
1918 $ilDB->unlockTables();
1925 include_once
'./Services/Object/classes/class.ilObject.php';
1934 $ilDB->unlockTables();
1947 return $this->
isSaved($a_node_id);
1960 if ($this->
isCacheUsed() && isset($this->is_saved_cache[$a_node_id]))
1963 return $this->is_saved_cache[$a_node_id];
1966 $query =
'SELECT '.$this->tree_pk.
' FROM '.$this->table_tree.
' '.
1967 'WHERE child = %s ';
1968 $res = $ilDB->queryF(
$query,array(
'integer'),array($a_node_id));
1971 if (
$row[$this->tree_pk] < 0)
1975 $this->is_saved_cache[$a_node_id] =
true;
1983 $this->is_saved_cache[$a_node_id] =
false;
1999 if (!is_array($a_node_ids) || !$this->
isCacheUsed())
2004 $query =
'SELECT '.$this->tree_pk.
', child FROM '.$this->table_tree.
' '.
2005 'WHERE '.$ilDB->in(
"child", $a_node_ids,
false,
"integer");
2008 while (
$row = $ilDB->fetchAssoc(
$res))
2010 if (
$row[$this->tree_pk] < 0)
2014 $this->is_saved_cache[
$row[
"child"]] =
true;
2021 $this->is_saved_cache[
$row[
"child"]] =
false;
2038 if (!isset($a_parent_id))
2040 $this->ilErr->raiseError(get_class($this).
"::getSavedNodeData(): No node_id given!",$this->ilErr->WARNING);
2043 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2045 'WHERE '.$this->table_tree.
'.'.$this->tree_pk.
' < %s '.
2046 'AND '.$this->table_tree.
'.parent = %s';
2047 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2051 while(
$row = $ilDB->fetchAssoc(
$res))
2056 return $saved ? $saved : array();
2069 $query =
'SELECT '.$this->table_obj_data.
'.obj_id FROM '.$this->table_tree.
' '.
2071 'WHERE '.$this->table_tree.
'.'.$this->tree_pk.
' < '.$ilDB->quote(0,
'integer').
' '.
2072 'AND '.$ilDB->in($this->table_obj_data.
'.obj_id', $a_obj_ids,
'',
'integer');
2074 while(
$row = $ilDB->fetchAssoc(
$res))
2076 $saved[] =
$row[
'obj_id'];
2079 return $saved ? $saved : array();
2092 if (!isset($a_node_id))
2094 $this->ilErr->raiseError(get_class($this).
"::getParentId(): No node_id given! ",$this->ilErr->WARNING);
2097 $query =
'SELECT parent FROM '.$this->table_tree.
' '.
2098 'WHERE child = %s '.
2099 'AND '.$this->tree_pk.
' = %s ';
2100 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2105 return $row->parent;
2118 if (!isset($a_node_id))
2120 $this->ilErr->raiseError(get_class($this).
"::getLeftValued(): No node_id given! ",$this->ilErr->WARNING);
2123 $query =
'SELECT lft FROM '.$this->table_tree.
' '.
2124 'WHERE child = %s '.
2125 'AND '.$this->tree_pk.
' = %s ';
2126 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2143 if (!isset($a_node))
2145 $this->ilErr->raiseError(get_class($this).
"::getChildSequenceNumber(): No node_id given! ",$this->ilErr->WARNING);
2150 $query =
'SELECT count(*) cnt FROM '.$this->table_tree.
' '.
2155 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2157 $res = $ilDB->queryF(
$query,array(
'integer',
'text',
'integer',
'integer'),array(
2165 $query =
'SELECT count(*) cnt FROM '.$this->table_tree.
' '.
2169 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2171 $res = $ilDB->queryF(
$query,array(
'integer',
'integer',
'integer'),array(
2191 $query =
'SELECT child FROM '.$this->table_tree.
' '.
2192 'WHERE parent = %s '.
2193 'AND '.$this->tree_pk.
' = %s ';
2194 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2198 $this->root_id =
$row->child;
2213 $this->root_id = $a_root_id;
2233 $this->tree_id = $a_tree_id;
2247 if (!isset($a_node_id))
2249 $this->ilErr->raiseError(get_class($this).
"::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
2253 $query =
'SELECT lft FROM '.$this->table_tree.
' '.
2254 'WHERE '.$this->table_tree.
'.child = %s '.
2255 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2256 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2259 $curr_node = $ilDB->fetchAssoc(
$res);
2263 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2266 'AND '.$this->table_obj_data.
'.type = %s '.
2267 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2270 $res = $ilDB->queryF(
$query,array(
'integer',
'text',
'integer'),array(
2277 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2280 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2283 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2288 if (
$res->numRows() < 1)
2310 if (!isset($a_node_id))
2312 $this->ilErr->raiseError(get_class($this).
"::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
2316 $query =
'SELECT lft FROM '.$this->table_tree.
' '.
2317 'WHERE '.$this->table_tree.
'.child = %s '.
2318 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2319 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2323 $curr_node = $ilDB->fetchAssoc(
$res);
2327 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2330 'AND '.$this->table_obj_data.
'.type = %s '.
2331 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2332 'ORDER BY lft DESC';
2334 $res = $ilDB->queryF(
$query,array(
'integer',
'text',
'integer'),array(
2341 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2344 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2345 'ORDER BY lft DESC';
2347 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2352 if (
$res->numRows() < 1)
2390 2 => array(
'name' => $this->table_obj_reference,
'type' =>
ilDB::LOCK_WRITE),
2392 4 => array(
'name' =>
'object_data',
'type' =>
ilDB::LOCK_WRITE,
'alias' =>
'od'),
2393 5 => array(
'name' =>
'container_reference',
'type' =>
ilDB::LOCK_WRITE,
'alias' =>
'cr')
2399 $ilDB->unlockTables();
2419 $query =
'UPDATE '.$this->table_tree.
' SET lft = %s WHERE child = %s';
2420 $res = $ilDB->manipulateF(
$query,array(
'integer',
'integer'),array(
2428 foreach ($childs as $child)
2435 if (count($childs) > 0)
2437 $i += $this->gap * 2;
2441 $query =
'UPDATE '.$this->table_tree.
' SET rgt = %s WHERE child = %s';
2442 $res = $ilDB->manipulateF(
$query,array(
'integer',
'integer'),array(
2462 $cache_key = $a_ref_id.
'.'.$a_type.
'.'.((int)$a_exclude_source_check);
2466 array_key_exists($cache_key, $this->parent_type_cache))
2468 return $this->parent_type_cache[$cache_key];
2472 $do_cache = ($this->
__isMainTree() && count($this->parent_type_cache) < 1000);
2479 $this->parent_type_cache[$cache_key] =
false;
2487 if($a_exclude_source_check)
2492 foreach(
$path as $node)
2495 if($node[
"type"] == $a_type)
2499 $this->parent_type_cache[$cache_key] = $node[
"child"];
2501 return $node[
"child"];
2507 $this->parent_type_cache[$cache_key] =
false;
2525 if($a_db_table ===
'tree')
2527 if($a_tree == 1 and $a_child == ROOT_FOLDER_ID)
2529 $message = sprintf(
'%s::_removeEntry(): Tried to delete root node! $a_tree: %s $a_child: %s',
2533 $ilLog->write($message,$ilLog->FATAL);
2534 $ilErr->raiseError($message,$ilErr->WARNING);
2538 $query =
'DELETE FROM '.$a_db_table.
' '.
2541 $res = $ilDB->manipulateF(
$query,array(
'integer',
'integer'),array(
2555 return $this->table_tree ===
'tree';
2577 $counter = (int) $lft_childs = array();
2578 while(
$row = $ilDB->fetchObject(
$res))
2580 $lft_childs[
$row->child] =
$row->parent;
2585 if($counter != count($lft_childs))
2587 $message = sprintf(
'%s::__checkTree(): Duplicate entries for "child" in maintree! $a_node_id: %s',
2590 $this->log->write($message,$this->log->FATAL);
2591 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2595 $parent_childs = array();
2615 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2616 'WHERE child = %s '.
2618 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2623 while(
$row = $ilDB->fetchObject(
$res))
2625 $parent_childs[$a_node_id] =
$row->parent;
2631 $message = sprintf(
'%s::__getSubTreeByParentRelation(): Multiple entries in maintree! $a_node_id: %s',
2634 $this->log->write($message,$this->log->FATAL);
2635 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2639 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2640 'WHERE parent = %s ';
2641 $res = $ilDB->queryF(
$query,array(
'integer'),array($a_node_id));
2643 while(
$row = $ilDB->fetchObject(
$res))
2655 ksort($parent_childs);
2657 $GLOBALS[
'ilLog']->write(__METHOD__.
': left childs '. print_r($lft_childs,
true));
2658 $GLOBALS[
'ilLog']->write(__METHOD__.
': parent childs '. print_r($parent_childs,
true));
2660 if(count($lft_childs) != count($parent_childs))
2662 $message = sprintf(
'%s::__validateSubtrees(): (COUNT) Tree is corrupted! Left/Right subtree does not comply .'.
2663 'with parent relation',
2665 $this->log->write($message,$this->log->FATAL);
2666 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2670 foreach($lft_childs as $key => $value)
2672 if($parent_childs[$key] != $value)
2674 $message = sprintf(
'%s::__validateSubtrees(): (COMPARE) Tree is corrupted! Left/Right subtree does not comply '.
2675 'with parent relation',
2677 $this->log->write($message,$this->log->FATAL);
2678 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2680 if($key == ROOT_FOLDER_ID)
2682 $message = sprintf(
'%s::__validateSubtrees(): (ROOT_FOLDER) Tree is corrupted! Tried to delete root folder',
2684 $this->log->write($message,$this->log->FATAL);
2685 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2700 public function moveTree($a_source_id, $a_target_id, $a_location = self::POS_LAST_NODE)
2702 $old_parent_id = $this->
getParentId($a_source_id);
2705 $GLOBALS[
'ilAppEventHandler']->raise(
2709 'tree' => $this->table_tree,
2710 'source_id' => $a_source_id,
2711 'target_id' => $a_target_id,
2712 'old_parent_id' => $old_parent_id
2742 public function getSubTreeQuery($a_node_id,$a_fields = array(), $a_types =
'', $a_force_join_reference =
false)
2747 $a_force_join_reference,
2775 if(count($a_fields))
2777 $fields = implode(
',',$a_fields);
2780 $query =
"SELECT ".$fields.
2781 " FROM ".$this->getTreeTable().
2782 " ".$this->buildJoin().
2783 " WHERE ".$this->getTableReference().
".".$this->ref_pk.
" IN (".
$query.
")".
2784 " AND ".$ilDB->in($this->
getObjectDataTable().
".".$this->obj_pk, $a_obj_ids,
"",
"integer");
2785 $set = $ilDB->query(
$query);
2786 while(
$row = $ilDB->fetchAssoc($set))
2798 $query =
'DELETE FROM tree where '.
2799 'child = '.$ilDB->quote($a_node_id,
'integer').
' '.
2800 'AND tree = '.$ilDB->quote($a_tree_id,
'integer');
2801 $ilDB->manipulate(
$query);
2813 $query =
'SELECT DISTINCT(o.type) type FROM tree t JOIN object_reference r ON child = r.ref_id '.
2814 'JOIN object_data o on r.obj_id = o.obj_id '.
2815 'WHERE tree < '.$ilDB->quote(0,
'integer').
' '.
2816 'AND child = -tree '.
2820 $types_deleted = array();
2823 $types_deleted[] =
$row->type;
2825 return $types_deleted;
removeTree($a_tree_id)
remove an existing tree
Thrown if invalid tree strucutes are found.
static setDeletedDates($a_ref_ids)
Set deleted date type $ilDB.
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
initTreeImplementation()
Init tree implementation.
_resetDeletedDate($a_ref_id)
only called in ilObjectGUI::insertSavedNodes
getChilds($a_node_id, $a_order="", $a_direction="ASC")
get child nodes of given node public
const PEAR_ERROR_CALLBACK
preloadDeleted($a_node_ids)
Preload deleted information.
isGrandChild($a_startnode_id, $a_querynode_id)
checks if a node is in the path of an other node public
isDeleted($a_node_id)
This is a wrapper for isSaved() with a more useful name.
renumber($node_id=1, $i=1)
Wrapper for renumber.
getFilteredChilds($a_filter, $a_node, $a_order="", $a_direction="ASC")
get child nodes of given node (exclude filtered obj_types) public
getSavedNodeObjIds(array $a_obj_ids)
get object id of saved/deleted nodes
fetchNodeData($a_row)
get data of parent node from tree and object_data private
getNodeTreeData($a_node_id)
return all columns of tabel tree
getRelation($a_node_a, $a_node_b)
Get relation of two nodes.
fetchPredecessorNode($a_node_id, $a_type="")
get node data of predecessor node
getTreeId()
get tree id public
getParentCache()
Get parent cache.
buildJoin()
build join depending on table settings private
getChildsByType($a_node_id, $a_type)
get child nodes of given node by object type public
getDepth($a_node_id)
return depth of a node in tree private
deleteTree($a_node)
delete node and the whole subtree under this node public
setObjectTablePK($a_column_name)
set column containing primary key in object table public
static shortenText($a_str, $a_len, $a_dots=false, $a_next_blank=false, $a_keep_extension=false)
shorten a string to given length.
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...
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...
ilTree($a_tree_id, $a_root_id=0)
Constructor public.
static strToLower($a_string)
getTreePk()
Get tree primary key.
__validateSubtrees(&$lft_childs, $parent_childs)
Base class for nested set path based trees.
deleteNode($a_tree_id, $a_node_id)
getSubTreeTypes($a_node, $a_filter=0)
get types of nodes in the subtree under specified node
const DB_FETCHMODE_OBJECT
getChildsByTypeFilter($a_node_id, $a_types, $a_order="", $a_direction="ASC")
get child nodes of given node by object type public
toNFC( $string)
Convert a UTF-8 string to normal form C, canonical composition.
getFilteredSubTree($a_node_id, $a_filter=array())
get filtered subtree
getObjectDataTable()
Get object data table.
validateParentRelations()
Validate parent relations of tree.
__checkDelete($a_node)
Check for deleteTree() compares a subtree of a given node by checking lft, rgt against parent relatio...
quote($a_query, $a_type=null)
Wrapper for quote method.
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...
getLeftValue($a_node_id)
get left value of given node public
static _lookupTitle($a_obj_id)
Overwitten from base class.
getTreeTable()
Get tree table name.
checkTree()
check consistence of tree all left & right values are checked if they are exists only once public ...
getRootId()
get the root id of tree public
setTreeId($a_tree_id)
set tree id public
getNodeData($a_node_id, $a_tree_pk=null)
get all information of a node.
getNodePath($a_endnode_id, $a_startnode_id=0)
Returns the node path for the specified object reference.
lookupTrashedObjectTypes()
Lookup object types in trash type $ilDB.
getParentId($a_node_id)
get parent id of given node public
getTableReference()
Get reference table if available.
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...
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.
preloadDepthParent($a_node_ids)
Preload depth/parent.
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
moveToTrash($a_node_id, $a_set_deleted=false)
Wrapper for saveSubTree.
__renumber($node_id=1, $i=1)
This method is private.
setTreeTablePK($a_column_name)
set column containing primary key in tree table public
setReferenceTablePK($a_column_name)
set column containing primary key in reference table public
__getSubTreeByParentRelation($a_node_id, &$parent_childs)
type $ilDB
getDepthCache()
Get depth cache.
static quoteArray($a_array)
Quotes all members of an array for usage in DB query statement.
initLangCode()
Store user language.
getNodePathForTitlePath($titlePath, $a_startnode_id=null)
Converts a path consisting of object titles into a path consisting of tree nodes. ...
getChildIds($a_node)
Get node child ids type $ilDB.
getMaximumDepth()
Return the current maximum depth in the tree 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 public
getRbacSubtreeInfo($a_endnode_id)
This method is used for change existing objects and returns all necessary information for this action...
getGap()
Get default gap *.
fetchTranslationFromObjectDataCache($a_obj_ids)
Get translation data from object cache (trigger in object cache on preload)
_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.
Base class for materialize path based trees Based on implementation of Werner Randelshofer.
getParentNodeData($a_node_id)
get data of parent node from tree and object_data public
getSubTree($a_node, $a_with_data=true, $a_type="")
get all nodes in the subtree under specified node
getNodeDataByType($a_type)
get nodes by type
static getLogger($a_component_id)
Get component logger.
isCacheUsed()
Check if cache is active.
$GLOBALS['PHPCAS_CLIENT']
This global variable is used by the interface class phpCAS.
getSubTreeIds($a_ref_id)
Get all ids of subnodes.
getChildSequenceNumber($a_node, $type="")
get sequence number of node in sibling sequence public
getRelationOfNodes($a_node_a_arr, $a_node_b_arr)
get relation of two nodes by node data
fetchSuccessorNode($a_node_id, $a_type="")
get node data of successor node
useCache($a_use=true)
Use Cache (usually activated)
__isMainTree()
Check if operations are done on main tree.
getTreeImplementation()
Get tree implementation.
isSaved($a_node_id)
Use method isDeleted check if node is saved.
addTree($a_tree_id, $a_node_id=-1)
create a new tree to do: ???
checkTreeChilds($a_no_zero_child=true)
check, if all childs of tree nodes exist in object table
isInTree($a_node_id)
get all information of a node.
moveTree($a_source_id, $a_target_id, $a_location=self::POS_LAST_NODE)
Move Tree Implementation.
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...
getSavedNodeData($a_parent_id)
get data saved/deleted nodes
readRootId()
read root id from database