4 include_once
'./Services/Tree/interfaces/interface.ilTreeImplementation.php';
26 $this->tree = $a_tree;
49 $query =
'SELECT s.child FROM ' .
50 $this->
getTree()->getTreeTable() .
' s, ' .
51 $this->
getTree()->getTreeTable() .
' t ' .
52 'WHERE t.child = %s ' .
53 'AND s.lft > t.lft ' .
54 'AND s.rgt < t.rgt ' .
55 'AND s.' . $this->
getTree()->getTreePk() .
' = %s';
59 array(
'integer',
'integer'),
60 array($a_node_id,$this->
getTree()->getTreeId())
63 $childs[] =
$row->child;
65 return $childs ? $childs : array();
77 public function getSubTreeQuery($a_node, $a_types =
'', $a_force_join_reference =
true, $a_fields = array())
84 if (is_array($a_types)) {
86 $type_str =
"AND " .
$ilDB->in($this->
getTree()->getObjectDataTable() .
".type", $a_types,
false,
"text");
88 } elseif (strlen($a_types)) {
89 $type_str =
"AND " . $this->
getTree()->getObjectDataTable() .
".type = " .
$ilDB->quote($a_types,
"text");
93 if ($type_str
or $a_force_join_reference) {
94 $join = $this->
getTree()->buildJoin();
98 if (count($a_fields)) {
99 $fields = implode(
',', $a_fields);
104 "FROM " . $this->
getTree()->getTreeTable() .
" " .
106 "WHERE " . $this->
getTree()->getTreeTable() .
'.lft ' .
107 'BETWEEN ' .
$ilDB->quote($a_node[
'lft'],
'integer') .
' ' .
108 'AND ' .
$ilDB->quote($a_node[
'rgt'],
'integer') .
' ' .
109 "AND " . $this->
getTree()->getTreeTable() .
"." . $this->
getTree()->getTreePk() .
" = " .
$ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
' ' .
111 "ORDER BY " . $this->
getTree()->getTreeTable() .
".lft";
113 #ilLoggerFactory::getLogger('tree')->debug('-----------------: '. $query); 127 if ($a_node_a[
'child'] == $a_node_b[
'child']) {
131 if ($a_node_a[
'lft'] < $a_node_b[
'lft']
and $a_node_a[
'rgt'] > $a_node_b[
'rgt']) {
135 if ($a_node_b[
'lft'] < $a_node_a[
'lft']
and $a_node_b[
'rgt'] > $a_node_a[
'rgt']) {
141 if ($a_node_a[
'parent'] == $a_node_b[
'parent']) {
172 $ilDB = $DIC[
'ilDB'];
174 $insert_node_callable =
function (
ilDBInterface $ilDB) use ($a_node_id, $a_parent_id, $a_pos) {
180 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
181 'WHERE child = %s ' .
182 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
183 $ilDB->quote($a_parent_id,
'integer'),
190 if (
$r->parent === null) {
201 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
202 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
203 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ' .
204 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
205 $ilDB->quote($left,
'integer'),
206 $ilDB->quote($left,
'integer'),
214 if ($this->
getTree()->getGap() > 0) {
217 'SELECT rgt,lft,parent FROM ' . $this->
getTree()->getTreeTable() .
' ' .
218 'WHERE child = %s ' .
219 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
220 $ilDB->quote($a_parent_id,
'integer'),
226 if (
$r[
'parent'] === null) {
230 $parentRgt =
$r[
'rgt'];
231 $parentLft =
$r[
'lft'];
234 $availableSpace = $parentRgt - $parentLft;
235 if ($availableSpace < 2) {
244 'SELECT MAX(rgt) max_rgt FROM ' . $this->
getTree()->getTreeTable() .
' ' .
245 'WHERE parent = %s ' .
246 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
247 $ilDB->quote($a_parent_id,
'integer'),
253 if (isset(
$r[
'max_rgt'])) {
256 $availableSpace = $parentRgt -
$r[
'max_rgt'];
257 $lft = $r[
'max_rgt'] + 1;
262 $lft = $parentLft + 1;
269 if ($availableSpace < 2) {
272 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
273 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
274 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ' .
275 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
276 $ilDB->quote($parentRgt,
'integer'),
277 $ilDB->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
278 $ilDB->quote($parentRgt,
'integer'),
279 $ilDB->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
290 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
291 'WHERE child = %s ' .
292 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
293 $ilDB->quote($a_parent_id,
'integer'),
299 if (
$r->parent === null) {
310 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
311 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
312 'rgt = CASE WHEN rgt >= %s THEN rgt + 2 ELSE rgt END ' .
313 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s',
314 $ilDB->quote($right,
'integer'),
315 $ilDB->quote($right,
'integer'),
327 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
328 'WHERE child = %s ' .
329 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
330 $ilDB->quote($a_pos,
'integer'),
337 if (
$r->parent != $a_parent_id) {
348 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
349 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
350 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ' .
351 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s',
352 $ilDB->quote($right,
'integer'),
353 $ilDB->quote($right,
'integer'),
362 $depth = $this->
getTree()->getDepth($a_parent_id) + 1;
366 'INSERT INTO ' . $this->
getTree()->getTreeTable() .
' (' . $this->
getTree()->getTreePk() .
',child,parent,lft,rgt,depth) ' .
367 'VALUES (%s,%s,%s,%s,%s,%s)',
368 $ilDB->quote($this->getTree()->getTreeId(),
'integer'),
369 $ilDB->quote($a_node_id,
'integer'),
370 $ilDB->quote($a_parent_id,
'integer'),
371 $ilDB->quote($lft,
'integer'),
372 $ilDB->quote($rgt,
'integer'),
373 $ilDB->quote($depth,
'integer')
378 if ($this->
getTree()->__isMainTree()) {
379 $ilAtomQuery =
$ilDB->buildAtomQuery();
380 $ilAtomQuery->addTableLock(
'tree');
381 $ilAtomQuery->addQueryCallable($insert_node_callable);
384 $insert_node_callable(
$ilDB);
398 $ilDB = $DIC[
'ilDB'];
404 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
405 'WHERE child = ' .
$ilDB->quote($a_node_id,
'integer') .
' ' .
406 'AND ' . $this->
getTree()->getTreePk() .
' = ' .
$ilDB->quote($this->
getTree()->getTreeId(),
'integer');
412 'DELETE FROM ' . $this->
getTree()->getTreeTable() .
' ' .
413 'WHERE lft BETWEEN %s AND %s ' .
414 'AND rgt BETWEEN %s AND %s ' .
415 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
416 $ilDB->quote($a_node[
'lft'],
'integer'),
417 $ilDB->quote($a_node[
'rgt'],
'integer'),
418 $ilDB->quote($a_node[
'lft'],
'integer'),
419 $ilDB->quote($a_node[
'rgt'],
'integer'),
420 $ilDB->quote($a_node[$this->
getTree()->getTreePk()],
'integer')
428 $diff = $a_node[
"rgt"] - $a_node[
"lft"] + 1;
430 $a_node[$this->
getTree()->getTreePk()] >= 0 &&
431 $a_node[
'rgt'] - $a_node[
'lft'] >= $this->
getTree()->getGap() * 2
435 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
436 'lft = CASE WHEN lft > %s THEN lft - %s ELSE lft END, ' .
437 'rgt = CASE WHEN rgt > %s THEN rgt - %s ELSE rgt END ' .
438 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
439 $ilDB->quote($a_node[
'lft'],
'integer'),
440 $ilDB->quote($diff,
'integer'),
441 $ilDB->quote($a_node[
'lft'],
'integer'),
442 $ilDB->quote($diff,
'integer'),
443 $ilDB->quote($a_node[$this->
getTree()->getTreePk()],
'integer')
451 if ($this->
getTree()->__isMainTree()) {
452 $ilAtomQuery =
$ilDB->buildAtomQuery();
453 $ilAtomQuery->addTableLock(
'tree');
454 $ilAtomQuery->addQueryCallable($delete_tree_callable);
457 $delete_tree_callable(
$ilDB);
475 $ilDB = $DIC[
'ilDB'];
478 $node = $this->
getTree()->getNodeTreeData($a_node_id);
480 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' ' .
481 'SET tree = ' .
$ilDB->quote(-1 * $node[
'child'],
'integer') .
' ' .
482 'WHERE ' . $this->
getTree()->getTreePk() .
' = ' .
$ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
' ' .
483 'AND lft BETWEEN ' .
$ilDB->quote($node[
'lft'],
'integer') .
' AND ' .
$ilDB->quote($node[
'rgt'],
'integer') .
' ';
490 if ($this->
getTree()->__isMainTree()) {
491 $ilAtomQuery =
$ilDB->buildAtomQuery();
492 $ilAtomQuery->addTableLock(
"tree");
494 $ilAtomQuery->addQueryCallable($move_to_trash_callable);
498 $move_to_trash_callable(
$ilDB);
517 $ilDB = $DIC[
'ilDB'];
524 $takeId = $a_startnode_id == 0;
526 $depth_cache = $this->
getTree()->getDepthCache();
527 $parent_cache = $this->
getTree()->getParentCache();
530 $this->
getTree()->__isMainTree() &&
531 isset($depth_cache[$a_endnode_id]) &&
532 isset($parent_cache[$a_endnode_id])) {
533 $nodeDepth = $depth_cache[$a_endnode_id];
534 $parentId = $parent_cache[$a_endnode_id];
536 $nodeDepth = $this->
getTree()->getDepth($a_endnode_id);
537 $parentId = $this->
getTree()->getParentId($a_endnode_id);
546 } elseif ($nodeDepth == 1) {
547 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
549 $pathIds[] = $a_endnode_id;
551 } elseif ($nodeDepth == 2) {
552 $takeId = $takeId || $parentId == $a_startnode_id;
554 $pathIds[] = $parentId;
556 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
558 $pathIds[] = $a_endnode_id;
560 } elseif ($nodeDepth == 3) {
561 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
563 $pathIds[] = $this->
getTree()->getRootId();
565 $takeId = $takeId || $parentId == $a_startnode_id;
567 $pathIds[] = $parentId;
569 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
571 $pathIds[] = $a_endnode_id;
573 } elseif ($nodeDepth < 32) {
583 $qSelect =
't1.child c0';
585 for (
$i = 1;
$i < $nodeDepth - 2;
$i++) {
586 $qSelect .=
', t' .
$i .
'.parent c' .
$i;
587 $qJoin .=
' JOIN ' . $this->
getTree()->getTreeTable() .
' t' .
$i .
' ON ' .
588 't' .
$i .
'.child=t' . (
$i - 1) .
'.parent AND ' .
589 't' .
$i .
'.' . $this->
getTree()->getTreePk() .
' = ' . (int) $this->
getTree()->getTreeId();
592 $types = array(
'integer',
'integer');
594 $query =
'SELECT ' . $qSelect .
' ' .
595 'FROM ' . $this->
getTree()->getTreeTable() .
' t0 ' . $qJoin .
' ' .
596 'WHERE t0.' . $this->
getTree()->getTreePk() .
' = %s ' .
597 'AND t0.child = %s ';
602 if (
$res->numRows() == 0) {
608 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
610 $pathIds[] = $this->
getTree()->getRootId();
612 for (
$i = $nodeDepth - 4;
$i >= 0;
$i--) {
613 $takeId = $takeId ||
$row[
'c' .
$i] == $a_startnode_id;
615 $pathIds[] =
$row[
'c' .
$i];
618 $takeId = $takeId || $parentId == $a_startnode_id;
620 $pathIds[] = $parentId;
622 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
624 $pathIds[] = $a_endnode_id;
645 $ilDB = $DIC[
'ilDB'];
653 $fields = array(
'integer',
'integer',
'integer');
656 $query =
"SELECT T2.child " .
657 "FROM " . $this->
getTree()->getTreeTable() .
" T1, " . $this->
getTree()->getTreeTable() .
" T2 " .
658 "WHERE T1.child = %s " .
659 "AND T1.lft BETWEEN T2.lft AND T2.rgt " .
660 "AND T1." . $this->
getTree()->getTreePk() .
" = %s " .
661 "AND T2." . $this->
getTree()->getTreePk() .
" = %s " .
666 $takeId = $a_startnode_id == 0;
668 if ($takeId ||
$row[
'child'] == $a_startnode_id) {
670 $pathIds[] =
$row[
'child'];
673 return $pathIds ? $pathIds : array();
685 public function moveTree($a_source_id, $a_target_id, $a_position)
689 $ilDB = $DIC[
'ilDB'];
691 $move_tree_callable =
function (
ilDBInterface $ilDB) use ($a_source_id, $a_target_id, $a_position) {
693 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
694 'WHERE ( child = %s OR child = %s ) ' .
695 'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
696 $res =
$ilDB->queryF(
$query, array(
'integer',
'integer',
'integer'), array(
699 $this->
getTree()->getTreeId()));
702 if (
$res->numRows() != 2) {
707 if (
$row->child == $a_source_id) {
708 $source_lft =
$row->lft;
709 $source_rgt =
$row->rgt;
710 $source_depth =
$row->depth;
711 $source_parent =
$row->parent;
713 $target_lft =
$row->lft;
714 $target_rgt =
$row->rgt;
715 $target_depth =
$row->depth;
720 if ($target_lft >= $source_lft
and $target_rgt <= $source_rgt) {
727 $spread_diff = $source_rgt - $source_lft + 1;
728 #var_dump("<pre>","SPREAD_DIFF: ",$spread_diff,"<pre>"); 730 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
731 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
732 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ' .
733 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ';
734 $res =
$ilDB->manipulateF(
$query, array(
'integer',
'integer',
'integer',
'integer',
'integer'), array(
739 $this->
getTree()->getTreeId()));
743 if ($source_lft > $target_rgt) {
744 $where_offset = $spread_diff;
745 $move_diff = $target_rgt - $source_lft - $spread_diff;
748 $move_diff = $target_rgt - $source_lft;
750 $depth_diff = $target_depth - $source_depth + 1;
753 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
754 'parent = CASE WHEN parent = %s THEN %s ELSE parent END, ' .
757 'depth = depth + %s ' .
760 'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
761 $res =
$ilDB->manipulateF(
$query, array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'), array(
767 $source_lft + $where_offset,
768 $source_rgt + $where_offset,
769 $this->
getTree()->getTreeId()));
772 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
773 'lft = CASE WHEN lft >= %s THEN lft - %s ELSE lft END, ' .
774 'rgt = CASE WHEN rgt >= %s THEN rgt - %s ELSE rgt END ' .
775 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ';
777 $res =
$ilDB->manipulateF(
$query, array(
'integer',
'integer',
'integer',
'integer',
'integer'), array(
778 $source_lft + $where_offset,
780 $source_rgt + $where_offset,
782 $this->
getTree()->getTreeId()));
786 if ($this->
getTree()->__isMainTree()) {
787 $ilAtomQuery =
$ilDB->buildAtomQuery();
788 $ilAtomQuery->addTableLock(
'tree');
789 $ilAtomQuery->addQueryCallable($move_tree_callable);
792 $move_tree_callable(
$ilDB);
806 $ilDB = $DIC[
'ilDB'];
808 $query =
"SELECT t2.lft lft, t2.rgt rgt, t2.child child, type " .
809 "FROM " . $this->
getTree()->getTreeTable() .
" t1 " .
810 "JOIN " . $this->
getTree()->getTreeTable() .
" t2 ON (t2.lft BETWEEN t1.lft AND t1.rgt) " .
811 "JOIN " . $this->
getTree()->getTableReference() .
" obr ON t2.child = obr.ref_id " .
812 "JOIN " . $this->
getTree()->getObjectDataTable() .
" obd ON obr.obj_id = obd.obj_id " .
813 "WHERE t1.child = " .
$ilDB->quote($a_endnode_id,
'integer') .
" " .
814 "AND t1." . $this->
getTree()->getTreePk() .
" = " .
$ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
" " .
815 "AND t2." . $this->
getTree()->getTreePk() .
" = " .
$ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
" " .
839 $ilDB = $DIC[
'ilDB'];
841 $query =
'select child from ' . $this->
getTree()->getTreeTable() .
' child where not exists ' .
843 'select child from ' . $this->
getTree()->getTreeTable() .
' parent where child.parent = parent.child and (parent.lft < child.lft) and (parent.rgt > child.rgt) ' .
845 'and ' . $this->
getTree()->getTreePk() .
' = ' . $this->
getTree()->getTreeId() .
' and child <> 1';
Thrown if invalid tree strucutes are found.
getPathIdsUsingNestedSets($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...
getPathIdsUsingAdjacencyMap($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...
getPathIds($a_endnode, $a_startnode=0)
Get path ids.
getRelation($a_node_a, $a_node_b)
Get relation.
getSubTreeIds($a_node_id)
Get subtree ids.
getTree()
Get tree object.
Base class for nested set path based trees.
moveTree($a_source_id, $a_target_id, $a_position)
Move source subtree to target.
insertNode($a_node_id, $a_parent_id, $a_pos)
Insert tree node.
foreach($_POST as $key=> $value) $res
__construct(ilTree $a_tree)
Constructor.
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
getSubtreeInfo($a_endnode_id)
Get rbac subtree info type $ilDB.
deleteTree($a_node_id)
Delete a subtree.
getSubTreeQuery($a_node, $a_types='', $a_force_join_reference=true, $a_fields=array())
Get subtree.
validateParentRelations()
Validate the parent relations of the tree implementation For nested set, validate the lft...
static getLogger($a_component_id)
Get component logger.
moveToTrash($a_node_id)
Move to trash.
Interface for tree implementations Currrently nested set or materialize path.