4 define(
"IL_LAST_NODE", -2);
5 define(
"IL_FIRST_NODE", -1);
7 include_once
'./Services/Tree/exceptions/class.ilInvalidTreeStructureException.php';
155 $ilDB = $DIC[
'ilDB'];
160 $this->lang_code =
"en";
165 if (!isset($a_tree_id) or (func_num_args() == 0)) {
166 $this->log->error(
"No tree_id given!");
171 if (func_num_args() > 2) {
172 $this->log->error(
"Wrong parameter count!");
177 if (empty($a_root_id)) {
181 $this->tree_id = $a_tree_id;
182 $this->root_id = $a_root_id;
183 $this->table_tree =
'tree';
184 $this->table_obj_data =
'object_data';
185 $this->table_obj_reference =
'object_reference';
186 $this->ref_pk =
'ref_id';
187 $this->obj_pk =
'obj_id';
188 $this->tree_pk =
'tree';
190 $this->use_cache =
true;
193 $this->translation_cache = array();
194 $this->parent_type_cache = array();
212 $db = $DIC->database();
214 $query =
'select tree from tree ' .
220 $trees[] = $row->tree;
232 if (!$DIC->isDependencyAvailable(
'settings') || $DIC->settings()->getModule() !=
'common') {
233 include_once
'./Services/Administration/classes/class.ilSetting.php';
236 $setting = $DIC->settings();
240 if ($setting->get(
'main_tree_impl',
'ns') ==
'ns') {
241 #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Using nested set.'); 242 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
245 #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Using materialized path.'); 246 include_once
'./Services/Tree/classes/class.ilMaterializedPathTree.php';
250 #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Using netsted set for non main tree.'); 251 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
270 $this->use_cache = $a_use;
311 $this->lang_code =
$ilUser->getCurrentLanguage();
313 $this->lang_code =
"en";
365 $this->in_tree_cache = array();
385 public function setTableNames($a_table_tree, $a_table_obj_data, $a_table_obj_reference =
"")
387 if (!isset($a_table_tree) or !isset($a_table_obj_data)) {
389 "tree table: " . $a_table_tree .
" object data table: " . $a_table_obj_data;
394 $this->table_tree = $a_table_tree;
395 $this->table_obj_data = $a_table_obj_data;
396 $this->table_obj_reference = $a_table_obj_reference;
412 if (!isset($a_column_name)) {
418 $this->ref_pk = $a_column_name;
431 if (!isset($a_column_name)) {
437 $this->obj_pk = $a_column_name;
450 if (!isset($a_column_name)) {
456 $this->tree_pk = $a_column_name;
467 if ($this->table_obj_reference) {
469 return "JOIN " . $this->table_obj_reference .
" ON " . $this->table_tree .
".child=" . $this->table_obj_reference .
"." . $this->ref_pk .
" " .
470 "JOIN " . $this->table_obj_data .
" ON " . $this->table_obj_reference .
"." . $this->obj_pk .
"=" . $this->table_obj_data .
"." . $this->obj_pk .
" ";
473 return "JOIN " . $this->table_obj_data .
" ON " . $this->table_tree .
".child=" . $this->table_obj_data .
"." . $this->obj_pk .
" ";
511 $ilDB = $DIC[
'ilDB'];
513 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
514 'WHERE parent = ' .
$ilDB->quote($a_node,
'integer') .
' ' .
515 'AND tree = ' .
$ilDB->quote($this->tree_id,
'integer' .
' ' .
521 $childs[] = $row->child;
535 public function getChilds($a_node_id, $a_order =
"", $a_direction =
"ASC")
540 $ilDB = $DIC[
'ilDB'];
541 $ilObjDataCache = $DIC[
'ilObjDataCache'];
544 if (!isset($a_node_id)) {
560 if (!empty($a_order)) {
561 $order_clause =
"ORDER BY " . $a_order .
" " . $a_direction;
563 $order_clause =
"ORDER BY " . $this->table_tree .
".lft";
568 'SELECT * FROM ' . $this->table_tree .
' ' .
570 "WHERE parent = %s " .
571 "AND " . $this->table_tree .
"." . $this->tree_pk .
" = %s " .
573 $ilDB->quote($a_node_id,
'integer'),
574 $ilDB->quote($this->tree_id,
'integer')
579 if (!$count = $res->numRows()) {
585 while ($r =
$ilDB->fetchAssoc($res)) {
587 $obj_ids[] = $r[
"obj_id"];
592 is_object(
$ilUser) && $this->lang_code ==
$ilUser->getLanguage() && !$this->oc_preloaded[$a_node_id]) {
594 $ilObjDataCache->preloadObjectCache($obj_ids, $this->lang_code);
596 $this->oc_preloaded[$a_node_id] =
true;
599 foreach (
$rows as $row) {
604 #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child'].' = true'); 605 $this->in_tree_cache[$row[
'child']] = $row[
'tree'] == 1;
608 $childs[$count - 1][
"last"] =
true;
623 $childs = $this->
getChilds($a_node, $a_order, $a_direction);
625 foreach ($childs as $child) {
626 if (!in_array($child[
"type"], $a_filter)) {
627 $filtered[] = $child;
630 return $filtered ? $filtered : array();
646 $ilDB = $DIC[
'ilDB'];
648 if (!isset($a_node_id) or !isset($a_type)) {
649 $message =
"Missing parameter! node_id:" . $a_node_id .
" type:" . $a_type;
654 if ($a_type ==
'rolf' && $this->table_obj_reference) {
658 $ilDB->setLimit(1, 0);
660 "SELECT * FROM " . $this->table_tree .
" " .
662 "WHERE parent = %s " .
663 "AND " . $this->table_tree .
"." . $this->tree_pk .
" = %s " .
664 "AND " . $this->table_obj_data .
".type = %s ",
665 $ilDB->quote($a_node_id,
'integer'),
666 $ilDB->quote($this->tree_id,
'integer'),
667 $ilDB->quote($a_type,
'text')
671 "SELECT * FROM " . $this->table_tree .
" " .
673 "WHERE parent = %s " .
674 "AND " . $this->table_tree .
"." . $this->tree_pk .
" = %s " .
675 "AND " . $this->table_obj_data .
".type = %s " .
676 "ORDER BY " . $this->table_tree .
".lft",
677 $ilDB->quote($a_node_id,
'integer'),
678 $ilDB->quote($this->tree_id,
'integer'),
679 $ilDB->quote($a_type,
'text')
686 while ($row =
$ilDB->fetchAssoc($res)) {
690 return $childs ? $childs : array();
706 $ilDB = $DIC[
'ilDB'];
708 if (!isset($a_node_id) or !$a_types) {
709 $message =
"Missing parameter! node_id:" . $a_node_id .
" type:" . $a_types;
716 $filter =
'AND ' . $this->table_obj_data .
'.type IN(' . implode(
',',
ilUtil::quoteArray($a_types)) .
') ';
720 if (!empty($a_order)) {
721 $order_clause =
"ORDER BY " . $a_order .
" " . $a_direction;
723 $order_clause =
"ORDER BY " . $this->table_tree .
".lft";
726 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
728 'WHERE parent = ' .
$ilDB->quote($a_node_id,
'integer') .
' ' .
729 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = ' .
$ilDB->quote($this->tree_id,
'integer') .
' ' .
738 return $childs ? $childs : array();
756 $ilDB = $DIC[
'ilDB'];
759 if ($a_source_id <= 1 or $a_target_id <= 0) {
764 if (!isset($a_source_id) or !isset($a_target_id)) {
768 if ($this->
isInTree($a_source_id)) {
774 $query =
'DELETE from tree ' .
775 'WHERE tree = ' .
$ilDB->quote($a_tree_id,
'integer') .
' ' .
776 'AND child = ' .
$ilDB->quote($a_source_id,
'integer');
795 $ilDB = $DIC[
'ilDB'];
800 if ($a_node_id <= 1 or $a_parent_id <= 0) {
802 'Invalid parameters! $a_node_id: %s $a_parent_id: %s',
812 if (!isset($a_node_id) or !isset($a_parent_id)) {
815 "node_id: " . $a_node_id .
" parent_id: " . $a_parent_id);
819 $this->table_tree .
"!");
824 $this->in_tree_cache[$a_node_id] =
true;
827 if ($a_reset_deletion_date) {
832 $GLOBALS[
'DIC'][
'ilAppEventHandler']->raise(
836 'tree' => $this->table_tree,
837 'node_id' => $a_node_id,
838 'parent_id' => $a_parent_id)
861 foreach ($this->
getSubTree($node) as $subnode) {
862 if ($depth and $subnode[
'depth'] > $depth) {
865 if (!$first and in_array($subnode[
'type'], $a_filter)) {
866 $depth = $subnode[
'depth'];
872 $filtered[] = $subnode;
874 return $filtered ? $filtered : array();
897 public function getSubTree($a_node, $a_with_data =
true, $a_type =
"")
901 $ilDB = $DIC[
'ilDB'];
903 if (!is_array($a_node)) {
927 $subtree[] = $row[
'child'];
930 if ($this->
__isMainTree() || $this->table_tree ==
"lm_tree") {
931 $this->in_tree_cache[$row[
'child']] =
true;
934 return $subtree ? $subtree : array();
947 $a_filter = $a_filter ? $a_filter : array();
949 foreach ($this->getSubtree($this->
getNodeData($a_node)) as $node) {
950 if (in_array($node[
"type"], $a_filter)) {
953 $types[
"$node[type]"] = $node[
"type"];
955 return $types ? $types : array();
969 $ilDB = $DIC[
'ilDB'];
971 $this->log->debug(
'Delete tree with node ' . $a_node);
973 if (!is_array($a_node)) {
978 $this->log->debug($this->tree_pk);
1015 $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
1020 $ilDB = $DIC[
'ilDB'];
1023 if (count($pathIds) == 0) {
1027 $inClause =
'child IN (';
1028 for (
$i = 0;
$i < count($pathIds);
$i++) {
1032 $inClause .=
$ilDB->quote($pathIds[
$i],
'integer');
1037 'FROM ' . $this->table_tree .
' ' .
1039 'WHERE ' . $inClause .
' ' .
1040 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = ' . $this->ilDB->quote($this->tree_id,
'integer') .
' ' .
1042 $r =
$ilDB->query($q);
1044 $pathFull = array();
1050 #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child']); 1051 $this->in_tree_cache[$row[
'child']] = $row[
'tree'] == 1;
1068 $ilDB = $DIC[
'ilDB'];
1074 $res =
$ilDB->query(
'SELECT t.depth, t.parent, t.child ' .
1075 'FROM ' . $this->table_tree .
' t ' .
1076 'WHERE ' .
$ilDB->in(
"child", $a_node_ids,
false,
"integer") .
1077 'AND ' . $this->tree_pk .
' = ' .
$ilDB->quote($this->tree_id,
"integer"));
1078 while ($row =
$ilDB->fetchAssoc(
$res)) {
1079 $this->depth_cache[$row[
"child"]] = $row[
"depth"];
1080 $this->parent_cache[$row[
"child"]] = $row[
"parent"];
1093 public function getPathId($a_endnode_id, $a_startnode_id = 0)
1095 if (!$a_endnode_id) {
1101 if ($this->
isCacheUsed() && isset($this->path_id_cache[$a_endnode_id][$a_startnode_id])) {
1103 return $this->path_id_cache[$a_endnode_id][$a_startnode_id];
1110 $this->path_id_cache[$a_endnode_id][$a_startnode_id] = $pathIds;
1137 $ilDB = $DIC[
'ilDB'];
1142 if ($titlePath == null || count($titlePath) == 0) {
1143 if ($a_startnode_id == 0) {
1151 if ($a_startnode_id != null && $a_startnode_id != 0) {
1154 $parent = $a_startnode_id;
1157 $nodePath = array();
1165 require_once(
'include/Unicode/UtfNormal.php');
1166 include_once
'./Services/Utilities/classes/class.ilStr.php';
1167 $inClause =
'd.title IN (';
1168 for (
$i = 0;
$i < count($titlePath);
$i++) {
1173 $inClause .=
$ilDB->quote($titlePath[$i],
'text');
1178 if ($this->table_obj_reference) {
1179 $joinClause =
'JOIN ' . $this->table_obj_reference .
' r ON t.child = r.' . $this->ref_pk .
' ' .
1180 'JOIN ' . $this->table_obj_data .
' d ON r.' . $this->obj_pk .
' = d.' .
$this->obj_pk;
1182 $joinClause =
'JOIN ' . $this->table_obj_data .
' d ON t.child = d.' .
$this->obj_pk;
1189 $q =
'SELECT t.depth, t.parent, t.child, d.' . $this->obj_pk .
' obj_id, d.type, d.title ' .
1190 'FROM ' . $this->table_tree .
' t ' .
1192 'WHERE ' . $inClause .
' ' .
1193 'AND t.depth <= ' . (count($titlePath) + count($nodePath)) .
' ' .
1195 'ORDER BY t.depth, t.child ASC';
1196 $r =
$ilDB->query($q);
1201 $row[
'ref_id'] = $row[
'child'];
1206 for (
$i = 0;
$i < count($titlePath);
$i++) {
1207 $pathElementFound =
false;
1208 foreach (
$rows as $row) {
1209 if ($row[
'parent'] == $parent &&
1214 $parent = $row[
'child'];
1215 $pathElementFound =
true;
1220 if (!$pathElementFound) {
1251 $ilDB = $DIC[
'ilDB'];
1253 $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
1256 if (count($pathIds) == 0) {
1263 for (
$i = 0;
$i < count($pathIds);
$i++) {
1264 $types[] =
'integer';
1268 $query =
'SELECT t.depth,t.parent,t.child,d.obj_id,d.type,d.title ' .
1269 'FROM ' . $this->table_tree .
' t ' .
1270 'JOIN ' . $this->table_obj_reference .
' r ON r.ref_id = t.child ' .
1271 'JOIN ' . $this->table_obj_data .
' d ON d.obj_id = r.obj_id ' .
1272 'WHERE ' .
$ilDB->in(
't.child',
$data,
false,
'integer') .
' ' .
1273 'ORDER BY t.depth ';
1277 $titlePath = array();
1278 while ($row =
$ilDB->fetchAssoc(
$res)) {
1279 $titlePath[] = $row;
1296 $ilDB = $DIC[
'ilDB'];
1298 $types = array(
'integer');
1299 $query =
'SELECT lft,rgt FROM ' . $this->table_tree .
' ' .
1300 'WHERE ' . $this->tree_pk .
' = %s ';
1303 while ($row =
$ilDB->fetchObject(
$res)) {
1308 $all = array_merge($lft, $rgt);
1309 $uni = array_unique($all);
1311 if (count($all) != count($uni)) {
1332 $ilDB = $DIC[
'ilDB'];
1334 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1335 'WHERE ' . $this->tree_pk .
' = %s ' .
1337 $r1 =
$ilDB->queryF(
$query, array(
'integer'), array($this->tree_id));
1339 while ($row =
$ilDB->fetchAssoc($r1)) {
1341 if (($row[
"child"] == 0) && $a_no_zero_child) {
1342 $message =
"Tree contains child with ID 0!";
1347 if ($this->table_obj_reference) {
1349 $query =
'SELECT * FROM ' . $this->table_obj_reference .
' WHERE ' . $this->ref_pk .
' = %s ';
1350 $r2 =
$ilDB->queryF(
$query, array(
'integer'), array($row[
'child']));
1353 if ($r2->numRows() == 0) {
1354 $message =
"No Object-to-Reference entry found for ID " . $row[
"child"] .
"!";
1358 if ($r2->numRows() > 1) {
1359 $message =
"More Object-to-Reference entries found for ID " . $row[
"child"] .
"!";
1365 $obj_ref =
$ilDB->fetchAssoc($r2);
1367 $query =
'SELECT * FROM ' . $this->table_obj_data .
' WHERE ' . $this->obj_pk .
' = %s';
1368 $r3 =
$ilDB->queryF(
$query, array(
'integer'), array($obj_ref[$this->obj_pk]));
1369 if ($r3->numRows() == 0) {
1374 if ($r3->numRows() > 1) {
1381 $query =
'SELECT * FROM ' . $this->table_obj_data .
' WHERE ' . $this->obj_pk .
' = %s';
1382 $r2 =
$ilDB->queryF(
$query, array(
'integer'), array($row[
'child']));
1384 if ($r2->numRows() == 0) {
1385 $message =
"No child found for ID " . $row[
"child"] .
"!";
1389 if ($r2->numRows() > 1) {
1390 $message =
"More childs found for ID " . $row[
"child"] .
"!";
1409 $ilDB = $DIC[
'ilDB'];
1415 return $row[
'depth'];
1428 $ilDB = $DIC[
'ilDB'];
1432 $query =
'SELECT depth FROM ' . $this->table_tree .
' ' .
1433 'WHERE child = %s ';
1437 $query =
'SELECT depth FROM ' . $this->table_tree .
' ' .
1438 'WHERE child = %s ' .
1439 'AND ' . $this->tree_pk .
' = %s ';
1440 $res =
$ilDB->queryF(
$query, array(
'integer',
'integer'), array($a_node_id,$this->tree_id));
1461 $ilDB = $DIC[
'ilDB'];
1468 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1469 'WHERE child = ' .
$ilDB->quote($a_node_id,
'integer');
1493 $ilDB = $DIC[
'ilDB'];
1495 if (!isset($a_node_id)) {
1500 if ($a_node_id < 1) {
1501 $message =
'No valid parameter given! $a_node_id: %s' . $a_node_id;
1509 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1511 'WHERE ' . $this->table_tree .
'.child = %s ' .
1512 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
1515 $a_tree_pk === null ? $this->tree_id : $a_tree_pk));
1534 $objDefinition = $DIC[
'objDefinition'];
1537 $ilDB = $DIC[
'ilDB'];
1541 $data[
"desc"] = $a_row[
"description"];
1546 if (is_object($objDefinition)) {
1547 $translation_type = $objDefinition->getTranslationType(
$data[
"type"]);
1551 if ($translation_type ==
"sys") {
1559 $data[
"description"] =
$lng->txt(
"obj_" .
$data[
"type"] .
"_desc");
1563 } elseif ($translation_type ==
"db") {
1567 array_key_exists(
$data[
"obj_id"] .
'.' . $lang_code, $this->translation_cache)) {
1568 $key =
$data[
"obj_id"] .
'.' . $lang_code;
1569 $data[
"title"] = $this->translation_cache[$key][
'title'];
1570 $data[
"description"] = $this->translation_cache[$key][
'description'];
1571 $data[
"desc"] = $this->translation_cache[$key][
'desc'];
1575 $query =
'SELECT title,description FROM object_translation ' .
1576 'WHERE obj_id = %s ' .
1577 'AND lang_code = %s ';
1585 $data[
"title"] = $row->title;
1587 $data[
"desc"] = $row->description;
1592 if ($this->
isCacheUsed() && count($this->translation_cache) < 1000) {
1593 $key =
$data[
"obj_id"] .
'.' . $lang_code;
1594 $this->translation_cache[$key] = array();
1595 $this->translation_cache[$key][
'title'] =
$data[
"title"] ;
1596 $this->translation_cache[$key][
'description'] =
$data[
"description"];
1597 $this->translation_cache[$key][
'desc'] =
$data[
"desc"];
1603 if (
$data[
'type'] ==
'crsr' or
$data[
'type'] ==
'catr' or
$data[
'type'] ==
'grpr' or
$data[
'type'] ===
'prgr') {
1604 include_once(
'./Services/ContainerReference/classes/class.ilContainerReference.php');
1620 $ilObjDataCache = $DIC[
'ilObjDataCache'];
1622 if ($this->
isCacheUsed() && is_array($a_obj_ids) && is_object($ilObjDataCache)) {
1623 foreach ($a_obj_ids as $id) {
1624 $this->translation_cache[$id .
'.'][
'title'] = $ilObjDataCache->lookupTitle($id);
1625 $this->translation_cache[$id .
'.'][
'description'] = $ilObjDataCache->lookupDescription($id);
1627 $this->translation_cache[$id .
'.'][
'desc'] =
1628 $this->translation_cache[$id .
'.'][
'description'];
1645 $ilDB = $DIC[
'ilDB'];
1647 if (!isset($a_node_id)) {
1649 #$this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING); 1652 if ($this->
isCacheUsed() && isset($this->in_tree_cache[$a_node_id])) {
1653 #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Using in tree cache '.$a_node_id); 1655 return $this->in_tree_cache[$a_node_id];
1658 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1659 'WHERE ' . $this->table_tree .
'.child = %s ' .
1660 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s';
1666 if (
$res->numRows() > 0) {
1668 #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = true'); 1669 $this->in_tree_cache[$a_node_id] =
true;
1674 #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = false'); 1675 $this->in_tree_cache[$a_node_id] =
false;
1692 $ilDB = $DIC[
'ilDB'];
1695 $ilLog = $DIC[
'ilLog'];
1697 if (!isset($a_node_id)) {
1702 if ($this->table_obj_reference) {
1704 $innerjoin =
"JOIN " . $this->table_obj_reference .
" ON v.child=" . $this->table_obj_reference .
"." . $this->ref_pk .
" " .
1705 "JOIN " . $this->table_obj_data .
" ON " . $this->table_obj_reference .
"." . $this->obj_pk .
"=" . $this->table_obj_data .
"." . $this->obj_pk .
" ";
1708 $innerjoin =
"JOIN " . $this->table_obj_data .
" ON v.child=" . $this->table_obj_data .
"." . $this->obj_pk .
" ";
1711 $query =
'SELECT * FROM ' . $this->table_tree .
' s, ' . $this->table_tree .
' v ' .
1713 'WHERE s.child = %s ' .
1714 'AND s.parent = v.child ' .
1715 'AND s.' . $this->tree_pk .
' = %s ' .
1716 'AND v.' . $this->tree_pk .
' = %s';
1717 $res =
$ilDB->queryF(
$query, array(
'integer',
'integer',
'integer'), array(
1734 return $this->
getRelation($a_startnode_id, $a_querynode_id) == self::RELATION_PARENT;
1746 public function addTree($a_tree_id, $a_node_id = -1)
1750 $ilDB = $DIC[
'ilDB'];
1755 'Operation not allowed on main tree! $a_tree_if: %s $a_node_id: %s',
1763 if (!isset($a_tree_id)) {
1769 if ($a_node_id <= 0) {
1770 $a_node_id = $a_tree_id;
1773 $query =
'INSERT INTO ' . $this->table_tree .
' (' .
1774 $this->tree_pk .
', child,parent,lft,rgt,depth) ' .
1776 '(%s,%s,%s,%s,%s,%s)';
1777 $res =
$ilDB->manipulateF(
$query, array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'), array(
1801 $ilDB = $DIC[
'ilDB'];
1803 if (!isset($a_type) or (!is_string($a_type))) {
1808 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1810 'WHERE ' . $this->table_obj_data .
'.type = ' . $this->ilDB->quote($a_type,
'text') .
1811 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = ' . $this->ilDB->quote($this->tree_id,
'integer');
1815 while ($row =
$ilDB->fetchAssoc(
$res)) {
1834 $ilDB = $DIC[
'ilDB'];
1846 $query =
'DELETE FROM ' . $this->table_tree .
1847 ' WHERE ' . $this->tree_pk .
' = %s ';
1848 $ilDB->manipulateF(
$query, array(
'integer'), array($a_tree_id));
1860 public function moveToTrash($a_node_id, $a_set_deleted =
false, $a_deleted_by = 0)
1864 $ilDB = $DIC->database();
1865 $user = $DIC->user();
1866 if(!$a_deleted_by) {
1867 $a_deleted_by = $user->getId();
1879 $subnodes = array();
1881 $subnodes[] = $row[
'child'];
1884 if (!count($subnodes)) {
1889 if ($a_set_deleted) {
1905 return $this->
isSaved($a_node_id);
1917 $ilDB = $DIC[
'ilDB'];
1920 if ($this->
isCacheUsed() && isset($this->is_saved_cache[$a_node_id])) {
1922 return $this->is_saved_cache[$a_node_id];
1925 $query =
'SELECT ' . $this->tree_pk .
' FROM ' . $this->table_tree .
' ' .
1926 'WHERE child = %s ';
1930 if ($row[$this->tree_pk] < 0) {
1932 $this->is_saved_cache[$a_node_id] =
true;
1937 $this->is_saved_cache[$a_node_id] =
false;
1953 $ilDB = $DIC[
'ilDB'];
1955 if (!is_array($a_node_ids) || !$this->
isCacheUsed()) {
1959 $query =
'SELECT ' . $this->tree_pk .
', child FROM ' . $this->table_tree .
' ' .
1960 'WHERE ' .
$ilDB->in(
"child", $a_node_ids,
false,
"integer");
1963 while ($row =
$ilDB->fetchAssoc(
$res)) {
1964 if ($row[$this->tree_pk] < 0) {
1966 $this->is_saved_cache[$row[
"child"]] =
true;
1970 $this->is_saved_cache[$row[
"child"]] =
false;
1988 $ilDB = $DIC[
'ilDB'];
1990 if (!isset($a_parent_id)) {
1996 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1998 'WHERE ' . $this->table_tree .
'.' . $this->tree_pk .
' < %s ' .
1999 'AND ' . $this->table_tree .
'.parent = %s';
2004 while ($row =
$ilDB->fetchAssoc(
$res)) {
2008 return $saved ? $saved : array();
2021 $ilDB = $DIC[
'ilDB'];
2023 $query =
'SELECT ' . $this->table_obj_data .
'.obj_id FROM ' . $this->table_tree .
' ' .
2025 'WHERE ' . $this->table_tree .
'.' . $this->tree_pk .
' < ' .
$ilDB->quote(0,
'integer') .
' ' .
2026 'AND ' .
$ilDB->in($this->table_obj_data .
'.obj_id', $a_obj_ids,
'',
'integer');
2028 while ($row =
$ilDB->fetchAssoc(
$res)) {
2029 $saved[] = $row[
'obj_id'];
2032 return $saved ? $saved : array();
2046 $ilDB = $DIC[
'ilDB'];
2048 if (!isset($a_node_id)) {
2055 $query =
'SELECT parent FROM ' . $this->table_tree .
' ' .
2056 'WHERE child = %s ';
2063 $query =
'SELECT parent FROM ' . $this->table_tree .
' ' .
2064 'WHERE child = %s ' .
2065 'AND ' . $this->tree_pk .
' = %s ';
2072 return $row->parent;
2086 $ilDB = $DIC[
'ilDB'];
2088 if (!isset($a_node_id)) {
2094 $query =
'SELECT lft FROM ' . $this->table_tree .
' ' .
2095 'WHERE child = %s ' .
2096 'AND ' . $this->tree_pk .
' = %s ';
2115 $ilDB = $DIC[
'ilDB'];
2117 if (!isset($a_node)) {
2124 $query =
'SELECT count(*) cnt FROM ' . $this->table_tree .
' ' .
2126 'WHERE lft <= %s ' .
2128 'AND parent = %s ' .
2129 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
2131 $res =
$ilDB->queryF(
$query, array(
'integer',
'text',
'integer',
'integer'), array(
2137 $query =
'SELECT count(*) cnt FROM ' . $this->table_tree .
' ' .
2139 'WHERE lft <= %s ' .
2140 'AND parent = %s ' .
2141 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
2143 $res =
$ilDB->queryF(
$query, array(
'integer',
'integer',
'integer'), array(
2162 $ilDB = $DIC[
'ilDB'];
2164 $query =
'SELECT child FROM ' . $this->table_tree .
' ' .
2165 'WHERE parent = %s ' .
2166 'AND ' . $this->tree_pk .
' = %s ';
2171 $this->root_id = $row->child;
2186 $this->root_id = $a_root_id;
2206 $this->tree_id = $a_tree_id;
2221 $ilDB = $DIC[
'ilDB'];
2223 if (!isset($a_node_id)) {
2230 $query =
'SELECT lft FROM ' . $this->table_tree .
' ' .
2231 'WHERE ' . $this->table_tree .
'.child = %s ' .
2232 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
2239 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2242 'AND ' . $this->table_obj_data .
'.type = %s ' .
2243 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ' .
2246 $res =
$ilDB->queryF(
$query, array(
'integer',
'text',
'integer'), array(
2251 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2254 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ' .
2262 if (
$res->numRows() < 1) {
2282 $ilDB = $DIC[
'ilDB'];
2284 if (!isset($a_node_id)) {
2291 $query =
'SELECT lft FROM ' . $this->table_tree .
' ' .
2292 'WHERE ' . $this->table_tree .
'.child = %s ' .
2293 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ';
2301 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2304 'AND ' . $this->table_obj_data .
'.type = %s ' .
2305 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ' .
2306 'ORDER BY lft DESC';
2308 $res =
$ilDB->queryF(
$query, array(
'integer',
'text',
'integer'), array(
2313 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2316 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = %s ' .
2317 'ORDER BY lft DESC';
2324 if (
$res->numRows() < 1) {
2344 $ilDB = $DIC[
'ilDB'];
2352 $ilAtomQuery =
$ilDB->buildAtomQuery();
2353 $ilAtomQuery->addTableLock($this->table_tree);
2355 $ilAtomQuery->addQueryCallable($renumber_callable);
2356 $ilAtomQuery->run();
2358 $renumber_callable(
$ilDB);
2377 $ilDB = $DIC[
'ilDB'];
2380 $query =
'UPDATE ' . $this->table_tree .
' SET lft = %s WHERE child = %s';
2383 array(
'integer',
'integer'),
2389 $query =
'UPDATE ' . $this->table_tree .
' SET lft = %s WHERE child = %s AND tree = %s';
2392 array(
'integer',
'integer',
'integer'),
2400 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2401 'WHERE parent = ' .
$ilDB->quote($node_id,
'integer') .
' ' .
2407 $childs[] = $row->child;
2410 foreach ($childs as $child) {
2416 if (count($childs) > 0) {
2417 $i += $this->gap * 2;
2422 $query =
'UPDATE ' . $this->table_tree .
' SET rgt = %s WHERE child = %s';
2425 array(
'integer',
'integer'),
2431 $query =
'UPDATE ' . $this->table_tree .
' SET rgt = %s WHERE child = %s AND tree = %s';
2432 $res =
$ilDB->manipulateF(
$query, array(
'integer',
'integer',
'integer'), array(
2454 $cache_key = $a_ref_id .
'.' . $a_type .
'.' . ((int) $a_exclude_source_check);
2458 array_key_exists($cache_key, $this->parent_type_cache)) {
2459 return $this->parent_type_cache[$cache_key];
2463 $do_cache = ($this->
__isMainTree() && count($this->parent_type_cache) < 1000);
2468 $this->parent_type_cache[$cache_key] =
false;
2473 $path = array_reverse($this->
getPathFull($a_ref_id));
2476 if ($a_exclude_source_check) {
2480 foreach ($path as $node) {
2482 if ($node[
"type"] == $a_type) {
2484 $this->parent_type_cache[$cache_key] = $node[
"child"];
2486 return $node[
"child"];
2491 $this->parent_type_cache[$cache_key] =
false;
2506 public static function _removeEntry($a_tree, $a_child, $a_db_table =
"tree")
2510 $ilDB = $DIC[
'ilDB'];
2512 if ($a_db_table ===
'tree') {
2515 'Tried to delete root node! $a_tree: %s $a_child: %s',
2524 $query =
'DELETE FROM ' . $a_db_table .
' ' .
2525 'WHERE tree = %s ' .
2540 return $this->table_tree ===
'tree';
2558 $ilDB = $DIC[
'ilDB'];
2562 $this->log->debug(
$query);
2565 $counter = (int) $lft_childs = array();
2566 while ($row =
$ilDB->fetchObject(
$res)) {
2567 $lft_childs[$row->child] = $row->parent;
2572 if ($counter != count($lft_childs)) {
2573 $message =
'Duplicate entries for "child" in maintree! $a_node_id: ' . $a_node[
'child'];
2580 $parent_childs = array();
2600 $ilDB = $DIC[
'ilDB'];
2603 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2604 'WHERE child = %s ' .
2611 while ($row =
$ilDB->fetchObject(
$res)) {
2612 $parent_childs[$a_node_id] = $row->parent;
2617 $message =
'Multiple entries in maintree! $a_node_id: ' . $a_node_id;
2624 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
2625 'WHERE parent = %s ';
2628 while ($row =
$ilDB->fetchObject(
$res)) {
2646 ksort($parent_childs);
2648 $this->log->debug(
'left childs ' . print_r($lft_childs,
true));
2649 $this->log->debug(
'parent childs ' . print_r($parent_childs,
true));
2651 if (count($lft_childs) != count($parent_childs)) {
2652 $message =
'(COUNT) Tree is corrupted! Left/Right subtree does not comply with parent relation';
2658 foreach ($lft_childs as $key => $value) {
2659 if ($parent_childs[$key] != $value) {
2660 $message =
'(COMPARE) Tree is corrupted! Left/Right subtree does not comply with parent relation';
2665 $message =
'(ROOT_FOLDER) Tree is corrupted! Tried to delete root folder';
2682 public function moveTree($a_source_id, $a_target_id, $a_location = self::POS_LAST_NODE)
2684 $old_parent_id = $this->
getParentId($a_source_id);
2687 $GLOBALS[
'DIC'][
'ilAppEventHandler']->raise(
2691 'tree' => $this->table_tree,
2692 'source_id' => $a_source_id,
2693 'target_id' => $a_target_id,
2694 'old_parent_id' => $old_parent_id
2724 public function getSubTreeQuery($a_node_id, $a_fields = array(), $a_types =
'', $a_force_join_reference =
false)
2729 $a_force_join_reference,
2742 $a_force_join_reference,
2760 $ilDB = $DIC[
'ilDB'];
2763 if (!
sizeof($node)) {
2772 if (count($a_fields)) {
2773 $fields = implode(
',', $a_fields);
2776 $query =
"SELECT " . $fields .
2782 while ($row =
$ilDB->fetchAssoc($set)) {
2793 $ilDB = $DIC[
'ilDB'];
2794 $ilAppEventHandler = $DIC[
'ilAppEventHandler'];
2796 $query =
'DELETE FROM tree where ' .
2797 'child = ' .
$ilDB->quote($a_node_id,
'integer') .
' ' .
2798 'AND tree = ' .
$ilDB->quote($a_tree_id,
'integer');
2801 $ilAppEventHandler->raise(
2804 array(
'tree' => $this->table_tree,
2805 'node_id' => $a_node_id,
2806 'tree_id' => $a_tree_id
2820 $ilDB = $DIC[
'ilDB'];
2822 $query =
'SELECT DISTINCT(o.type) ' .
$ilDB->quoteIdentifier(
'type') .
' FROM tree t JOIN object_reference r ON child = r.ref_id ' .
2823 'JOIN object_data o on r.obj_id = o.obj_id ' .
2824 'WHERE tree < ' .
$ilDB->quote(0,
'integer') .
' ' .
2825 'AND child = -tree ' .
2829 $types_deleted = array();
2831 $types_deleted[] = $row->type;
2833 return $types_deleted;
2841 if ($this->table_tree ==
'tree') {
isRepositoryTree()
check if current tree instance operates on repository tree table
removeTree($a_tree_id)
remove an existing tree
Thrown if invalid tree strucutes are found.
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.
static setDeletedDates($a_ref_ids, $a_user_id)
Set deleted date.
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
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 lookupTreesForNode(int $node_id)
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
const TREE_TYPE_MATERIALIZED_PATH
__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.
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...
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.
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
getParentId($a_node_id)
get parent id of given node public
moveToTrash($a_node_id, $a_set_deleted=false, $a_deleted_by=0)
Move node to trash bin.
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.
__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. ...
const TREE_TYPE_NESTED_SET
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
getTrashSubTreeQuery($a_node_id, $a_fields=[], $a_types='', $a_force_join_reference=false)
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