4 define(
"IL_LAST_NODE", -2);
5 define(
"IL_FIRST_NODE", -1);
7 include_once
'./Services/Tree/exceptions/class.ilInvalidTreeStructureException.php';
155 $this->lang_code =
"en";
160 if (!isset($a_tree_id) or (func_num_args() == 0)) {
161 $this->log->error(
"No tree_id given!");
166 if (func_num_args() > 2) {
167 $this->log->error(
"Wrong parameter count!");
172 if (empty($a_root_id)) {
173 $a_root_id = ROOT_FOLDER_ID;
176 $this->tree_id = $a_tree_id;
177 $this->root_id = $a_root_id;
178 $this->table_tree =
'tree';
179 $this->table_obj_data =
'object_data';
180 $this->table_obj_reference =
'object_reference';
181 $this->ref_pk =
'ref_id';
182 $this->obj_pk =
'obj_id';
183 $this->tree_pk =
'tree';
185 $this->use_cache =
true;
188 $this->translation_cache =
array();
189 $this->parent_type_cache =
array();
207 if (!is_object(
$GLOBALS[
'ilSetting']) or
$GLOBALS[
'ilSetting']->getModule() !=
'common') {
208 include_once
'./Services/Administration/classes/class.ilSetting.php';
215 if ($setting->get(
'main_tree_impl',
'ns') ==
'ns') {
216 #$GLOBALS['ilLog']->write(__METHOD__.': Using nested set.'); 217 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
220 #$GLOBALS['ilLog']->write(__METHOD__.': Using materialized path.'); 221 include_once
'./Services/Tree/classes/class.ilMaterializedPathTree.php';
225 #$GLOBALS['ilLog']->write(__METHOD__.': Using netsted set for non main tree.'); 226 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
245 $this->use_cache = $a_use;
284 if (!is_object($ilUser)) {
285 $this->lang_code =
"en";
287 $this->lang_code = $ilUser->getCurrentLanguage();
339 $this->in_tree_cache =
array();
359 public function setTableNames($a_table_tree, $a_table_obj_data, $a_table_obj_reference =
"")
361 if (!isset($a_table_tree) or !isset($a_table_obj_data)) {
363 "tree table: " . $a_table_tree .
" object data table: " . $a_table_obj_data;
368 $this->table_tree = $a_table_tree;
369 $this->table_obj_data = $a_table_obj_data;
370 $this->table_obj_reference = $a_table_obj_reference;
386 if (!isset($a_column_name)) {
392 $this->ref_pk = $a_column_name;
405 if (!isset($a_column_name)) {
411 $this->obj_pk = $a_column_name;
424 if (!isset($a_column_name)) {
430 $this->tree_pk = $a_column_name;
441 if ($this->table_obj_reference) {
443 return "JOIN " . $this->table_obj_reference .
" ON " . $this->table_tree .
".child=" . $this->table_obj_reference .
"." . $this->ref_pk .
" " .
444 "JOIN " . $this->table_obj_data .
" ON " . $this->table_obj_reference .
"." . $this->obj_pk .
"=" . $this->table_obj_data .
"." . $this->obj_pk .
" ";
447 return "JOIN " . $this->table_obj_data .
" ON " . $this->table_tree .
".child=" . $this->table_obj_data .
"." . $this->obj_pk .
" ";
485 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
486 'WHERE parent = ' . $ilDB->quote($a_node,
'integer') .
' ' .
487 'AND tree = ' . $ilDB->quote($this->tree_id,
'integer' .
' ' .
493 $childs[] =
$row->child;
507 public function getChilds($a_node_id, $a_order =
"", $a_direction =
"ASC")
511 if (!isset($a_node_id)) {
527 if (!empty($a_order)) {
528 $order_clause =
"ORDER BY " . $a_order .
" " . $a_direction;
530 $order_clause =
"ORDER BY " . $this->table_tree .
".lft";
535 'SELECT * FROM ' . $this->table_tree .
' ' .
537 "WHERE parent = %s " .
538 "AND " . $this->table_tree .
"." . $this->tree_pk .
" = %s " .
540 $ilDB->quote($a_node_id,
'integer'),
541 $ilDB->quote($this->tree_id,
'integer')
546 if (!$count = $res->numRows()) {
552 while (
$r = $ilDB->fetchAssoc($res)) {
554 $obj_ids[] =
$r[
"obj_id"];
559 is_object($ilUser) && $this->lang_code == $ilUser->getLanguage() && !$this->oc_preloaded[$a_node_id]) {
561 $ilObjDataCache->preloadObjectCache($obj_ids, $this->lang_code);
563 $this->oc_preloaded[$a_node_id] =
true;
571 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child'].' = true'); 572 $this->in_tree_cache[$row[
'child']] = $row[
'tree'] == 1;
575 $childs[$count - 1][
"last"] =
true;
590 $childs = $this->
getChilds($a_node, $a_order, $a_direction);
592 foreach ($childs as $child) {
593 if (!in_array($child[
"type"], $a_filter)) {
594 $filtered[] = $child;
597 return $filtered ? $filtered :
array();
613 if (!isset($a_node_id) or !isset(
$a_type)) {
614 $message =
"Missing parameter! node_id:" . $a_node_id .
" type:" .
$a_type;
619 if (
$a_type==
'rolf' && $this->table_obj_reference) {
623 $ilDB->setLimit(1, 0);
625 "SELECT * FROM " . $this->table_tree .
" " .
627 "WHERE parent = %s " .
628 "AND " . $this->table_tree .
"." . $this->tree_pk .
" = %s " .
629 "AND " . $this->table_obj_data .
".type = %s ",
630 $ilDB->quote($a_node_id,
'integer'),
631 $ilDB->quote($this->tree_id,
'integer'),
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 "ORDER BY " . $this->table_tree .
".lft",
642 $ilDB->quote($a_node_id,
'integer'),
643 $ilDB->quote($this->tree_id,
'integer'),
651 while (
$row = $ilDB->fetchAssoc($res)) {
655 return $childs ? $childs :
array();
671 if (!isset($a_node_id) or !$a_types) {
672 $message =
"Missing parameter! node_id:" . $a_node_id .
" type:" . $a_types;
679 $filter =
'AND ' . $this->table_obj_data .
'.type IN(' . implode(
',',
ilUtil::quoteArray($a_types)) .
') ';
683 if (!empty($a_order)) {
684 $order_clause =
"ORDER BY " . $a_order .
" " . $a_direction;
686 $order_clause =
"ORDER BY " . $this->table_tree .
".lft";
689 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
691 'WHERE parent = ' . $ilDB->quote($a_node_id,
'integer') .
' ' .
692 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = ' . $ilDB->quote($this->tree_id,
'integer') .
' ' .
697 while (
$row = $ilDB->fetchAssoc(
$res)) {
701 return $childs ? $childs :
array();
720 if ($a_source_id <= 1 or $a_target_id <= 0) {
725 if (!isset($a_source_id) or !isset($a_target_id)) {
729 if ($this->
isInTree($a_source_id)) {
735 $query =
'DELETE from tree ' .
736 'WHERE tree = ' . $ilDB->quote($a_tree_id,
'integer') .
' ' .
737 'AND child = ' . $ilDB->quote($a_source_id,
'integer');
738 $ilDB->manipulate(
$query);
759 if ($a_node_id <= 1 or $a_parent_id <= 0) {
761 'Invalid parameters! $a_node_id: %s $a_parent_id: %s',
771 if (!isset($a_node_id) or !isset($a_parent_id)) {
774 "node_id: " . $a_node_id .
" parent_id: " . $a_parent_id);
778 $this->table_tree .
"!");
783 $this->in_tree_cache[$a_node_id] =
true;
786 if ($a_reset_deletion_date) {
791 $GLOBALS[
'ilAppEventHandler']->raise(
795 'tree' => $this->table_tree,
796 'node_id' => $a_node_id,
797 'parent_id' => $a_parent_id)
820 foreach ($this->
getSubTree($node) as $subnode) {
821 if ($depth and $subnode[
'depth'] > $depth) {
824 if (!$first and in_array($subnode[
'type'], $a_filter)) {
825 $depth = $subnode[
'depth'];
831 $filtered[] = $subnode;
833 return $filtered ? $filtered :
array();
860 if (!is_array($a_node)) {
880 while (
$row = $ilDB->fetchAssoc(
$res)) {
884 $subtree[] =
$row[
'child'];
887 if ($this->
__isMainTree() || $this->table_tree ==
"lm_tree") {
888 $this->in_tree_cache[
$row[
'child']] =
true;
891 return $subtree ? $subtree :
array();
904 $a_filter = $a_filter ? $a_filter :
array();
906 foreach ($this->getSubtree($this->
getNodeData($a_node)) as $node) {
907 if (in_array($node[
"type"], $a_filter)) {
910 $types[
"$node[type]"] = $node[
"type"];
912 return $types ? $types :
array();
926 $this->log->debug(
'Delete tree with node ' . $a_node);
928 if (!is_array($a_node)) {
933 $this->log->debug($this->tree_pk);
970 $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
976 if (count($pathIds) == 0) {
980 $inClause =
'child IN (';
981 for (
$i=0;
$i < count($pathIds);
$i++) {
985 $inClause .= $ilDB->quote($pathIds[
$i],
'integer');
990 'FROM ' . $this->table_tree .
' ' .
992 'WHERE ' . $inClause .
' ' .
993 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = ' . $this->
ilDB->
quote($this->tree_id,
'integer') .
' ' .
995 $r = $ilDB->query($q);
1003 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child']); 1004 $this->in_tree_cache[
$row[
'child']] = $row[
'tree'] == 1;
1025 $res = $ilDB->query(
'SELECT t.depth, t.parent, t.child ' .
1026 'FROM ' . $this->table_tree .
' t ' .
1027 'WHERE ' . $ilDB->in(
"child", $a_node_ids,
false,
"integer") .
1028 'AND ' . $this->tree_pk .
' = ' . $ilDB->quote($this->tree_id,
"integer"));
1029 while (
$row = $ilDB->fetchAssoc(
$res)) {
1030 $this->depth_cache[
$row[
"child"]] = $row[
"depth"];
1031 $this->parent_cache[$row[
"child"]] = $row[
"parent"];
1044 public function getPathId($a_endnode_id, $a_startnode_id = 0)
1046 if (!$a_endnode_id) {
1052 if ($this->
isCacheUsed() && isset($this->path_id_cache[$a_endnode_id][$a_startnode_id])) {
1054 return $this->path_id_cache[$a_endnode_id][$a_startnode_id];
1061 $this->path_id_cache[$a_endnode_id][$a_startnode_id] = $pathIds;
1090 if ($titlePath == null || count($titlePath) == 0) {
1091 if ($a_startnode_id == 0) {
1099 if ($a_startnode_id != null && $a_startnode_id != 0) {
1102 $parent = $a_startnode_id;
1105 $nodePath =
array();
1113 require_once(
'include/Unicode/UtfNormal.php');
1114 include_once
'./Services/Utilities/classes/class.ilStr.php';
1115 $inClause =
'd.title IN (';
1116 for (
$i=0;
$i < count($titlePath);
$i++) {
1121 $inClause .= $ilDB->quote($titlePath[$i],
'text');
1126 if ($this->table_obj_reference) {
1127 $joinClause =
'JOIN ' . $this->table_obj_reference .
' r ON t.child = r.' . $this->ref_pk .
' ' .
1128 'JOIN ' . $this->table_obj_data .
' d ON r.' . $this->obj_pk .
' = d.' .
$this->obj_pk;
1130 $joinClause =
'JOIN ' . $this->table_obj_data .
' d ON t.child = d.' .
$this->obj_pk;
1137 $q =
'SELECT t.depth, t.parent, t.child, d.' . $this->obj_pk .
' obj_id, d.type, d.title ' .
1138 'FROM ' . $this->table_tree .
' t ' .
1140 'WHERE ' . $inClause .
' ' .
1141 'AND t.depth <= ' . (count($titlePath)+count($nodePath)) .
' ' .
1143 'ORDER BY t.depth, t.child ASC';
1144 $r = $ilDB->query($q);
1154 for (
$i = 0;
$i < count($titlePath);
$i++) {
1155 $pathElementFound =
false;
1157 if ($row[
'parent'] == $parent &&
1162 $parent = $row[
'child'];
1163 $pathElementFound =
true;
1168 if (!$pathElementFound) {
1199 $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
1202 if (count($pathIds) == 0) {
1209 for (
$i = 0;
$i < count($pathIds);
$i++) {
1210 $types[] =
'integer';
1214 $query =
'SELECT t.depth,t.parent,t.child,d.obj_id,d.type,d.title ' .
1215 'FROM ' . $this->table_tree .
' t ' .
1216 'JOIN ' . $this->table_obj_reference .
' r ON r.ref_id = t.child ' .
1217 'JOIN ' . $this->table_obj_data .
' d ON d.obj_id = r.obj_id ' .
1218 'WHERE ' . $ilDB->in(
't.child',
$data,
false,
'integer') .
' ' .
1219 'ORDER BY t.depth ';
1223 $titlePath =
array();
1224 while (
$row = $ilDB->fetchAssoc(
$res)) {
1225 $titlePath[] =
$row;
1242 $types =
array(
'integer');
1243 $query =
'SELECT lft,rgt FROM ' . $this->table_tree .
' ' .
1244 'WHERE ' . $this->tree_pk .
' = %s ';
1247 while (
$row = $ilDB->fetchObject(
$res)) {
1252 $all = array_merge($lft, $rgt);
1253 $uni = array_unique($all);
1255 if (count($all) != count($uni)) {
1276 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1277 'WHERE ' . $this->tree_pk .
' = %s ' .
1281 while (
$row = $ilDB->fetchAssoc($r1)) {
1283 if ((
$row[
"child"] == 0) && $a_no_zero_child) {
1284 $message =
"Tree contains child with ID 0!";
1289 if ($this->table_obj_reference) {
1291 $query =
'SELECT * FROM ' . $this->table_obj_reference .
' WHERE ' . $this->ref_pk .
' = %s ';
1295 if ($r2->numRows() == 0) {
1296 $message =
"No Object-to-Reference entry found for ID " .
$row[
"child"] .
"!";
1300 if ($r2->numRows() > 1) {
1301 $message =
"More Object-to-Reference entries found for ID " .
$row[
"child"] .
"!";
1307 $obj_ref = $ilDB->fetchAssoc($r2);
1309 $query =
'SELECT * FROM ' . $this->table_obj_data .
' WHERE ' . $this->obj_pk .
' = %s';
1310 $r3 = $ilDB->queryF(
$query,
array(
'integer'),
array($obj_ref[$this->obj_pk]));
1311 if ($r3->numRows() == 0) {
1316 if ($r3->numRows() > 1) {
1323 $query =
'SELECT * FROM ' . $this->table_obj_data .
' WHERE ' . $this->obj_pk .
' = %s';
1326 if ($r2->numRows() == 0) {
1327 $message =
"No child found for ID " .
$row[
"child"] .
"!";
1331 if ($r2->numRows() > 1) {
1332 $message =
"More childs found for ID " .
$row[
"child"] .
"!";
1355 return $row[
'depth'];
1369 $query =
'SELECT depth FROM ' . $this->table_tree .
' ' .
1370 'WHERE child = %s ' .
1371 'AND ' . $this->tree_pk .
' = %s ';
1397 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1398 'WHERE child = ' . $ilDB->quote($a_node_id,
'integer');
1422 if (!isset($a_node_id)) {
1427 if ($a_node_id < 1) {
1428 $message =
'No valid parameter given! $a_node_id: %s' . $a_node_id;
1436 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1438 'WHERE ' . $this->table_tree .
'.child = %s ' .
1439 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
1442 $a_tree_pk === null ? $this->tree_id : $a_tree_pk));
1463 $data[
"desc"] = $a_row[
"description"];
1468 if (is_object($objDefinition)) {
1469 $translation_type = $objDefinition->getTranslationType(
$data[
"type"]);
1473 if ($translation_type ==
"sys") {
1475 if (
$data[
"type"] ==
"rolf" and
$data[
"obj_id"] != ROLE_FOLDER_ID) {
1476 $data[
"description"] = $lng->txt(
"obj_" .
$data[
"type"] .
"_local_desc") .
$data[
"title"] .
$data[
"desc"];
1477 $data[
"desc"] = $lng->txt(
"obj_" .
$data[
"type"] .
"_local_desc") .
$data[
"title"] .
$data[
"desc"];
1478 $data[
"title"] = $lng->txt(
"obj_" .
$data[
"type"] .
"_local");
1480 $data[
"title"] = $lng->txt(
"obj_" .
$data[
"type"]);
1481 $data[
"description"] = $lng->txt(
"obj_" .
$data[
"type"] .
"_desc");
1482 $data[
"desc"] = $lng->txt(
"obj_" .
$data[
"type"] .
"_desc");
1485 } elseif ($translation_type ==
"db") {
1489 array_key_exists(
$data[
"obj_id"] .
'.' . $lang_code, $this->translation_cache)) {
1490 $key =
$data[
"obj_id"] .
'.' . $lang_code;
1491 $data[
"title"] = $this->translation_cache[
$key][
'title'];
1492 $data[
"description"] = $this->translation_cache[
$key][
'description'];
1493 $data[
"desc"] = $this->translation_cache[
$key][
'desc'];
1497 $query =
'SELECT title,description FROM object_translation ' .
1498 'WHERE obj_id = %s ' .
1499 'AND lang_code = %s ' .
1500 'AND NOT lang_default = %s';
1516 if ($this->
isCacheUsed() && count($this->translation_cache) < 1000) {
1517 $key =
$data[
"obj_id"] .
'.' . $lang_code;
1518 $this->translation_cache[
$key] =
array();
1519 $this->translation_cache[
$key][
'title'] =
$data[
"title"] ;
1520 $this->translation_cache[
$key][
'description'] =
$data[
"description"];
1521 $this->translation_cache[
$key][
'desc'] =
$data[
"desc"];
1527 if (
$data[
'type'] ==
'crsr' or
$data[
'type'] ==
'catr' or
$data[
'type'] ==
'grpr') {
1528 include_once(
'./Services/ContainerReference/classes/class.ilContainerReference.php');
1542 global $ilObjDataCache;
1544 if ($this->
isCacheUsed() && is_array($a_obj_ids) && is_object($ilObjDataCache)) {
1545 foreach ($a_obj_ids as
$id) {
1546 $this->translation_cache[$id .
'.'][
'title'] = $ilObjDataCache->lookupTitle($id);
1547 $this->translation_cache[$id .
'.'][
'description'] = $ilObjDataCache->lookupDescription($id);
1549 $this->translation_cache[$id .
'.'][
'desc'] =
1550 $this->translation_cache[$id .
'.'][
'description'];
1567 if (!isset($a_node_id)) {
1569 #$this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING); 1572 if ($this->
isCacheUsed() && isset($this->in_tree_cache[$a_node_id])) {
1573 #$GLOBALS['ilLog']->write(__METHOD__.': Using in tree cache '.$a_node_id); 1575 return $this->in_tree_cache[$a_node_id];
1578 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1579 'WHERE ' . $this->table_tree .
'.child = %s ' .
1580 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s';
1586 if (
$res->numRows() > 0) {
1588 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = true'); 1589 $this->in_tree_cache[$a_node_id] =
true;
1594 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = false'); 1595 $this->in_tree_cache[$a_node_id] =
false;
1613 if (!isset($a_node_id)) {
1618 if ($this->table_obj_reference) {
1620 $innerjoin =
"JOIN " . $this->table_obj_reference .
" ON v.child=" . $this->table_obj_reference .
"." . $this->ref_pk .
" " .
1621 "JOIN " . $this->table_obj_data .
" ON " . $this->table_obj_reference .
"." . $this->obj_pk .
"=" . $this->table_obj_data .
"." . $this->obj_pk .
" ";
1624 $innerjoin =
"JOIN " . $this->table_obj_data .
" ON v.child=" . $this->table_obj_data .
"." . $this->obj_pk .
" ";
1627 $query =
'SELECT * FROM ' . $this->table_tree .
' s, ' . $this->table_tree .
' v ' .
1629 'WHERE s.child = %s ' .
1630 'AND s.parent = v.child ' .
1631 'AND s.' . $this->tree_pk .
' = %s ' .
1632 'AND v.' . $this->tree_pk .
' = %s';
1650 return $this->
getRelation($a_startnode_id, $a_querynode_id) == self::RELATION_PARENT;
1662 public function addTree($a_tree_id, $a_node_id = -1)
1669 'Operation not allowed on main tree! $a_tree_if: %s $a_node_id: %s',
1677 if (!isset($a_tree_id)) {
1683 if ($a_node_id <= 0) {
1684 $a_node_id = $a_tree_id;
1687 $query =
'INSERT INTO ' . $this->table_tree .
' (' .
1688 $this->tree_pk .
', child,parent,lft,rgt,depth) ' .
1690 '(%s,%s,%s,%s,%s,%s)';
1691 $res = $ilDB->manipulateF(
$query,
array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
array(
1720 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1722 'WHERE ' . $this->table_obj_data .
'.type = ' . $this->
ilDB->
quote(
$a_type,
'text') .
1723 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = ' . $this->
ilDB->
quote($this->tree_id,
'integer');
1727 while (
$row = $ilDB->fetchAssoc(
$res)) {
1756 $query =
'DELETE FROM ' . $this->table_tree .
1757 ' WHERE ' . $this->tree_pk .
' = %s ';
1782 $subnodes =
array();
1784 $subnodes[] =
$row[
'child'];
1787 if (!count($subnodes)) {
1792 if ($a_set_deleted) {
1793 include_once
'./Services/Object/classes/class.ilObject.php';
1815 return $this->
moveToTrash($a_node_id, $a_set_deleted);
1824 return $this->
isSaved($a_node_id);
1837 if ($this->
isCacheUsed() && isset($this->is_saved_cache[$a_node_id])) {
1839 return $this->is_saved_cache[$a_node_id];
1842 $query =
'SELECT ' . $this->tree_pk .
' FROM ' . $this->table_tree .
' ' .
1843 'WHERE child = %s ';
1847 if (
$row[$this->tree_pk] < 0) {
1849 $this->is_saved_cache[$a_node_id] =
true;
1854 $this->is_saved_cache[$a_node_id] =
false;
1870 if (!is_array($a_node_ids) || !$this->
isCacheUsed()) {
1874 $query =
'SELECT ' . $this->tree_pk .
', child FROM ' . $this->table_tree .
' ' .
1875 'WHERE ' . $ilDB->in(
"child", $a_node_ids,
false,
"integer");
1878 while (
$row = $ilDB->fetchAssoc(
$res)) {
1879 if (
$row[$this->tree_pk] < 0) {
1881 $this->is_saved_cache[
$row[
"child"]] =
true;
1885 $this->is_saved_cache[
$row[
"child"]] =
false;
1903 if (!isset($a_parent_id)) {
1909 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1911 'WHERE ' . $this->table_tree .
'.' . $this->tree_pk .
' < %s ' .
1912 'AND ' . $this->table_tree .
'.parent = %s';
1917 while (
$row = $ilDB->fetchAssoc(
$res)) {
1921 return $saved ? $saved :
array();
1934 $query =
'SELECT ' . $this->table_obj_data .
'.obj_id FROM ' . $this->table_tree .
' ' .
1936 'WHERE ' . $this->table_tree .
'.' . $this->tree_pk .
' < ' . $ilDB->quote(0,
'integer') .
' ' .
1937 'AND ' . $ilDB->in($this->table_obj_data .
'.obj_id', $a_obj_ids,
'',
'integer');
1939 while (
$row = $ilDB->fetchAssoc(
$res)) {
1940 $saved[] =
$row[
'obj_id'];
1943 return $saved ? $saved :
array();
1957 if (!isset($a_node_id)) {
1963 $query =
'SELECT parent FROM ' . $this->table_tree .
' ' .
1964 'WHERE child = %s ' .
1965 'AND ' . $this->tree_pk .
' = %s ';
1971 return $row->parent;
1985 if (!isset($a_node_id)) {
1991 $query =
'SELECT lft FROM ' . $this->table_tree .
' ' .
1992 'WHERE child = %s ' .
1993 'AND ' . $this->tree_pk .
' = %s ';
2012 if (!isset($a_node)) {
2019 $query =
'SELECT count(*) cnt FROM ' . $this->table_tree .
' ' .
2021 'WHERE lft <= %s ' .
2023 'AND parent = %s ' .
2024 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
2032 $query =
'SELECT count(*) cnt FROM ' . $this->table_tree .
' ' .
2034 'WHERE lft <= %s ' .
2035 'AND parent = %s ' .
2036 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
2057 $query =
'SELECT child FROM ' . $this->table_tree .
' ' .
2058 'WHERE parent = %s ' .
2059 'AND ' . $this->tree_pk .
' = %s ';
2064 $this->root_id =
$row->child;
2079 $this->root_id = $a_root_id;
2099 $this->tree_id = $a_tree_id;
2114 if (!isset($a_node_id)) {
2121 $query =
'SELECT lft FROM ' . $this->table_tree .
' ' .
2122 'WHERE ' . $this->table_tree .
'.child = %s ' .
2123 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
2127 $curr_node = $ilDB->fetchAssoc(
$res);
2130 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2133 'AND ' . $this->table_obj_data .
'.type = %s ' .
2134 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ' .
2142 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2145 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ' .
2153 if (
$res->numRows() < 1) {
2173 if (!isset($a_node_id)) {
2180 $query =
'SELECT lft FROM ' . $this->table_tree .
' ' .
2181 'WHERE ' . $this->table_tree .
'.child = %s ' .
2182 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
2187 $curr_node = $ilDB->fetchAssoc(
$res);
2190 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2193 'AND ' . $this->table_obj_data .
'.type = %s ' .
2194 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ' .
2195 'ORDER BY lft DESC';
2202 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2205 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ' .
2206 'ORDER BY lft DESC';
2213 if (
$res->numRows() < 1) {
2239 $ilAtomQuery = $ilDB->buildAtomQuery();
2240 $ilAtomQuery->addTableLock($this->table_tree);
2242 $ilAtomQuery->addQueryCallable($renumber_callable);
2243 $ilAtomQuery->run();
2245 $renumber_callable($ilDB);
2264 $query =
'UPDATE ' . $this->table_tree .
' SET lft = %s WHERE child = %s AND tree = %s';
2274 foreach ($childs as $child) {
2280 if (count($childs) > 0) {
2281 $i += $this->gap * 2;
2285 $query =
'UPDATE ' . $this->table_tree .
' SET rgt = %s WHERE child = %s AND tree = %s';
2307 $cache_key = $a_ref_id .
'.' .
$a_type .
'.' . ((int) $a_exclude_source_check);
2311 array_key_exists($cache_key, $this->parent_type_cache)) {
2312 return $this->parent_type_cache[$cache_key];
2316 $do_cache = ($this->
__isMainTree() && count($this->parent_type_cache) < 1000);
2321 $this->parent_type_cache[$cache_key] =
false;
2329 if ($a_exclude_source_check) {
2333 foreach (
$path as $node) {
2335 if ($node[
"type"] ==
$a_type) {
2337 $this->parent_type_cache[$cache_key] = $node[
"child"];
2339 return $node[
"child"];
2344 $this->parent_type_cache[$cache_key] =
false;
2359 public static function _removeEntry($a_tree, $a_child, $a_db_table =
"tree")
2363 if ($a_db_table ===
'tree') {
2364 if ($a_tree == 1 and $a_child == ROOT_FOLDER_ID) {
2366 'Tried to delete root node! $a_tree: %s $a_child: %s',
2375 $query =
'DELETE FROM ' . $a_db_table .
' ' .
2376 'WHERE tree = %s ' .
2391 return $this->table_tree ===
'tree';
2411 $this->log->debug(
$query);
2415 while (
$row = $ilDB->fetchObject(
$res)) {
2416 $lft_childs[
$row->child] =
$row->parent;
2421 if (
$counter != count($lft_childs)) {
2422 $message =
'Duplicate entries for "child" in maintree! $a_node_id: ' . $a_node[
'child'];
2429 $parent_childs =
array();
2450 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2451 'WHERE child = %s ' .
2458 while (
$row = $ilDB->fetchObject(
$res)) {
2459 $parent_childs[$a_node_id] =
$row->parent;
2464 $message =
'Multiple entries in maintree! $a_node_id: ' . $a_node_id;
2471 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2472 'WHERE parent = %s ';
2475 while (
$row = $ilDB->fetchObject(
$res)) {
2493 ksort($parent_childs);
2495 $this->log->debug(
'left childs ' . print_r($lft_childs,
true));
2496 $this->log->debug(
'parent childs ' . print_r($parent_childs,
true));
2498 if (count($lft_childs) != count($parent_childs)) {
2499 $message =
'(COUNT) Tree is corrupted! Left/Right subtree does not comply with parent relation';
2505 foreach ($lft_childs as
$key => $value) {
2506 if ($parent_childs[
$key] != $value) {
2507 $message =
'(COMPARE) Tree is corrupted! Left/Right subtree does not comply with parent relation';
2511 if (
$key == ROOT_FOLDER_ID) {
2512 $message =
'(ROOT_FOLDER) Tree is corrupted! Tried to delete root folder';
2529 public function moveTree($a_source_id, $a_target_id, $a_location = self::POS_LAST_NODE)
2531 $old_parent_id = $this->
getParentId($a_source_id);
2534 $GLOBALS[
'ilAppEventHandler']->raise(
2538 'tree' => $this->table_tree,
2539 'source_id' => $a_source_id,
2540 'target_id' => $a_target_id,
2541 'old_parent_id' => $old_parent_id
2576 $a_force_join_reference,
2595 if (!
sizeof($node)) {
2604 if (count($a_fields)) {
2605 $fields = implode(
',', $a_fields);
2608 $query =
"SELECT " . $fields .
2612 " AND " . $ilDB->in($this->
getObjectDataTable() .
"." . $this->obj_pk, $a_obj_ids,
"",
"integer");
2613 $set = $ilDB->query(
$query);
2614 while (
$row = $ilDB->fetchAssoc($set)) {
2623 global
$ilDB, $ilAppEventHandler;
2625 $query =
'DELETE FROM tree where ' .
2626 'child = ' . $ilDB->quote($a_node_id,
'integer') .
' ' .
2627 'AND tree = ' . $ilDB->quote($a_tree_id,
'integer');
2628 $ilDB->manipulate(
$query);
2630 $ilAppEventHandler->raise(
2633 array(
'tree' => $this->table_tree,
2634 'node_id' => $a_node_id,
2635 'tree_id' => $a_tree_id
2649 $query =
'SELECT DISTINCT(o.type) ' . $ilDB->quoteIdentifier(
'type') .
' FROM tree t JOIN object_reference r ON child = r.ref_id ' .
2650 'JOIN object_data o on r.obj_id = o.obj_id ' .
2651 'WHERE tree < ' . $ilDB->quote(0,
'integer') .
' ' .
2652 'AND child = -tree ' .
2656 $types_deleted =
array();
2658 $types_deleted[] =
$row->type;
2660 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.
static _resetDeletedDate($a_ref_id)
only called in ilObjectGUI::insertSavedNodes
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.
getChilds($a_node_id, $a_order="", $a_direction="ASC")
get child nodes of given node public
static shortenText( $a_str, $a_len, $a_dots=false, $a_next_blank=false, $a_keep_extension=false)
shorten a string to given length.
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
static _removeEntry($a_tree, $a_child, $a_db_table="tree")
STATIC METHOD Removes a single entry from a tree.
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
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
getTreeId()
get tree id public
getParentCache()
Get parent cache.
if(!array_key_exists('StateId', $_REQUEST)) $id
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
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...
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
__construct($a_tree_id, $a_root_id=0)
Constructor public.
getChildsByTypeFilter($a_node_id, $a_types, $a_order="", $a_direction="ASC")
get child nodes of given node by object type public
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...
static toNFC($string)
Convert a UTF-8 string to normal form C, canonical composition.
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...
catch(Exception $e) $message
foreach($_POST as $key=> $value) $res
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.
Create styles array
The data for the language used.
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)
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.
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