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) )
162 $this->log->error(
"No tree_id given!");
167 if (func_num_args() > 2)
169 $this->log->error(
"Wrong parameter count!");
174 if (empty($a_root_id))
176 $a_root_id = ROOT_FOLDER_ID;
179 $this->tree_id = $a_tree_id;
180 $this->root_id = $a_root_id;
181 $this->table_tree =
'tree';
182 $this->table_obj_data =
'object_data';
183 $this->table_obj_reference =
'object_reference';
184 $this->ref_pk =
'ref_id';
185 $this->obj_pk =
'obj_id';
186 $this->tree_pk =
'tree';
188 $this->use_cache =
true;
191 $this->translation_cache =
array();
192 $this->parent_type_cache =
array();
210 if(!is_object(
$GLOBALS[
'ilSetting'])
or $GLOBALS[
'ilSetting']->getModule() !=
'common')
212 include_once
'./Services/Administration/classes/class.ilSetting.php';
222 if($setting->get(
'main_tree_impl',
'ns') ==
'ns')
224 #$GLOBALS['ilLog']->write(__METHOD__.': Using nested set.'); 225 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
230 #$GLOBALS['ilLog']->write(__METHOD__.': Using materialized path.'); 231 include_once
'./Services/Tree/classes/class.ilMaterializedPathTree.php';
237 #$GLOBALS['ilLog']->write(__METHOD__.': Using netsted set for non main tree.'); 238 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
257 $this->use_cache = $a_use;
296 if (!is_object($ilUser))
298 $this->lang_code =
"en";
302 $this->lang_code = $ilUser->getCurrentLanguage();
354 $this->in_tree_cache =
array();
374 function setTableNames($a_table_tree,$a_table_obj_data,$a_table_obj_reference =
"")
376 if (!isset($a_table_tree)
or !isset($a_table_obj_data))
378 $message =
"Missing parameter! ".
379 "tree table: ".$a_table_tree.
" object data table: ".$a_table_obj_data;
380 $this->log->error($message);
384 $this->table_tree = $a_table_tree;
385 $this->table_obj_data = $a_table_obj_data;
386 $this->table_obj_reference = $a_table_obj_reference;
402 if (!isset($a_column_name))
404 $message =
"No column name given!";
405 $this->log->error($message);
409 $this->ref_pk = $a_column_name;
422 if (!isset($a_column_name))
424 $message =
"No column name given!";
425 $this->log->error($message);
429 $this->obj_pk = $a_column_name;
442 if (!isset($a_column_name))
444 $message =
"No column name given!";
445 $this->log->error($message);
449 $this->tree_pk = $a_column_name;
460 if ($this->table_obj_reference)
463 return "JOIN ".$this->table_obj_reference.
" ON ".$this->table_tree.
".child=".$this->table_obj_reference.
".".$this->ref_pk.
" ".
464 "JOIN ".$this->table_obj_data.
" ON ".$this->table_obj_reference.
".".$this->obj_pk.
"=".$this->table_obj_data.
".".$this->obj_pk.
" ";
469 return "JOIN ".$this->table_obj_data.
" ON ".$this->table_tree.
".child=".$this->table_obj_data.
".".$this->obj_pk.
" ";
507 $query =
'SELECT * FROM '. $this->table_tree .
' ' .
508 'WHERE parent = '.$ilDB->quote($a_node,
'integer').
' '.
509 'AND tree = '.$ilDB->quote($this->tree_id,
'integer' .
' ' .
516 $childs[] =
$row->child;
530 function getChilds($a_node_id, $a_order =
"", $a_direction =
"ASC")
534 if (!isset($a_node_id))
536 $message =
"No node_id given!";
537 $this->log->error($message);
551 if (!empty($a_order))
553 $order_clause =
"ORDER BY ".$a_order.
" ".$a_direction;
557 $order_clause =
"ORDER BY ".$this->table_tree.
".lft";
561 $query = sprintf(
'SELECT * FROM '.$this->table_tree.
' '.
563 "WHERE parent = %s " .
564 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
566 $ilDB->quote($a_node_id,
'integer'),
567 $ilDB->quote($this->tree_id,
'integer'));
571 if(!$count = $res->numRows())
578 while(
$r = $ilDB->fetchAssoc($res))
581 $obj_ids[] =
$r[
"obj_id"];
586 is_object($ilUser) && $this->lang_code == $ilUser->getLanguage() && !$this->oc_preloaded[$a_node_id])
589 $ilObjDataCache->preloadObjectCache($obj_ids, $this->lang_code);
591 $this->oc_preloaded[$a_node_id] =
true;
594 foreach ($rows as
$row)
601 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child'].' = true'); 602 $this->in_tree_cache[$row[
'child']] = $row[
'tree'] == 1;
605 $childs[$count - 1][
"last"] =
true;
620 $childs = $this->
getChilds($a_node,$a_order,$a_direction);
622 foreach($childs as $child)
624 if(!in_array($child[
"type"],$a_filter))
626 $filtered[] = $child;
629 return $filtered ? $filtered :
array();
645 if (!isset($a_node_id)
or !isset(
$a_type))
647 $message =
"Missing parameter! node_id:".$a_node_id.
" type:".
$a_type;
648 $this->log->error($message);
652 if (
$a_type==
'rolf' && $this->table_obj_reference) {
656 $ilDB->setLimit(1,0);
657 $query = sprintf(
"SELECT * FROM ".$this->table_tree.
" ".
659 "WHERE parent = %s ".
660 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
661 "AND ".$this->table_obj_data.
".type = %s ",
662 $ilDB->quote($a_node_id,
'integer'),
663 $ilDB->quote($this->tree_id,
'integer'),
666 $query = sprintf(
"SELECT * FROM ".$this->table_tree.
" ".
668 "WHERE parent = %s ".
669 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
670 "AND ".$this->table_obj_data.
".type = %s ".
671 "ORDER BY ".$this->table_tree.
".lft",
672 $ilDB->quote($a_node_id,
'integer'),
673 $ilDB->quote($this->tree_id,
'integer'),
680 while(
$row = $ilDB->fetchAssoc($res))
685 return $childs ? $childs :
array();
701 if (!isset($a_node_id)
or !$a_types)
703 $message =
"Missing parameter! node_id:".$a_node_id.
" type:".$a_types;
704 $this->log->error($message);
711 $filter =
'AND '.$this->table_obj_data.
'.type IN('.implode(
',',
ilUtil::quoteArray($a_types)).
') ';
715 if (!empty($a_order))
717 $order_clause =
"ORDER BY ".$a_order.
" ".$a_direction;
721 $order_clause =
"ORDER BY ".$this->table_tree.
".lft";
724 $query =
'SELECT * FROM '.$this->table_tree.
' '.
726 'WHERE parent = '.$ilDB->quote($a_node_id,
'integer').
' '.
727 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = '.$ilDB->quote($this->tree_id,
'integer').
' '.
732 while(
$row = $ilDB->fetchAssoc(
$res))
737 return $childs ? $childs :
array();
757 if($a_source_id <= 1
or $a_target_id <= 0)
763 if (!isset($a_source_id)
or !isset($a_target_id))
775 $query =
'DELETE from tree '.
776 'WHERE tree = '.$ilDB->quote($a_tree_id,
'integer').
' '.
777 'AND child = '.$ilDB->quote($a_source_id,
'integer');
778 $ilDB->manipulate(
$query);
800 if($a_node_id <= 1
or $a_parent_id <= 0)
802 $message = sprintf(
'Invalid parameters! $a_node_id: %s $a_parent_id: %s',
811 if (!isset($a_node_id)
or !isset($a_parent_id))
815 "node_id: ".$a_node_id.
" parent_id: ".$a_parent_id);
820 $this->table_tree.
"!");
825 $this->in_tree_cache[$a_node_id] =
true;
828 if ($a_reset_deletion_date)
834 $GLOBALS[
'ilAppEventHandler']->raise(
838 'tree' => $this->table_tree,
839 'node_id' => $a_node_id,
840 'parent_id' => $a_parent_id)
865 if($depth
and $subnode[
'depth'] > $depth)
869 if(!$first
and in_array($subnode[
'type'],$a_filter))
871 $depth = $subnode[
'depth'];
877 $filtered[] = $subnode;
879 return $filtered ? $filtered :
array();
906 if (!is_array($a_node))
927 while(
$row = $ilDB->fetchAssoc(
$res))
935 $subtree[] =
$row[
'child'];
938 if($this->
__isMainTree() || $this->table_tree ==
"lm_tree")
940 $this->in_tree_cache[
$row[
'child']] =
true;
943 return $subtree ? $subtree :
array();
956 $a_filter = $a_filter ? $a_filter :
array();
958 foreach($this->getSubtree($this->
getNodeData($a_node)) as $node)
960 if(in_array($node[
"type"],$a_filter))
964 $types[
"$node[type]"] = $node[
"type"];
966 return $types ? $types :
array();
980 $this->log->debug(
'Delete tree with node '. $a_node);
982 if (!is_array($a_node))
988 $this->log->debug($this->tree_pk);
1027 $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
1033 if (count($pathIds) == 0)
1038 $inClause =
'child IN (';
1039 for ($i=0; $i < count($pathIds); $i++)
1041 if ($i > 0) $inClause .=
',';
1042 $inClause .= $ilDB->quote($pathIds[$i],
'integer');
1047 'FROM '.$this->table_tree.
' '.
1049 'WHERE '.$inClause.
' '.
1050 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = '.$this->
ilDB->
quote($this->tree_id,
'integer').
' '.
1052 $r = $ilDB->query($q);
1054 $pathFull =
array();
1062 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child']); 1063 $this->in_tree_cache[
$row[
'child']] = $row[
'tree'] == 1;
1085 $res = $ilDB->query(
'SELECT t.depth, t.parent, t.child '.
1086 'FROM '.$this->table_tree.
' t '.
1087 'WHERE '.$ilDB->in(
"child", $a_node_ids,
false,
"integer").
1088 'AND '.$this->tree_pk.
' = '.$ilDB->quote($this->tree_id,
"integer"));
1089 while (
$row = $ilDB->fetchAssoc(
$res))
1091 $this->depth_cache[
$row[
"child"]] = $row[
"depth"];
1092 $this->parent_cache[$row[
"child"]] = $row[
"parent"];
1105 public function getPathId($a_endnode_id, $a_startnode_id = 0)
1114 if ($this->
isCacheUsed() && isset($this->path_id_cache[$a_endnode_id][$a_startnode_id]))
1117 return $this->path_id_cache[$a_endnode_id][$a_startnode_id];
1125 $this->path_id_cache[$a_endnode_id][$a_startnode_id] = $pathIds;
1154 if ($titlePath == null || count($titlePath) == 0)
1156 if ($a_startnode_id == 0)
1167 if ($a_startnode_id != null && $a_startnode_id != 0)
1171 $parent = $a_startnode_id;
1176 $nodePath =
array();
1184 require_once(
'include/Unicode/UtfNormal.php');
1185 include_once
'./Services/Utilities/classes/class.ilStr.php';
1186 $inClause =
'd.title IN (';
1187 for ($i=0; $i < count($titlePath); $i++)
1190 if ($i > 0) $inClause .=
',';
1191 $inClause .= $ilDB->quote($titlePath[$i],
'text');
1196 if ($this->table_obj_reference)
1198 $joinClause =
'JOIN '.$this->table_obj_reference.
' r ON t.child = r.'.$this->ref_pk.
' '.
1199 'JOIN '.$this->table_obj_data.
' d ON r.'.$this->obj_pk.
' = d.'.
$this->obj_pk;
1203 $joinClause =
'JOIN '.$this->table_obj_data.
' d ON t.child = d.'.
$this->obj_pk;
1210 $q =
'SELECT t.depth, t.parent, t.child, d.'.$this->obj_pk.
' obj_id, d.type, d.title '.
1211 'FROM '.$this->table_tree.
' t '.
1213 'WHERE '.$inClause.
' '.
1214 'AND t.depth <= '.(count($titlePath)+count($nodePath)).
' '.
1216 'ORDER BY t.depth, t.child ASC';
1217 $r = $ilDB->query($q);
1228 for ($i = 0; $i < count($titlePath); $i++) {
1229 $pathElementFound =
false;
1230 foreach ($rows as
$row) {
1231 if ($row[
'parent'] == $parent &&
1237 $parent = $row[
'child'];
1238 $pathElementFound =
true;
1243 if (! $pathElementFound)
1275 $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
1278 if (count($pathIds) == 0)
1286 for ($i = 0; $i < count($pathIds); $i++)
1288 $types[] =
'integer';
1289 $data[] = $pathIds[$i];
1292 $query =
'SELECT t.depth,t.parent,t.child,d.obj_id,d.type,d.title '.
1293 'FROM '.$this->table_tree.
' t '.
1294 'JOIN '.$this->table_obj_reference.
' r ON r.ref_id = t.child '.
1295 'JOIN '.$this->table_obj_data.
' d ON d.obj_id = r.obj_id '.
1296 'WHERE '.$ilDB->in(
't.child',
$data,
false,
'integer').
' '.
1297 'ORDER BY t.depth ';
1301 $titlePath =
array();
1302 while (
$row = $ilDB->fetchAssoc(
$res))
1304 $titlePath[] =
$row;
1321 $types =
array(
'integer');
1322 $query =
'SELECT lft,rgt FROM '.$this->table_tree.
' '.
1323 'WHERE '.$this->tree_pk.
' = %s ';
1326 while (
$row = $ilDB->fetchObject(
$res))
1332 $all = array_merge($lft,$rgt);
1333 $uni = array_unique($all);
1335 if (count($all) != count($uni))
1337 $message =
'Tree is corrupted!';
1339 $this->log->error($message);
1357 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1358 'WHERE '.$this->tree_pk.
' = %s '.
1362 while (
$row = $ilDB->fetchAssoc($r1))
1365 if ((
$row[
"child"] == 0) && $a_no_zero_child)
1367 $message =
"Tree contains child with ID 0!";
1368 $this->log->error($message);
1372 if ($this->table_obj_reference)
1375 $query =
'SELECT * FROM '.$this->table_obj_reference.
' WHERE '.$this->ref_pk.
' = %s ';
1379 if ($r2->numRows() == 0)
1381 $message =
"No Object-to-Reference entry found for ID ".
$row[
"child"].
"!";
1382 $this->log->error($message);
1385 if ($r2->numRows() > 1)
1387 $message =
"More Object-to-Reference entries found for ID ".
$row[
"child"].
"!";
1388 $this->log->error($message);
1393 $obj_ref = $ilDB->fetchAssoc($r2);
1395 $query =
'SELECT * FROM '.$this->table_obj_data.
' WHERE '.$this->obj_pk.
' = %s';
1396 $r3 = $ilDB->queryF(
$query,
array(
'integer'),
array($obj_ref[$this->obj_pk]));
1397 if ($r3->numRows() == 0)
1399 $message =
" No child found for ID ". $obj_ref[
$this->obj_pk].
"!";
1400 $this->log->error($message);
1403 if ($r3->numRows() > 1)
1405 $message =
"More childs found for ID ". $obj_ref[
$this->obj_pk].
"!";
1406 $this->log->error($message);
1414 $query =
'SELECT * FROM '.$this->table_obj_data.
' WHERE '.$this->obj_pk.
' = %s';
1417 if ($r2->numRows() == 0)
1419 $message =
"No child found for ID ".
$row[
"child"].
"!";
1420 $this->log->error($message);
1423 if ($r2->numRows() > 1)
1425 $message =
"More childs found for ID ".
$row[
"child"].
"!";
1426 $this->log->error($message);
1444 $query =
'SELECT MAX(depth) depth FROM '.$this->table_tree;
1448 return $row[
'depth'];
1463 $query =
'SELECT depth FROM '.$this->table_tree.
' '.
1464 'WHERE child = %s '.
1465 'AND '.$this->tree_pk.
' = %s ';
1494 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1495 'WHERE child = '.$ilDB->quote($a_node_id,
'integer');
1520 if (!isset($a_node_id))
1529 $message =
'No valid parameter given! $a_node_id: %s'.$a_node_id;
1531 $this->log->error($message);
1537 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1539 'WHERE '.$this->table_tree.
'.child = %s '.
1540 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
1543 $a_tree_pk === null ? $this->tree_id : $a_tree_pk));
1564 $data[
"desc"] = $a_row[
"description"];
1569 if (is_object($objDefinition))
1571 $translation_type = $objDefinition->getTranslationType(
$data[
"type"]);
1575 if ($translation_type ==
"sys")
1578 if (
$data[
"type"] ==
"rolf" and $data[
"obj_id"] != ROLE_FOLDER_ID)
1580 $data[
"description"] = $lng->txt(
"obj_".
$data[
"type"].
"_local_desc").$data[
"title"].$data[
"desc"];
1581 $data[
"desc"] = $lng->txt(
"obj_".
$data[
"type"].
"_local_desc").$data[
"title"].$data[
"desc"];
1582 $data[
"title"] = $lng->txt(
"obj_".
$data[
"type"].
"_local");
1586 $data[
"title"] = $lng->txt(
"obj_".
$data[
"type"]);
1587 $data[
"description"] = $lng->txt(
"obj_".
$data[
"type"].
"_desc");
1588 $data[
"desc"] = $lng->txt(
"obj_".
$data[
"type"].
"_desc");
1592 elseif ($translation_type ==
"db")
1597 array_key_exists(
$data[
"obj_id"].
'.'.$lang_code, $this->translation_cache)) {
1599 $key =
$data[
"obj_id"].
'.'.$lang_code;
1600 $data[
"title"] = $this->translation_cache[$key][
'title'];
1601 $data[
"description"] = $this->translation_cache[$key][
'description'];
1602 $data[
"desc"] = $this->translation_cache[$key][
'desc'];
1608 $query =
'SELECT title,description FROM object_translation '.
1609 'WHERE obj_id = %s '.
1610 'AND lang_code = %s '.
1611 'AND NOT lang_default = %s';
1628 if ($this->
isCacheUsed() && count($this->translation_cache) < 1000)
1630 $key =
$data[
"obj_id"].
'.'.$lang_code;
1631 $this->translation_cache[$key] =
array();
1632 $this->translation_cache[$key][
'title'] =
$data[
"title"] ;
1633 $this->translation_cache[$key][
'description'] =
$data[
"description"];
1634 $this->translation_cache[$key][
'desc'] =
$data[
"desc"];
1642 include_once(
'./Services/ContainerReference/classes/class.ilContainerReference.php');
1656 global $ilObjDataCache;
1658 if ($this->
isCacheUsed() && is_array($a_obj_ids) && is_object($ilObjDataCache))
1660 foreach ($a_obj_ids as $id)
1662 $this->translation_cache[$id.
'.'][
'title'] = $ilObjDataCache->lookupTitle($id);
1663 $this->translation_cache[$id.
'.'][
'description'] = $ilObjDataCache->lookupDescription($id);;
1664 $this->translation_cache[$id.
'.'][
'desc'] =
1665 $this->translation_cache[$id.
'.'][
'description'];
1682 if (!isset($a_node_id))
1685 #$this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING); 1688 if ($this->
isCacheUsed() && isset($this->in_tree_cache[$a_node_id]))
1690 #$GLOBALS['ilLog']->write(__METHOD__.': Using in tree cache '.$a_node_id); 1692 return $this->in_tree_cache[$a_node_id];
1695 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1696 'WHERE '.$this->table_tree.
'.child = %s '.
1697 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s';
1703 if (
$res->numRows() > 0)
1707 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = true'); 1708 $this->in_tree_cache[$a_node_id] =
true;
1716 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = false'); 1717 $this->in_tree_cache[$a_node_id] =
false;
1735 if (!isset($a_node_id))
1741 if ($this->table_obj_reference)
1744 $innerjoin =
"JOIN ".$this->table_obj_reference.
" ON v.child=".$this->table_obj_reference.
".".$this->ref_pk.
" ".
1745 "JOIN ".$this->table_obj_data.
" ON ".$this->table_obj_reference.
".".$this->obj_pk.
"=".$this->table_obj_data.
".".$this->obj_pk.
" ";
1750 $innerjoin =
"JOIN ".$this->table_obj_data.
" ON v.child=".$this->table_obj_data.
".".$this->obj_pk.
" ";
1753 $query =
'SELECT * FROM '.$this->table_tree.
' s, '.$this->table_tree.
' v '.
1755 'WHERE s.child = %s '.
1756 'AND s.parent = v.child '.
1757 'AND s.'.$this->tree_pk.
' = %s '.
1758 'AND v.'.$this->tree_pk.
' = %s';
1776 return $this->
getRelation($a_startnode_id, $a_querynode_id) == self::RELATION_PARENT;
1795 $message = sprintf(
'Operation not allowed on main tree! $a_tree_if: %s $a_node_id: %s',
1798 $this->log->error($message);
1802 if (!isset($a_tree_id))
1804 $message =
"No tree_id given!";
1805 $this->log->error($message);
1809 if ($a_node_id <= 0)
1811 $a_node_id = $a_tree_id;
1814 $query =
'INSERT INTO '.$this->table_tree.
' ('.
1815 $this->tree_pk.
', child,parent,lft,rgt,depth) '.
1817 '(%s,%s,%s,%s,%s,%s)';
1818 $res = $ilDB->manipulateF(
$query,
array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
array(
1848 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1850 'WHERE ' . $this->table_obj_data .
'.type = ' . $this->
ilDB->
quote(
$a_type,
'text').
1851 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = ' . $this->
ilDB->
quote($this->tree_id,
'integer');
1855 while(
$row = $ilDB->fetchAssoc(
$res))
1887 $query =
'DELETE FROM '.$this->table_tree.
1888 ' WHERE '.$this->tree_pk.
' = %s ';
1914 $subnodes =
array();
1917 $subnodes[] =
$row[
'child'];
1920 if(!count($subnodes))
1928 include_once
'./Services/Object/classes/class.ilObject.php';
1950 return $this->
moveToTrash($a_node_id, $a_set_deleted);
1959 return $this->
isSaved($a_node_id);
1972 if ($this->
isCacheUsed() && isset($this->is_saved_cache[$a_node_id]))
1975 return $this->is_saved_cache[$a_node_id];
1978 $query =
'SELECT '.$this->tree_pk.
' FROM '.$this->table_tree.
' '.
1979 'WHERE child = %s ';
1983 if (
$row[$this->tree_pk] < 0)
1987 $this->is_saved_cache[$a_node_id] =
true;
1995 $this->is_saved_cache[$a_node_id] =
false;
2011 if (!is_array($a_node_ids) || !$this->
isCacheUsed())
2016 $query =
'SELECT '.$this->tree_pk.
', child FROM '.$this->table_tree.
' '.
2017 'WHERE '.$ilDB->in(
"child", $a_node_ids,
false,
"integer");
2020 while (
$row = $ilDB->fetchAssoc(
$res))
2022 if (
$row[$this->tree_pk] < 0)
2026 $this->is_saved_cache[
$row[
"child"]] =
true;
2033 $this->is_saved_cache[
$row[
"child"]] =
false;
2051 if (!isset($a_parent_id))
2053 $message =
"No node_id given!";
2054 $this->log->error($message);
2058 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2060 'WHERE '.$this->table_tree.
'.'.$this->tree_pk.
' < %s '.
2061 'AND '.$this->table_tree.
'.parent = %s';
2066 while(
$row = $ilDB->fetchAssoc(
$res))
2071 return $saved ? $saved :
array();
2084 $query =
'SELECT '.$this->table_obj_data.
'.obj_id FROM '.$this->table_tree.
' '.
2086 'WHERE '.$this->table_tree.
'.'.$this->tree_pk.
' < '.$ilDB->quote(0,
'integer').
' '.
2087 'AND '.$ilDB->in($this->table_obj_data.
'.obj_id', $a_obj_ids,
'',
'integer');
2089 while(
$row = $ilDB->fetchAssoc(
$res))
2091 $saved[] =
$row[
'obj_id'];
2094 return $saved ? $saved :
array();
2108 if (!isset($a_node_id))
2110 $message =
"No node_id given!";
2111 $this->log->error($message);
2115 $query =
'SELECT parent FROM '.$this->table_tree.
' '.
2116 'WHERE child = %s '.
2117 'AND '.$this->tree_pk.
' = %s ';
2123 return $row->parent;
2137 if (!isset($a_node_id))
2139 $message =
"No node_id given!";
2140 $this->log->error($message);
2144 $query =
'SELECT lft FROM '.$this->table_tree.
' '.
2145 'WHERE child = %s '.
2146 'AND '.$this->tree_pk.
' = %s ';
2165 if (!isset($a_node))
2167 $message =
"No node_id given!";
2168 $this->log->error($message);
2174 $query =
'SELECT count(*) cnt FROM '.$this->table_tree.
' '.
2179 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2189 $query =
'SELECT count(*) cnt FROM '.$this->table_tree.
' '.
2193 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2215 $query =
'SELECT child FROM '.$this->table_tree.
' '.
2216 'WHERE parent = %s '.
2217 'AND '.$this->tree_pk.
' = %s ';
2222 $this->root_id =
$row->child;
2237 $this->root_id = $a_root_id;
2257 $this->tree_id = $a_tree_id;
2272 if (!isset($a_node_id))
2274 $message =
"No node_id given!";
2275 $this->log->error($message);
2280 $query =
'SELECT lft FROM '.$this->table_tree.
' '.
2281 'WHERE '.$this->table_tree.
'.child = %s '.
2282 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2286 $curr_node = $ilDB->fetchAssoc(
$res);
2290 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2293 'AND '.$this->table_obj_data.
'.type = %s '.
2294 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2304 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2307 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2315 if (
$res->numRows() < 1)
2338 if (!isset($a_node_id))
2340 $message =
"No node_id given!";
2341 $this->log->error($message);
2346 $query =
'SELECT lft FROM '.$this->table_tree.
' '.
2347 'WHERE '.$this->table_tree.
'.child = %s '.
2348 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2353 $curr_node = $ilDB->fetchAssoc(
$res);
2357 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2360 'AND '.$this->table_obj_data.
'.type = %s '.
2361 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2362 'ORDER BY lft DESC';
2371 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2374 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2375 'ORDER BY lft DESC';
2382 if (
$res->numRows() < 1)
2415 $ilAtomQuery = $ilDB->buildAtomQuery();
2416 $ilAtomQuery->addTableLock( $this->table_tree );
2418 $ilAtomQuery->addQueryCallable($renumber_callable);
2419 $ilAtomQuery->run();
2423 $renumber_callable($ilDB);
2442 $query =
'UPDATE '.$this->table_tree.
' SET lft = %s WHERE child = %s AND tree = %s';
2452 foreach ($childs as $child)
2459 if (count($childs) > 0)
2461 $i += $this->gap * 2;
2465 $query =
'UPDATE '.$this->table_tree.
' SET rgt = %s WHERE child = %s AND tree = %s';
2487 $cache_key = $a_ref_id.
'.'.
$a_type.
'.'.((int)$a_exclude_source_check);
2491 array_key_exists($cache_key, $this->parent_type_cache))
2493 return $this->parent_type_cache[$cache_key];
2497 $do_cache = ($this->
__isMainTree() && count($this->parent_type_cache) < 1000);
2504 $this->parent_type_cache[$cache_key] =
false;
2512 if($a_exclude_source_check)
2517 foreach(
$path as $node)
2524 $this->parent_type_cache[$cache_key] = $node[
"child"];
2526 return $node[
"child"];
2532 $this->parent_type_cache[$cache_key] =
false;
2551 if($a_db_table ===
'tree')
2553 if($a_tree == 1
and $a_child == ROOT_FOLDER_ID)
2555 $message = sprintf(
'Tried to delete root node! $a_tree: %s $a_child: %s',
2563 $query =
'DELETE FROM '.$a_db_table.
' '.
2580 return $this->table_tree ===
'tree';
2600 $this->log->debug(
$query);
2604 while(
$row = $ilDB->fetchObject(
$res))
2606 $lft_childs[
$row->child] =
$row->parent;
2613 $message =
'Duplicate entries for "child" in maintree! $a_node_id: '.$a_node[
'child'];
2615 $this->log->error($message);
2620 $parent_childs =
array();
2641 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2642 'WHERE child = %s '.
2649 while(
$row = $ilDB->fetchObject(
$res))
2651 $parent_childs[$a_node_id] =
$row->parent;
2657 $message =
'Multiple entries in maintree! $a_node_id: '. $a_node_id;
2659 $this->log->error($message);
2664 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2665 'WHERE parent = %s ';
2668 while(
$row = $ilDB->fetchObject(
$res))
2687 ksort($parent_childs);
2689 $this->log->debug(
'left childs '. print_r($lft_childs,
true));
2690 $this->log->debug(
'parent childs '. print_r($parent_childs,
true));
2692 if(count($lft_childs) != count($parent_childs))
2694 $message =
'(COUNT) Tree is corrupted! Left/Right subtree does not comply with parent relation';
2695 $this->log->error($message);
2700 foreach($lft_childs as $key => $value)
2702 if($parent_childs[$key] != $value)
2704 $message =
'(COMPARE) Tree is corrupted! Left/Right subtree does not comply with parent relation';
2705 $this->log->error($message);
2708 if($key == ROOT_FOLDER_ID)
2710 $message =
'(ROOT_FOLDER) Tree is corrupted! Tried to delete root folder';
2711 $this->log->error($message);
2727 public function moveTree($a_source_id, $a_target_id, $a_location = self::POS_LAST_NODE)
2729 $old_parent_id = $this->
getParentId($a_source_id);
2732 $GLOBALS[
'ilAppEventHandler']->raise(
2736 'tree' => $this->table_tree,
2737 'source_id' => $a_source_id,
2738 'target_id' => $a_target_id,
2739 'old_parent_id' => $old_parent_id
2774 $a_force_join_reference,
2802 if(count($a_fields))
2804 $fields = implode(
',',$a_fields);
2807 $query =
"SELECT ".$fields.
2808 " FROM ".$this->getTreeTable().
2809 " ".$this->buildJoin().
2810 " WHERE ".$this->getTableReference().
".".$this->ref_pk.
" IN (".
$query.
")".
2811 " AND ".$ilDB->in($this->
getObjectDataTable().
".".$this->obj_pk, $a_obj_ids,
"",
"integer");
2812 $set = $ilDB->query(
$query);
2813 while(
$row = $ilDB->fetchAssoc($set))
2823 global
$ilDB, $ilAppEventHandler;
2825 $query =
'DELETE FROM tree where '.
2826 'child = '.$ilDB->quote($a_node_id,
'integer').
' '.
2827 'AND tree = '.$ilDB->quote($a_tree_id,
'integer');
2828 $ilDB->manipulate(
$query);
2830 $ilAppEventHandler->raise(
2833 array(
'tree' => $this->table_tree,
2834 'node_id' => $a_node_id,
2835 'tree_id' => $a_tree_id
2849 $query =
'SELECT DISTINCT(o.type) '.$ilDB->quoteIdentifier(
'type').
' FROM tree t JOIN object_reference r ON child = r.ref_id '.
2850 'JOIN object_data o on r.obj_id = o.obj_id '.
2851 'WHERE tree < '.$ilDB->quote(0,
'integer').
' '.
2852 'AND child = -tree '.
2856 $types_deleted =
array();
2859 $types_deleted[] =
$row->type;
2861 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
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.
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...
static strToLower($a_string)
getTreePk()
Get tree primary key.
__validateSubtrees(&$lft_childs, $parent_childs)
Base class for nested set path based trees.
static toNFC( $string)
Convert a UTF-8 string to normal form C, canonical composition.
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...
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.
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