4define(
"IL_LAST_NODE", -2);
5define(
"IL_FIRST_NODE", -1);
7include_once
'./Services/Tree/exceptions/class.ilInvalidTreeStructureException.php';
147 function ilTree($a_tree_id, $a_root_id = 0)
164 $this->lang_code =
"en";
166 if (!isset($a_tree_id) or (func_num_args() == 0) )
168 $this->ilErr->raiseError(get_class($this).
"::Constructor(): No tree_id given!",$this->ilErr->WARNING);
171 if (func_num_args() > 2)
173 $this->ilErr->raiseError(get_class($this).
"::Constructor(): Wrong parameter count!",$this->ilErr->WARNING);
180 if (empty($a_root_id))
182 $a_root_id = ROOT_FOLDER_ID;
185 $this->tree_id = $a_tree_id;
186 $this->root_id = $a_root_id;
187 $this->table_tree =
'tree';
188 $this->table_obj_data =
'object_data';
189 $this->table_obj_reference =
'object_reference';
190 $this->ref_pk =
'ref_id';
191 $this->obj_pk =
'obj_id';
192 $this->tree_pk =
'tree';
194 $this->use_cache =
true;
197 $this->translation_cache = array();
198 $this->parent_type_cache = array();
216 if(!is_object(
$GLOBALS[
'ilSetting']) or
$GLOBALS[
'ilSetting']->getModule() !=
'common')
218 include_once
'./Services/Administration/classes/class.ilSetting.php';
228 if($setting->get(
'main_tree_impl',
'ns') ==
'ns')
230 #$GLOBALS['ilLog']->write(__METHOD__.': Using nested set.');
231 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
236 #$GLOBALS['ilLog']->write(__METHOD__.': Using materialized path.');
237 include_once
'./Services/Tree/classes/class.ilMaterializedPathTree.php';
243 #$GLOBALS['ilLog']->write(__METHOD__.': Using netsted set for non main tree.');
244 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
263 $this->use_cache = $a_use;
304 $this->lang_code =
"en";
308 $this->lang_code =
$ilUser->getCurrentLanguage();
360 $this->in_tree_cache = array();
378 function setTableNames($a_table_tree,$a_table_obj_data,$a_table_obj_reference =
"")
380 if (!isset($a_table_tree) or !isset($a_table_obj_data))
382 $this->ilErr->raiseError(get_class($this).
"::setTableNames(): Missing parameter! ".
383 "tree table: ".$a_table_tree.
" object data table: ".$a_table_obj_data,$this->ilErr->WARNING);
386 $this->table_tree = $a_table_tree;
387 $this->table_obj_data = $a_table_obj_data;
388 $this->table_obj_reference = $a_table_obj_reference;
403 if (!isset($a_column_name))
405 $this->ilErr->raiseError(get_class($this).
"::setReferenceTablePK(): No column name given!",$this->ilErr->WARNING);
408 $this->ref_pk = $a_column_name;
420 if (!isset($a_column_name))
422 $this->ilErr->raiseError(get_class($this).
"::setObjectTablePK(): No column name given!",$this->ilErr->WARNING);
425 $this->obj_pk = $a_column_name;
437 if (!isset($a_column_name))
439 $this->ilErr->raiseError(get_class($this).
"::setTreeTablePK(): No column name given!",$this->ilErr->WARNING);
442 $this->tree_pk = $a_column_name;
453 if ($this->table_obj_reference)
456 return "JOIN ".$this->table_obj_reference.
" ON ".$this->table_tree.
".child=".$this->table_obj_reference.
".".$this->ref_pk.
" ".
457 "JOIN ".$this->table_obj_data.
" ON ".$this->table_obj_reference.
".".$this->obj_pk.
"=".$this->table_obj_data.
".".$this->obj_pk.
" ";
462 return "JOIN ".$this->table_obj_data.
" ON ".$this->table_tree.
".child=".$this->table_obj_data.
".".$this->obj_pk.
" ";
500 $query =
'SELECT * FROM tree '.
501 'WHERE parent = '.$ilDB->quote($a_node,
'integer').
' '.
502 'AND tree > '.$ilDB->quote(0,
'integer');
508 $childs[] =
$row->child;
521 function getChilds($a_node_id, $a_order =
"", $a_direction =
"ASC")
525 if (!isset($a_node_id))
527 $message = get_class($this).
"::getChilds(): No node_id given!";
528 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
541 if (!empty($a_order))
543 $order_clause =
"ORDER BY ".$a_order.
" ".$a_direction;
547 $order_clause =
"ORDER BY ".$this->table_tree.
".lft";
551 $query = sprintf(
'SELECT * FROM '.$this->table_tree.
' '.
553 "WHERE parent = %s " .
554 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
556 $ilDB->quote($a_node_id,
'integer'),
557 $ilDB->quote($this->tree_id,
'integer'));
561 if(!$count =
$res->numRows())
571 $obj_ids[] = $r[
"obj_id"];
576 is_object(
$ilUser) && $this->lang_code ==
$ilUser->getLanguage() && !$this->oc_preloaded[$a_node_id])
579 $ilObjDataCache->preloadObjectCache($obj_ids, $this->lang_code);
581 $this->oc_preloaded[$a_node_id] =
true;
584 foreach ($rows as
$row)
591 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child'].' = true');
592 $this->in_tree_cache[
$row[
'child']] =
$row[
'tree'] == 1;
595 $childs[$count - 1][
"last"] =
true;
610 $childs = $this->
getChilds($a_node,$a_order,$a_direction);
612 foreach($childs as $child)
614 if(!in_array($child[
"type"],$a_filter))
616 $filtered[] = $child;
619 return $filtered ? $filtered : array();
634 if (!isset($a_node_id) or !isset($a_type))
636 $message = get_class($this).
"::getChildsByType(): Missing parameter! node_id:".$a_node_id.
" type:".$a_type;
637 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
640 if ($a_type==
'rolf' && $this->table_obj_reference) {
644 $ilDB->setLimit(1,0);
645 $query = sprintf(
"SELECT * FROM ".$this->table_tree.
" ".
647 "WHERE parent = %s ".
648 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
649 "AND ".$this->table_obj_data.
".type = %s ",
650 $ilDB->quote($a_node_id,
'integer'),
651 $ilDB->quote($this->tree_id,
'integer'),
652 $ilDB->quote($a_type,
'text'));
654 $query = sprintf(
"SELECT * FROM ".$this->table_tree.
" ".
656 "WHERE parent = %s ".
657 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
658 "AND ".$this->table_obj_data.
".type = %s ".
659 "ORDER BY ".$this->table_tree.
".lft",
660 $ilDB->quote($a_node_id,
'integer'),
661 $ilDB->quote($this->tree_id,
'integer'),
662 $ilDB->quote($a_type,
'text'));
673 return $childs ? $childs : array();
688 if (!isset($a_node_id) or !$a_types)
690 $message = get_class($this).
"::getChildsByType(): Missing parameter! node_id:".$a_node_id.
" type:".$a_types;
691 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
697 $filter =
'AND '.$this->table_obj_data.
'.type IN('.implode(
',',
ilUtil::quoteArray($a_types)).
') ';
701 if (!empty($a_order))
703 $order_clause =
"ORDER BY ".$a_order.
" ".$a_direction;
707 $order_clause =
"ORDER BY ".$this->table_tree.
".lft";
710 $query =
'SELECT * FROM '.$this->table_tree.
' '.
712 'WHERE parent = '.$ilDB->quote($a_node_id,
'integer').
' '.
713 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = '.
$ilDB->quote($this->tree_id,
'integer').
' '.
723 return $childs ? $childs : array();
741 if($a_node_id <= 1 or $a_parent_id <= 0)
744 $message = sprintf(
'%s::insertNode(): Invalid parameters! $a_node_id: %s $a_parent_id: %s',
748 $this->log->write($message,$this->log->FATAL);
749 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
754 if (!isset($a_node_id) or !isset($a_parent_id))
757 $this->ilErr->raiseError(get_class($this).
"::insertNode(): Missing parameter! ".
758 "node_id: ".$a_node_id.
" parent_id: ".$a_parent_id,$this->ilErr->WARNING);
762 $this->ilErr->raiseError(get_class($this).
"::insertNode(): Node ".$a_node_id.
" already in tree ".
763 $this->table_tree.
"!",$this->ilErr->WARNING);
768 $this->in_tree_cache[$a_node_id] =
true;
771 if ($a_reset_deletion_date)
797 if($depth and $subnode[
'depth'] > $depth)
801 if(!$first and in_array($subnode[
'type'],$a_filter))
803 $depth = $subnode[
'depth'];
809 $filtered[] = $subnode;
811 return $filtered ? $filtered : array();
834 function getSubTree($a_node,$a_with_data =
true, $a_type =
"")
838 if (!is_array($a_node))
841 throw new InvalidArgumentException(__METHOD__.
': wrong datatype for node data given');
867 $subtree[] =
$row[
'child'];
870 if($this->
__isMainTree() || $this->table_tree ==
"lm_tree")
872 $this->in_tree_cache[
$row[
'child']] =
true;
875 return $subtree ? $subtree : array();
888 $a_filter = $a_filter ? $a_filter : array();
890 foreach($this->getSubtree($this->
getNodeData($a_node)) as $node)
892 if(in_array($node[
"type"],$a_filter))
896 $types[
"$node[type]"] = $node[
"type"];
898 return $types ? $types : array();
911 $GLOBALS[
'ilLog']->write(__METHOD__.
': Delete tree with node '. $a_node);
913 if (!is_array($a_node))
916 throw new InvalidArgumentException(__METHOD__.
': Wrong datatype for node data!');
919 $GLOBALS[
'ilLog']->write(__METHOD__.
': '. $this->tree_pk);
950 $pathIds =& $this->
getPathId($a_endnode_id, $a_startnode_id);
956 if (count($pathIds) == 0)
961 $inClause =
'child IN (';
962 for ($i=0; $i < count($pathIds); $i++)
964 if ($i > 0) $inClause .=
',';
965 $inClause .=
$ilDB->quote($pathIds[$i],
'integer');
970 'FROM '.$this->table_tree.
' '.
972 'WHERE '.$inClause.
' '.
973 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = '.$this->
ilDB->
quote($this->tree_id,
'integer').
' '.
975 $r =
$ilDB->query($q);
985 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child']);
986 $this->in_tree_cache[
$row[
'child']] =
$row[
'tree'] == 1;
1008 $res = $ilDB->query(
'SELECT t.depth, t.parent, t.child '.
1009 'FROM '.$this->table_tree.
' t '.
1010 'WHERE '.$ilDB->in(
"child", $a_node_ids,
false,
"integer").
1011 'AND '.$this->tree_pk.
' = '.
$ilDB->quote($this->tree_id,
"integer"));
1014 $this->depth_cache[
$row[
"child"]] =
$row[
"depth"];
1015 $this->parent_cache[
$row[
"child"]] =
$row[
"parent"];
1028 public function getPathId($a_endnode_id, $a_startnode_id = 0)
1033 throw new InvalidArgumentException(__METHOD__.
': No endnode given!');
1037 if ($this->
isCacheUsed() && isset($this->path_id_cache[$a_endnode_id][$a_startnode_id]))
1040 return $this->path_id_cache[$a_endnode_id][$a_startnode_id];
1048 $this->path_id_cache[$a_endnode_id][$a_startnode_id] = $pathIds;
1077 if ($titlePath ==
null || count($titlePath) == 0)
1079 if ($a_startnode_id == 0)
1090 if ($a_startnode_id !=
null && $a_startnode_id != 0)
1094 $parent = $a_startnode_id;
1099 $nodePath = array();
1107 require_once(
'include/Unicode/UtfNormal.php');
1108 include_once
'./Services/Utilities/classes/class.ilStr.php';
1109 $inClause =
'd.title IN (';
1110 for ($i=0; $i < count($titlePath); $i++)
1113 if ($i > 0) $inClause .=
',';
1114 $inClause .=
$ilDB->quote($titlePath[$i],
'text');
1119 if ($this->table_obj_reference)
1121 $joinClause =
'JOIN '.$this->table_obj_reference.
' r ON t.child = r.'.$this->ref_pk.
' '.
1122 'JOIN '.$this->table_obj_data.
' d ON r.'.$this->obj_pk.
' = d.'.
$this->obj_pk;
1126 $joinClause =
'JOIN '.$this->table_obj_data.
' d ON t.child = d.'.
$this->obj_pk;
1133 $q =
'SELECT t.depth, t.parent, t.child, d.'.$this->obj_pk.
' obj_id, d.type, d.title '.
1134 'FROM '.$this->table_tree.
' t '.
1136 'WHERE '.$inClause.
' '.
1137 'AND t.depth <= '.(count($titlePath)+count($nodePath)).
' '.
1139 'ORDER BY t.depth, t.child ASC';
1140 $r =
$ilDB->query($q);
1151 for ($i = 0; $i < count($titlePath); $i++) {
1152 $pathElementFound =
false;
1153 foreach ($rows as
$row) {
1154 if (
$row[
'parent'] == $parent &&
1160 $parent =
$row[
'child'];
1161 $pathElementFound =
true;
1166 if (! $pathElementFound)
1198 $pathIds = $this->
getPathId($a_endnode_id, $a_startnode_id);
1201 if (count($pathIds) == 0)
1209 for ($i = 0; $i < count($pathIds); $i++)
1211 $types[] =
'integer';
1212 $data[] = $pathIds[$i];
1215 $query =
'SELECT t.depth,t.parent,t.child,d.obj_id,d.type,d.title '.
1216 'FROM '.$this->table_tree.
' t '.
1217 'JOIN '.$this->table_obj_reference.
' r ON r.ref_id = t.child '.
1218 'JOIN '.$this->table_obj_data.
' d ON d.obj_id = r.obj_id '.
1219 'WHERE '.$ilDB->in(
't.child',
$data,
false,
'integer').
' '.
1220 'ORDER BY t.depth ';
1224 $titlePath = array();
1227 $titlePath[] =
$row;
1243 $types = array(
'integer');
1244 $query =
'SELECT lft,rgt FROM '.$this->table_tree.
' '.
1245 'WHERE '.$this->tree_pk.
' = %s ';
1254 $all = array_merge($lft,$rgt);
1255 $uni = array_unique($all);
1257 if (count($all) != count($uni))
1259 $message = sprintf(
'%s::checkTree(): Tree is corrupted!',
1262 $this->log->write($message,$this->log->FATAL);
1263 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
1276 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1277 'WHERE '.$this->tree_pk.
' = %s '.
1279 $r1 =
$ilDB->queryF(
$query,array(
'integer'),array($this->tree_id));
1284 if ((
$row[
"child"] == 0) && $a_no_zero_child)
1286 $this->ilErr->raiseError(get_class($this).
"::checkTreeChilds(): Tree contains child with ID 0!",$this->ilErr->WARNING);
1289 if ($this->table_obj_reference)
1292 $query =
'SELECT * FROM '.$this->table_obj_reference.
' WHERE '.$this->ref_pk.
' = %s ';
1296 if ($r2->numRows() == 0)
1298 $this->ilErr->raiseError(get_class($this).
"::checkTree(): No Object-to-Reference entry found for ID ".
1299 $row[
"child"].
"!",$this->ilErr->WARNING);
1301 if ($r2->numRows() > 1)
1303 $this->ilErr->raiseError(get_class($this).
"::checkTree(): More Object-to-Reference entries found for ID ".
1304 $row[
"child"].
"!",$this->ilErr->WARNING);
1308 $obj_ref =
$ilDB->fetchAssoc($r2);
1310 $query =
'SELECT * FROM '.$this->table_obj_data.
' WHERE '.$this->obj_pk.
' = %s';
1311 $r3 =
$ilDB->queryF(
$query,array(
'integer'),array($obj_ref[$this->obj_pk]));
1312 if ($r3->numRows() == 0)
1314 $this->ilErr->raiseError(get_class($this).
"::checkTree(): No child found for ID ".
1315 $obj_ref[$this->obj_pk].
"!",$this->ilErr->WARNING);
1317 if ($r3->numRows() > 1)
1319 $this->ilErr->raiseError(get_class($this).
"::checkTree(): More childs found for ID ".
1320 $obj_ref[$this->obj_pk].
"!",$this->ilErr->WARNING);
1327 $query =
'SELECT * FROM '.$this->table_obj_data.
' WHERE '.$this->obj_pk.
' = %s';
1330 if ($r2->numRows() == 0)
1332 $this->ilErr->raiseError(get_class($this).
"::checkTree(): No child found for ID ".
1333 $row[
"child"].
"!",$this->ilErr->WARNING);
1335 if ($r2->numRows() > 1)
1337 $this->ilErr->raiseError(get_class($this).
"::checkTree(): More childs found for ID ".
1338 $row[
"child"].
"!",$this->ilErr->WARNING);
1355 $query =
'SELECT MAX(depth) depth FROM '.$this->table_tree;
1359 return $row[
'depth'];
1374 $query =
'SELECT depth FROM '.$this->table_tree.
' '.
1375 'WHERE child = %s '.
1376 'AND '.$this->tree_pk.
' = %s ';
1377 $res =
$ilDB->queryF(
$query,array(
'integer',
'integer'),array($a_node_id,$this->tree_id));
1402 throw new InvalidArgumentException(
'Missing or empty parameter $a_node_id: '. $a_node_id);
1405 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1406 'WHERE child = '.$ilDB->quote($a_node_id,
'integer');
1430 if (!isset($a_node_id))
1433 $this->ilErr->raiseError(get_class($this).
"::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
1439 $message = sprintf(
'%s::getNodeData(): No valid parameter given! $a_node_id: %s',
1443 $this->log->write($message,$this->log->FATAL);
1444 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
1449 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1451 'WHERE '.$this->table_tree.
'.child = %s '.
1452 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
1455 $a_tree_pk ===
null ? $this->tree_id : $a_tree_pk));
1476 $data[
"desc"] = $a_row[
"description"];
1481 if (is_object($objDefinition))
1483 $translation_type = $objDefinition->getTranslationType(
$data[
"type"]);
1487 if ($translation_type ==
"sys")
1490 if (
$data[
"type"] ==
"rolf" and
$data[
"obj_id"] != ROLE_FOLDER_ID)
1492 $data[
"description"] =
$lng->txt(
"obj_".
$data[
"type"].
"_local_desc").$data[
"title"].$data[
"desc"];
1493 $data[
"desc"] =
$lng->txt(
"obj_".
$data[
"type"].
"_local_desc").$data[
"title"].$data[
"desc"];
1504 elseif ($translation_type ==
"db")
1509 array_key_exists(
$data[
"obj_id"].
'.'.$lang_code, $this->translation_cache)) {
1511 $key =
$data[
"obj_id"].
'.'.$lang_code;
1512 $data[
"title"] = $this->translation_cache[$key][
'title'];
1513 $data[
"description"] = $this->translation_cache[$key][
'description'];
1514 $data[
"desc"] = $this->translation_cache[$key][
'desc'];
1520 $query =
'SELECT title,description FROM object_translation '.
1521 'WHERE obj_id = %s '.
1522 'AND lang_code = %s '.
1523 'AND NOT lang_default = %s';
1540 if ($this->
isCacheUsed() && count($this->translation_cache) < 1000)
1542 $key =
$data[
"obj_id"].
'.'.$lang_code;
1543 $this->translation_cache[$key] = array();
1544 $this->translation_cache[$key][
'title'] =
$data[
"title"] ;
1545 $this->translation_cache[$key][
'description'] =
$data[
"description"];
1546 $this->translation_cache[$key][
'desc'] =
$data[
"desc"];
1552 if(
$data[
'type'] ==
'crsr' or
$data[
'type'] ==
'catr')
1554 include_once(
'./Services/ContainerReference/classes/class.ilContainerReference.php');
1568 global $ilObjDataCache;
1570 if ($this->
isCacheUsed() && is_array($a_obj_ids) && is_object($ilObjDataCache))
1572 foreach ($a_obj_ids as $id)
1574 $this->translation_cache[$id.
'.'][
'title'] = $ilObjDataCache->lookupTitle($id);
1575 $this->translation_cache[$id.
'.'][
'description'] = $ilObjDataCache->lookupDescription($id);;
1576 $this->translation_cache[$id.
'.'][
'desc'] =
1577 $this->translation_cache[$id.
'.'][
'description'];
1594 if (!isset($a_node_id))
1597 #$this->ilErr->raiseError(get_class($this)."::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
1600 if ($this->
isCacheUsed() && isset($this->in_tree_cache[$a_node_id]))
1602 #$GLOBALS['ilLog']->write(__METHOD__.': Using in tree cache '.$a_node_id);
1604 return $this->in_tree_cache[$a_node_id];
1607 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1608 'WHERE '.$this->table_tree.
'.child = %s '.
1609 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s';
1615 if (
$res->numRows() > 0)
1619 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = true');
1620 $this->in_tree_cache[$a_node_id] =
true;
1628 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$a_node_id.' = false');
1629 $this->in_tree_cache[$a_node_id] =
false;
1647 if (!isset($a_node_id))
1650 throw new InvalidArgumentException(__METHOD__.
': No node_id given!');
1653 if ($this->table_obj_reference)
1656 $innerjoin =
"JOIN ".$this->table_obj_reference.
" ON v.child=".$this->table_obj_reference.
".".$this->ref_pk.
" ".
1657 "JOIN ".$this->table_obj_data.
" ON ".$this->table_obj_reference.
".".$this->obj_pk.
"=".$this->table_obj_data.
".".$this->obj_pk.
" ";
1662 $innerjoin =
"JOIN ".$this->table_obj_data.
" ON v.child=".$this->table_obj_data.
".".$this->obj_pk.
" ";
1665 $query =
'SELECT * FROM '.$this->table_tree.
' s, '.$this->table_tree.
' v '.
1667 'WHERE s.child = %s '.
1668 'AND s.parent = v.child '.
1669 'AND s.'.$this->tree_pk.
' = %s '.
1670 'AND v.'.$this->tree_pk.
' = %s';
1671 $res =
$ilDB->queryF(
$query,array(
'integer',
'integer',
'integer'),array(
1706 $message = sprintf(
'%s::addTree(): Operation not allowed on main tree! $a_tree_if: %s $a_node_id: %s',
1710 $this->log->write($message,$this->log->FATAL);
1711 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
1714 if (!isset($a_tree_id))
1716 $this->ilErr->raiseError(get_class($this).
"::addTree(): No tree_id given! ",$this->ilErr->WARNING);
1719 if ($a_node_id <= 0)
1721 $a_node_id = $a_tree_id;
1724 $query =
'INSERT INTO '.$this->table_tree.
' ('.
1725 $this->tree_pk.
', child,parent,lft,rgt,depth) '.
1727 '(%s,%s,%s,%s,%s,%s)';
1728 $res =
$ilDB->manipulateF(
$query,array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),array(
1751 if(!isset($a_type) or (!is_string($a_type)))
1754 throw new InvalidArgumentException(
'Type not given or wrong datatype');
1757 $query =
'SELECT * FROM ' . $this->table_tree .
' ' .
1759 'WHERE ' . $this->table_obj_data .
'.type = ' . $this->
ilDB->
quote($a_type,
'text').
1760 'AND ' . $this->table_tree .
'.' . $this->tree_pk .
' = ' . $this->
ilDB->
quote($this->tree_id,
'integer');
1787 throw new InvalidArgumentException(
'Operation not allowed on main tree');
1792 throw new InvalidArgumentException(
'Missing parameter tree id');
1795 $query =
'DELETE FROM '.$this->table_tree.
1796 ' WHERE '.$this->tree_pk.
' = %s ';
1797 $ilDB->manipulateF(
$query,array(
'integer'),array($a_tree_id));
1809 return $this->
saveSubTree($a_node_id, $a_set_deleted);
1829 throw new InvalidArgumentException(
'No valid parameter given! $a_node_id: '.$a_node_id);
1844 $subnodes = array();
1847 $subnodes[] =
$row[
'child'];
1850 if(!count($subnodes))
1856 $ilDB->unlockTables();
1863 include_once
'./Services/Object/classes/class.ilObject.php';
1872 $ilDB->unlockTables();
1885 return $this->
isSaved($a_node_id);
1898 if ($this->
isCacheUsed() && isset($this->is_saved_cache[$a_node_id]))
1901 return $this->is_saved_cache[$a_node_id];
1904 $query =
'SELECT '.$this->tree_pk.
' FROM '.$this->table_tree.
' '.
1905 'WHERE child = %s ';
1909 if (
$row[$this->tree_pk] < 0)
1913 $this->is_saved_cache[$a_node_id] =
true;
1921 $this->is_saved_cache[$a_node_id] =
false;
1937 if (!is_array($a_node_ids) || !$this->
isCacheUsed())
1942 $query =
'SELECT '.$this->tree_pk.
', child FROM '.$this->table_tree.
' '.
1943 'WHERE '.$ilDB->in(
"child", $a_node_ids,
false,
"integer");
1948 if (
$row[$this->tree_pk] < 0)
1952 $this->is_saved_cache[
$row[
"child"]] =
true;
1959 $this->is_saved_cache[
$row[
"child"]] =
false;
1976 if (!isset($a_parent_id))
1978 $this->ilErr->raiseError(get_class($this).
"::getSavedNodeData(): No node_id given!",$this->ilErr->WARNING);
1981 $query =
'SELECT * FROM '.$this->table_tree.
' '.
1983 'WHERE '.$this->table_tree.
'.'.$this->tree_pk.
' < %s '.
1984 'AND '.$this->table_tree.
'.parent = %s';
1994 return $saved ? $saved : array();
2007 $query =
'SELECT '.$this->table_obj_data.
'.obj_id FROM '.$this->table_tree.
' '.
2009 'WHERE '.$this->table_tree.
'.'.$this->tree_pk.
' < '.
$ilDB->quote(0,
'integer').
' '.
2010 'AND '.$ilDB->in($this->table_obj_data.
'.obj_id', $a_obj_ids,
'',
'integer');
2014 $saved[] =
$row[
'obj_id'];
2017 return $saved ? $saved : array();
2030 if (!isset($a_node_id))
2032 $this->ilErr->raiseError(get_class($this).
"::getParentId(): No node_id given! ",$this->ilErr->WARNING);
2035 $query =
'SELECT parent FROM '.$this->table_tree.
' '.
2036 'WHERE child = %s '.
2037 'AND '.$this->tree_pk.
' = %s ';
2043 return $row->parent;
2056 if (!isset($a_node_id))
2058 $this->ilErr->raiseError(get_class($this).
"::getLeftValued(): No node_id given! ",$this->ilErr->WARNING);
2061 $query =
'SELECT lft FROM '.$this->table_tree.
' '.
2062 'WHERE child = %s '.
2063 'AND '.$this->tree_pk.
' = %s ';
2081 if (!isset($a_node))
2083 $this->ilErr->raiseError(get_class($this).
"::getChildSequenceNumber(): No node_id given! ",$this->ilErr->WARNING);
2088 $query =
'SELECT count(*) cnt FROM '.$this->table_tree.
' '.
2093 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2095 $res =
$ilDB->queryF(
$query,array(
'integer',
'text',
'integer',
'integer'),array(
2103 $query =
'SELECT count(*) cnt FROM '.$this->table_tree.
' '.
2107 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2109 $res =
$ilDB->queryF(
$query,array(
'integer',
'integer',
'integer'),array(
2129 $query =
'SELECT child FROM '.$this->table_tree.
' '.
2130 'WHERE parent = %s '.
2131 'AND '.$this->tree_pk.
' = %s ';
2136 $this->root_id =
$row->child;
2151 $this->root_id = $a_root_id;
2171 $this->tree_id = $a_tree_id;
2185 if (!isset($a_node_id))
2187 $this->ilErr->raiseError(get_class($this).
"::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
2191 $query =
'SELECT lft FROM '.$this->table_tree.
' '.
2192 'WHERE '.$this->table_tree.
'.child = %s '.
2193 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2201 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2204 'AND '.$this->table_obj_data.
'.type = %s '.
2205 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2215 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2218 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2226 if (
$res->numRows() < 1)
2248 if (!isset($a_node_id))
2250 $this->ilErr->raiseError(get_class($this).
"::getNodeData(): No node_id given! ",$this->ilErr->WARNING);
2254 $query =
'SELECT lft FROM '.$this->table_tree.
' '.
2255 'WHERE '.$this->table_tree.
'.child = %s '.
2256 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s ';
2265 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2268 'AND '.$this->table_obj_data.
'.type = %s '.
2269 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2270 'ORDER BY lft DESC';
2279 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2282 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2283 'ORDER BY lft DESC';
2290 if (
$res->numRows() < 1)
2328 2 => array(
'name' => $this->table_obj_reference,
'type' =>
ilDB::LOCK_WRITE),
2330 4 => array(
'name' =>
'object_data',
'type' =>
ilDB::LOCK_WRITE,
'alias' =>
'od'),
2331 5 => array(
'name' =>
'container_reference',
'type' =>
ilDB::LOCK_WRITE,
'alias' =>
'cr')
2337 $ilDB->unlockTables();
2357 $query =
'UPDATE '.$this->table_tree.
' SET lft = %s WHERE child = %s';
2364 foreach ($childs as $child)
2366 $i = $this->
__renumber($child[
"child"],$i+1);
2371 if (count($childs) > 0)
2373 $i += $this->gap * 2;
2377 $query =
'UPDATE '.$this->table_tree.
' SET rgt = %s WHERE child = %s';
2398 $cache_key = $a_ref_id.
'.'.$a_type.
'.'.((int)$a_exclude_source_check);
2402 array_key_exists($cache_key, $this->parent_type_cache))
2404 return $this->parent_type_cache[$cache_key];
2408 $do_cache = ($this->
__isMainTree() && count($this->parent_type_cache) < 1000);
2415 $this->parent_type_cache[$cache_key] =
false;
2423 if($a_exclude_source_check)
2428 foreach(
$path as $node)
2431 if($node[
"type"] == $a_type)
2435 $this->parent_type_cache[$cache_key] = $node[
"child"];
2437 return $node[
"child"];
2443 $this->parent_type_cache[$cache_key] =
false;
2461 if($a_db_table ===
'tree')
2463 if($a_tree == 1 and $a_child == ROOT_FOLDER_ID)
2465 $message = sprintf(
'%s::_removeEntry(): Tried to delete root node! $a_tree: %s $a_child: %s',
2474 $query =
'DELETE FROM '.$a_db_table.
' '.
2491 return $this->table_tree ===
'tree';
2513 $counter = (int) $lft_childs = array();
2516 $lft_childs[
$row->child] =
$row->parent;
2521 if($counter != count($lft_childs))
2523 $message = sprintf(
'%s::__checkTree(): Duplicate entries for "child" in maintree! $a_node_id: %s',
2526 $this->log->write($message,$this->log->FATAL);
2527 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2531 $parent_childs = array();
2551 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2552 'WHERE child = %s '.
2561 $parent_childs[$a_node_id] =
$row->parent;
2567 $message = sprintf(
'%s::__getSubTreeByParentRelation(): Multiple entries in maintree! $a_node_id: %s',
2570 $this->log->write($message,$this->log->FATAL);
2571 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2575 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2576 'WHERE parent = %s ';
2591 ksort($parent_childs);
2593 $GLOBALS[
'ilLog']->write(__METHOD__.
': left childs '. print_r($lft_childs,
true));
2594 $GLOBALS[
'ilLog']->write(__METHOD__.
': parent childs '. print_r($parent_childs,
true));
2596 if(count($lft_childs) != count($parent_childs))
2598 $message = sprintf(
'%s::__validateSubtrees(): (COUNT) Tree is corrupted! Left/Right subtree does not comply .'.
2599 'with parent relation',
2601 $this->log->write($message,$this->log->FATAL);
2602 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2606 foreach($lft_childs as $key => $value)
2608 if($parent_childs[$key] != $value)
2610 $message = sprintf(
'%s::__validateSubtrees(): (COMPARE) Tree is corrupted! Left/Right subtree does not comply '.
2611 'with parent relation',
2613 $this->log->write($message,$this->log->FATAL);
2614 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2616 if($key == ROOT_FOLDER_ID)
2618 $message = sprintf(
'%s::__validateSubtrees(): (ROOT_FOLDER) Tree is corrupted! Tried to delete root folder',
2620 $this->log->write($message,$this->log->FATAL);
2621 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
2636 public function moveTree($a_source_id, $a_target_id, $a_location = self::POS_LAST_NODE)
2639 $GLOBALS[
'ilAppEventHandler']->raise(
2643 'tree' => $this->table_tree,
2644 'source_id' => $a_source_id,
2645 'target_id' => $a_target_id)
2673 public function getSubTreeQuery($a_node_id,$a_fields = array(), $a_types =
'', $a_force_join_reference =
false)
2678 $a_force_join_reference,
2706 if(count($a_fields))
2708 $fields = implode(
',',$a_fields);
2711 $query =
"SELECT ".$fields.
2712 " FROM ".$this->getTreeTable().
2713 " ".$this->buildJoin().
2714 " WHERE ".$this->getTableReference().
".".$this->ref_pk.
" IN (".
$query.
")".
2715 " AND ".$ilDB->in($this->
getObjectDataTable().
".".$this->obj_pk, $a_obj_ids,
"",
"integer");
2729 $query =
'DELETE FROM tree where '.
2730 'child = '.$ilDB->quote($a_node_id,
'integer').
' '.
2731 'AND tree = '.$ilDB->quote($a_tree_id,
'integer');
const PEAR_ERROR_CALLBACK
toNFC( $string)
Convert a UTF-8 string to normal form C, canonical composition.
const DB_FETCHMODE_OBJECT
static _lookupTitle($a_obj_id)
Overwitten from base class.
quote($a_query, $a_type=null)
Wrapper for quote method.
Error Handling & global info handling uses PEAR error class.
Thrown if invalid tree strucutes are found.
Base class for materialize path based trees Based on implementation of Werner Randelshofer.
Base class for nested set path based trees.
static setDeletedDates($a_ref_ids)
Set deleted date @global type $ilDB.
_resetDeletedDate($a_ref_id)
only called in ilObjectGUI::insertSavedNodes
static strToLower($a_string)
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
isCacheUsed()
Check if cache is active.
fetchPredecessorNode($a_node_id, $a_type="")
get node data of predecessor node
getRelation($a_node_a, $a_node_b)
Get relation of two nodes.
moveToTrash($a_node_id, $a_set_deleted=false)
Wrapper for saveSubTree.
getSubTree($a_node, $a_with_data=true, $a_type="")
get all nodes in the subtree under specified node
getFilteredChilds($a_filter, $a_node, $a_order="", $a_direction="ASC")
get child nodes of given node (exclude filtered obj_types) @access public
isGrandChild($a_startnode_id, $a_querynode_id)
checks if a node is in the path of an other node @access public
getSubTreeTypes($a_node, $a_filter=0)
get types of nodes in the subtree under specified node
getRelationOfNodes($a_node_a_arr, $a_node_b_arr)
get relation of two nodes by node data
setObjectTablePK($a_column_name)
set column containing primary key in object table @access public
getTreePk()
Get tree primary key.
getParentId($a_node_id)
get parent id of given node @access public
getRbacSubtreeInfo($a_endnode_id)
This method is used for change existing objects and returns all necessary information for this action...
getParentCache()
Get parent cache.
setReferenceTablePK($a_column_name)
set column containing primary key in reference table @access public
saveSubTree($a_node_id, $a_set_deleted=false)
Use the wrapper moveToTrash save subtree: delete a subtree (defined by node_id) to a new tree with $t...
checkTreeChilds($a_no_zero_child=true)
check, if all childs of tree nodes exist in object table
getDepth($a_node_id)
return depth of a node in tree @access private
getSavedNodeData($a_parent_id)
get data saved/deleted nodes
getChildSequenceNumber($a_node, $type="")
get sequence number of node in sibling sequence @access public
useCache($a_use=true)
Use Cache (usually activated)
deleteTree($a_node)
delete node and the whole subtree under this node @access public
getLeftValue($a_node_id)
get left value of given node @access public
__checkDelete($a_node)
Check for deleteTree() compares a subtree of a given node by checking lft, rgt against parent relatio...
fetchSuccessorNode($a_node_id, $a_type="")
get node data of successor node
getDepthCache()
Get depth cache.
getTreeId()
get tree id @access public
getChildIds($a_node)
Get node child ids @global type $ilDB.
getNodeDataByType($a_type)
get nodes by type
getTreeTable()
Get tree table name.
getSubTreeQuery($a_node_id, $a_fields=array(), $a_types='', $a_force_join_reference=false)
Get tree subtree query.
__renumber($node_id=1, $i=1)
This method is private.
setTreeTablePK($a_column_name)
set column containing primary key in tree table @access public
isDeleted($a_node_id)
This is a wrapper for isSaved() with a more useful name.
getNodeTreeData($a_node_id)
return all columns of tabel tree
_removeEntry($a_tree, $a_child, $a_db_table="tree")
STATIC METHOD Removes a single entry from a tree.
setTableNames($a_table_tree, $a_table_obj_data, $a_table_obj_reference="")
set table names The primary key of the table containing your object_data must be 'obj_id' You may use...
getTableReference()
Get reference table if available.
fetchTranslationFromObjectDataCache($a_obj_ids)
Get translation data from object cache (trigger in object cache on preload)
readRootId()
read root id from database
removeTree($a_tree_id)
remove an existing tree
ilTree($a_tree_id, $a_root_id=0)
Constructor @access public.
fetchNodeData($a_row)
get data of parent node from tree and object_data @access private
checkTree()
check consistence of tree all left & right values are checked if they are exists only once @access pu...
getSubTreeFilteredByObjIds($a_node_id, array $a_obj_ids, array $a_fields=array())
get all node ids in the subtree under specified node id, filter by object ids
renumber($node_id=1, $i=1)
Wrapper for renumber.
getNodePath($a_endnode_id, $a_startnode_id=0)
Returns the node path for the specified object reference.
getChildsByType($a_node_id, $a_type)
get child nodes of given node by object type @access public
getNodeData($a_node_id, $a_tree_pk=null)
get all information of a node.
setTreeId($a_tree_id)
set tree id @access public
getSavedNodeObjIds(array $a_obj_ids)
get object id of saved/deleted nodes
getChildsByTypeFilter($a_node_id, $a_types, $a_order="", $a_direction="ASC")
get child nodes of given node by object type @access public
deleteNode($a_tree_id, $a_node_id)
getMaximumDepth()
Return the current maximum depth in the tree @access public.
moveTree($a_source_id, $a_target_id, $a_location=self::POS_LAST_NODE)
Move Tree Implementation.
preloadDepthParent($a_node_ids)
Preload depth/parent.
isSaved($a_node_id)
Use method isDeleted check if node is saved.
initLangCode()
Store user language.
buildJoin()
build join depending on table settings @access private
getTreeImplementation()
Get tree implementation.
getNodePathForTitlePath($titlePath, $a_startnode_id=null)
Converts a path consisting of object titles into a path consisting of tree nodes.
initTreeImplementation()
Init tree implementation.
preloadDeleted($a_node_ids)
Preload deleted information.
getFilteredSubTree($a_node_id, $a_filter=array())
get filtered subtree
getObjectDataTable()
Get object data table.
getRootId()
get the root id of tree @access public
insertNode($a_node_id, $a_parent_id, $a_pos=IL_LAST_NODE, $a_reset_deletion_date=false)
insert new node with node_id under parent node with parent_id @access public
checkForParentType($a_ref_id, $a_type, $a_exclude_source_check=false)
Check for parent type e.g check if a folder (ref_id 3) is in a parent course obj => checkForParentTyp...
__isMainTree()
Check if operations are done on main tree.
__getSubTreeByParentRelation($a_node_id, &$parent_childs)
@global type $ilDB
isInTree($a_node_id)
get all information of a node.
getGap()
Get default gap *.
__validateSubtrees(&$lft_childs, $parent_childs)
getPathId($a_endnode_id, $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
addTree($a_tree_id, $a_node_id=-1)
create a new tree to do: ???
getPathFull($a_endnode_id, $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
getParentNodeData($a_node_id)
get data of parent node from tree and object_data @access public
getChilds($a_node_id, $a_order="", $a_direction="ASC")
get child nodes of given node @access public
getSubTreeIds($a_ref_id)
Get all ids of subnodes.
static shortenText($a_str, $a_len, $a_dots=false, $a_next_blank=false, $a_keep_extension=false)
shorten a string to given length.
static quoteArray($a_array)
Quotes all members of an array for usage in DB query statement.