4 define(
"IL_LAST_NODE", -2);
5 define(
"IL_FIRST_NODE", -1);
7 include_once
'./Services/Tree/exceptions/class.ilInvalidTreeStructureException.php';
147 function ilTree($a_tree_id, $a_root_id = 0)
164 $this->lang_code =
"en";
166 if (!isset($a_tree_id) or (func_num_args() == 0) )
168 $this->ilErr->raiseError(get_class($this).
"::Constructor(): No tree_id given!",$this->ilErr->WARNING);
171 if (func_num_args() > 2)
173 $this->ilErr->raiseError(get_class($this).
"::Constructor(): Wrong parameter count!",$this->ilErr->WARNING);
180 if (empty($a_root_id))
182 $a_root_id = ROOT_FOLDER_ID;
185 $this->tree_id = $a_tree_id;
186 $this->root_id = $a_root_id;
187 $this->table_tree =
'tree';
188 $this->table_obj_data =
'object_data';
189 $this->table_obj_reference =
'object_reference';
190 $this->ref_pk =
'ref_id';
191 $this->obj_pk =
'obj_id';
192 $this->tree_pk =
'tree';
194 $this->use_cache =
true;
197 $this->translation_cache = array();
198 $this->parent_type_cache = array();
216 if(!is_object(
$GLOBALS[
'ilSetting']) or
$GLOBALS[
'ilSetting']->getModule() !=
'common')
218 include_once
'./Services/Administration/classes/class.ilSetting.php';
228 if($setting->get(
'main_tree_impl',
'ns') ==
'ns')
230 #$GLOBALS['ilLog']->write(__METHOD__.': Using nested set.');
231 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
236 #$GLOBALS['ilLog']->write(__METHOD__.': Using materialized path.');
237 include_once
'./Services/Tree/classes/class.ilMaterializedPathTree.php';
243 #$GLOBALS['ilLog']->write(__METHOD__.': Using netsted set for non main tree.');
244 include_once
'./Services/Tree/classes/class.ilNestedSetTree.php';
263 $this->use_cache = $a_use;
302 if (!is_object($ilUser))
304 $this->lang_code =
"en";
308 $this->lang_code = $ilUser->getCurrentLanguage();
360 $this->in_tree_cache = array();
378 function setTableNames($a_table_tree,$a_table_obj_data,$a_table_obj_reference =
"")
380 if (!isset($a_table_tree) or !isset($a_table_obj_data))
382 $this->ilErr->raiseError(get_class($this).
"::setTableNames(): Missing parameter! ".
383 "tree table: ".$a_table_tree.
" object data table: ".$a_table_obj_data,$this->ilErr->WARNING);
386 $this->table_tree = $a_table_tree;
387 $this->table_obj_data = $a_table_obj_data;
388 $this->table_obj_reference = $a_table_obj_reference;
403 if (!isset($a_column_name))
405 $this->ilErr->raiseError(get_class($this).
"::setReferenceTablePK(): No column name given!",$this->ilErr->WARNING);
408 $this->ref_pk = $a_column_name;
420 if (!isset($a_column_name))
422 $this->ilErr->raiseError(get_class($this).
"::setObjectTablePK(): No column name given!",$this->ilErr->WARNING);
425 $this->obj_pk = $a_column_name;
437 if (!isset($a_column_name))
439 $this->ilErr->raiseError(get_class($this).
"::setTreeTablePK(): No column name given!",$this->ilErr->WARNING);
442 $this->tree_pk = $a_column_name;
453 if ($this->table_obj_reference)
456 return "JOIN ".$this->table_obj_reference.
" ON ".$this->table_tree.
".child=".$this->table_obj_reference.
".".$this->ref_pk.
" ".
457 "JOIN ".$this->table_obj_data.
" ON ".$this->table_obj_reference.
".".$this->obj_pk.
"=".$this->table_obj_data.
".".$this->obj_pk.
" ";
462 return "JOIN ".$this->table_obj_data.
" ON ".$this->table_tree.
".child=".$this->table_obj_data.
".".$this->obj_pk.
" ";
500 $query =
'SELECT * FROM tree '.
501 'WHERE parent = '.$ilDB->quote($a_node,
'integer').
' '.
502 'AND tree > '.$ilDB->quote(0,
'integer');
508 $childs[] =
$row->child;
521 function getChilds($a_node_id, $a_order =
"", $a_direction =
"ASC")
525 if (!isset($a_node_id))
527 $message = get_class($this).
"::getChilds(): No node_id given!";
528 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
541 if (!empty($a_order))
543 $order_clause =
"ORDER BY ".$a_order.
" ".$a_direction;
547 $order_clause =
"ORDER BY ".$this->table_tree.
".lft";
551 $query = sprintf(
'SELECT * FROM '.$this->table_tree.
' '.
553 "WHERE parent = %s " .
554 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
556 $ilDB->quote($a_node_id,
'integer'),
557 $ilDB->quote($this->tree_id,
'integer'));
561 if(!$count = $res->numRows())
568 while($r = $ilDB->fetchAssoc($res))
571 $obj_ids[] = $r[
"obj_id"];
576 is_object($ilUser) && $this->lang_code == $ilUser->getLanguage() && !$this->oc_preloaded[$a_node_id])
579 $ilObjDataCache->preloadObjectCache($obj_ids, $this->lang_code);
581 $this->oc_preloaded[$a_node_id] =
true;
584 foreach ($rows as
$row)
591 #$GLOBALS['ilLog']->write(__METHOD__.': Storing in tree cache '.$row['child'].' = true');
592 $this->in_tree_cache[$row[
'child']] = $row[
'tree'] == 1;
595 $childs[$count - 1][
"last"] =
true;
610 $childs = $this->
getChilds($a_node,$a_order,$a_direction);
612 foreach($childs as $child)
614 if(!in_array($child[
"type"],$a_filter))
616 $filtered[] = $child;
619 return $filtered ? $filtered : array();
634 if (!isset($a_node_id) or !isset($a_type))
636 $message = get_class($this).
"::getChildsByType(): Missing parameter! node_id:".$a_node_id.
" type:".$a_type;
637 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
640 if ($a_type==
'rolf' && $this->table_obj_reference) {
644 $ilDB->setLimit(1,0);
645 $query = sprintf(
"SELECT * FROM ".$this->table_tree.
" ".
647 "WHERE parent = %s ".
648 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
649 "AND ".$this->table_obj_data.
".type = %s ",
650 $ilDB->quote($a_node_id,
'integer'),
651 $ilDB->quote($this->tree_id,
'integer'),
652 $ilDB->quote($a_type,
'text'));
654 $query = sprintf(
"SELECT * FROM ".$this->table_tree.
" ".
656 "WHERE parent = %s ".
657 "AND ".$this->table_tree.
".".$this->tree_pk.
" = %s ".
658 "AND ".$this->table_obj_data.
".type = %s ".
659 "ORDER BY ".$this->table_tree.
".lft",
660 $ilDB->quote($a_node_id,
'integer'),
661 $ilDB->quote($this->tree_id,
'integer'),
662 $ilDB->quote($a_type,
'text'));
668 while(
$row = $ilDB->fetchAssoc(
$res))
673 return $childs ? $childs : array();
688 if (!isset($a_node_id) or !$a_types)
690 $message = get_class($this).
"::getChildsByType(): Missing parameter! node_id:".$a_node_id.
" type:".$a_types;
691 $this->ilErr->raiseError($message,$this->ilErr->WARNING);
697 $filter =
'AND '.$this->table_obj_data.
'.type IN('.implode(
',',
ilUtil::quoteArray($a_types)).
') ';
701 if (!empty($a_order))
703 $order_clause =
"ORDER BY ".$a_order.
" ".$a_direction;
707 $order_clause =
"ORDER BY ".$this->table_tree.
".lft";
710 $query =
'SELECT * FROM '.$this->table_tree.
' '.
712 'WHERE parent = '.$ilDB->quote($a_node_id,
'integer').
' '.
713 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = '.$ilDB->quote($this->tree_id,
'integer').
' '.
718 while(
$row = $ilDB->fetchAssoc(
$res))
723 return $childs ? $childs : array();
741 if($a_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');
859 while(
$row = $ilDB->fetchAssoc(
$res))
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"));
1012 while (
$row = $ilDB->fetchAssoc(
$res))
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();
1225 while (
$row = $ilDB->fetchAssoc(
$res))
1227 $titlePath[] =
$row;
1243 $types = array(
'integer');
1244 $query =
'SELECT lft,rgt FROM '.$this->table_tree.
' '.
1245 'WHERE '.$this->tree_pk.
' = %s ';
1247 $res = $ilDB->queryF(
$query,$types,array($this->tree_id));
1248 while (
$row = $ilDB->fetchObject(
$res))
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));
1281 while (
$row = $ilDB->fetchAssoc($r1))
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 ';
1293 $r2 = $ilDB->queryF(
$query,array(
'integer'),array(
$row[
'child']));
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';
1328 $r2 = $ilDB->queryF(
$query,array(
'integer'),array(
$row[
'child']));
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 ';
1453 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
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"];
1494 $data[
"title"] = $lng->txt(
"obj_".$data[
"type"].
"_local");
1498 $data[
"title"] = $lng->txt(
"obj_".$data[
"type"]);
1499 $data[
"description"] = $lng->txt(
"obj_".$data[
"type"].
"_desc");
1500 $data[
"desc"] = $lng->txt(
"obj_".$data[
"type"].
"_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';
1525 $res = $ilDB->queryF(
$query,array(
'integer',
'text',
'integer'),array(
1533 $data[
"title"] =
$row->title;
1535 $data[
"desc"] =
$row->description;
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');
1558 return $data ? $data : array();
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';
1611 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
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');
1764 while(
$row = $ilDB->fetchAssoc(
$res))
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 ';
1906 $res = $ilDB->queryF(
$query,array(
'integer'),array($a_node_id));
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");
1946 while (
$row = $ilDB->fetchAssoc(
$res))
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';
1985 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
1989 while(
$row = $ilDB->fetchAssoc(
$res))
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');
2012 while(
$row = $ilDB->fetchAssoc(
$res))
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 ';
2038 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
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 ';
2064 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
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 ';
2132 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
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 ';
2194 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2197 $curr_node = $ilDB->fetchAssoc(
$res);
2201 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2204 'AND '.$this->table_obj_data.
'.type = %s '.
2205 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2208 $res = $ilDB->queryF(
$query,array(
'integer',
'text',
'integer'),array(
2215 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2218 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2221 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
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 ';
2257 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2261 $curr_node = $ilDB->fetchAssoc(
$res);
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';
2272 $res = $ilDB->queryF(
$query,array(
'integer',
'text',
'integer'),array(
2279 $query =
'SELECT * FROM '.$this->table_tree.
' '.
2282 'AND '.$this->table_tree.
'.'.$this->tree_pk.
' = %s '.
2283 'ORDER BY lft DESC';
2285 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
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';
2358 $res = $ilDB->manipulateF(
$query,array(
'integer',
'integer'),array(
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';
2378 $res = $ilDB->manipulateF(
$query,array(
'integer',
'integer'),array(
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',
2469 $ilLog->write($message,$ilLog->FATAL);
2470 $ilErr->raiseError($message,$ilErr->WARNING);
2474 $query =
'DELETE FROM '.$a_db_table.
' '.
2477 $res = $ilDB->manipulateF(
$query,array(
'integer',
'integer'),array(
2491 return $this->table_tree ===
'tree';
2513 $counter = (int) $lft_childs = array();
2514 while(
$row = $ilDB->fetchObject(
$res))
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 '.
2554 $res = $ilDB->queryF(
$query,array(
'integer',
'integer'),array(
2559 while(
$row = $ilDB->fetchObject(
$res))
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 ';
2577 $res = $ilDB->queryF(
$query,array(
'integer'),array($a_node_id));
2579 while(
$row = $ilDB->fetchObject(
$res))
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");
2716 $set = $ilDB->query(
$query);
2717 while(
$row = $ilDB->fetchAssoc($set))
2729 $query =
'DELETE FROM tree where '.
2730 'child = '.$ilDB->quote($a_node_id,
'integer').
' '.
2731 'AND tree = '.$ilDB->quote($a_tree_id,
'integer');
2732 $ilDB->manipulate(
$query);