19 declare(strict_types=1);
39 $this->tree = $a_tree;
40 $this->db = $DIC->database();
54 $query =
'SELECT s.child FROM ' .
55 $this->
getTree()->getTreeTable() .
' s, ' .
56 $this->
getTree()->getTreeTable() .
' t ' .
57 'WHERE t.child = %s ' .
58 'AND s.lft > t.lft ' .
59 'AND s.rgt < t.rgt ' .
60 'AND s.' . $this->
getTree()->getTreePk() .
' = %s';
62 $res = $this->db->queryF(
64 array(
'integer',
'integer'),
65 array($a_node_id, $this->
getTree()->getTreeId())
69 $childs[] = (
int) $row->child;
80 bool $a_force_join_reference =
true,
84 if (is_array($a_types)) {
86 $type_str =
"AND " . $this->db->in(
87 $this->
getTree()->getObjectDataTable() .
".type",
96 if ($type_str || $a_force_join_reference) {
97 $join = $this->
getTree()->buildJoin();
101 if (count($a_fields)) {
102 $fields = implode(
',', $a_fields);
107 "FROM " . $this->
getTree()->getTreeTable() .
" " .
109 "WHERE " . $this->
getTree()->getTreeTable() .
'.lft ' .
110 'BETWEEN ' . $this->db->quote($a_node[
'lft'],
'integer') .
' ' .
111 'AND ' . $this->db->quote($a_node[
'rgt'],
'integer') .
' ' .
112 "AND " . $this->
getTree()->getTreeTable() .
"." . $this->
getTree()->getTreePk() .
' < 0 ' .
114 "ORDER BY " . $this->
getTree()->getTreeTable() .
".lft";
125 bool $a_force_join_reference =
true,
129 if (count($a_types)) {
131 $type_str =
"AND " . $this->db->in(
132 $this->
getTree()->getObjectDataTable() .
".type",
142 if ($type_str || $a_force_join_reference) {
143 $join = $this->
getTree()->buildJoin();
147 if (count($a_fields)) {
148 $fields = implode(
',', $a_fields);
153 "FROM " . $this->
getTree()->getTreeTable() .
" " .
155 "WHERE " . $this->
getTree()->getTreeTable() .
'.lft ' .
156 'BETWEEN ' . $this->db->quote($a_node[
'lft'],
'integer') .
' ' .
157 'AND ' . $this->db->quote($a_node[
'rgt'],
'integer') .
' ' .
158 "AND " . $this->
getTree()->getTreeTable() .
"." . $this->
getTree()->getTreePk() .
" = " . $this->db->quote(
163 "ORDER BY " . $this->
getTree()->getTreeTable() .
".lft";
172 if ($a_node_a === [] || $a_node_b === []) {
175 if ($a_node_a[
'child'] == $a_node_b[
'child']) {
178 if ($a_node_a[
'lft'] < $a_node_b[
'lft'] && $a_node_a[
'rgt'] > $a_node_b[
'rgt']) {
181 if ($a_node_b[
'lft'] < $a_node_a[
'lft'] && $a_node_b[
'rgt'] > $a_node_a[
'rgt']) {
186 if ($a_node_a[
'parent'] == $a_node_b[
'parent']) {
192 public function getPathIds(
int $a_endnode,
int $a_startnode = 0): array
200 public function insertNode(
int $a_node_id,
int $a_parent_id,
int $a_pos): void
202 $insert_node_callable =
function (
ilDBInterface $db) use ($a_node_id, $a_parent_id, $a_pos):
void {
208 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
209 'WHERE child = %s ' .
210 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
211 $this->db->quote($a_parent_id,
'integer'),
212 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
215 $res = $this->db->query($query);
216 $r = $this->db->fetchObject($res);
218 if (
$r->parent ===
null) {
227 if ($this->
getTree()->__isMainTree()) {
229 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
230 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
231 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ',
232 $this->db->quote($left,
'integer'),
233 $this->db->quote($left,
'integer')
235 $res = $this->db->manipulate($query);
238 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
239 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
240 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ' .
241 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
242 $this->db->quote($left,
'integer'),
243 $this->db->quote($left,
'integer'),
244 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
246 $res = $this->db->manipulate($query);
253 if ($this->
getTree()->getGap() > 0) {
256 'SELECT rgt,lft,parent FROM ' . $this->
getTree()->getTreeTable() .
' ' .
257 'WHERE child = %s ' .
258 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
259 $this->db->quote($a_parent_id,
'integer'),
260 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
262 $res = $this->db->query($query);
263 $r = $this->db->fetchAssoc($res);
265 if (
$r[
'parent'] ===
null) {
269 $parentRgt = (
int)
$r[
'rgt'];
270 $parentLft = (
int)
$r[
'lft'];
273 $availableSpace = $parentRgt - $parentLft;
274 if ($availableSpace < 2) {
282 if ($this->
getTree()->__isMainTree()) {
284 'SELECT MAX(rgt) max_rgt FROM ' . $this->
getTree()->getTreeTable() .
' ' .
285 'WHERE parent = %s ',
286 $this->db->quote($a_parent_id,
'integer')
288 $res = $this->db->query($query);
289 $r = $this->db->fetchAssoc($res);
292 'SELECT MAX(rgt) max_rgt FROM ' . $this->
getTree()->getTreeTable() .
' ' .
293 'WHERE parent = %s ' .
294 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
295 $this->db->quote($a_parent_id,
'integer'),
296 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
298 $res = $this->db->query($query);
299 $r = $this->db->fetchAssoc($res);
302 if (isset(
$r[
'max_rgt'])) {
305 $availableSpace = $parentRgt -
$r[
'max_rgt'];
306 $lft = $r[
'max_rgt'] + 1;
311 $lft = $parentLft + 1;
317 if ($availableSpace < 2) {
318 if ($this->
getTree()->__isMainTree()) {
320 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
321 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
322 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ',
323 $this->db->quote($parentRgt,
'integer'),
324 $this->db->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
325 $this->db->quote($parentRgt,
'integer'),
326 $this->db->quote((2 + $this->
getTree()->getGap() * 2),
'integer')
328 $res = $this->db->manipulate($query);
331 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
332 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
333 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ' .
334 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
335 $this->db->quote($parentRgt,
'integer'),
336 $this->db->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
337 $this->db->quote($parentRgt,
'integer'),
338 $this->db->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
339 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
341 $res = $this->db->manipulate($query);
347 if ($this->
getTree()->__isMainTree()) {
349 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
351 $this->db->quote($a_parent_id,
'integer')
353 $res = $this->db->query($query);
356 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
357 'WHERE child = %s ' .
358 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
359 $this->db->quote($a_parent_id,
'integer'),
360 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
362 $res = $this->db->query($query);
364 $r = $this->db->fetchObject($res);
366 if (
$r->parent ===
null) {
376 if ($this->
getTree()->__isMainTree()) {
378 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
379 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
380 'rgt = CASE WHEN rgt >= %s THEN rgt + 2 ELSE rgt END ',
381 $this->db->quote($right,
'integer'),
382 $this->db->quote($right,
'integer')
384 $res = $this->db->manipulate($query);
387 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
388 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
389 'rgt = CASE WHEN rgt >= %s THEN rgt + 2 ELSE rgt END ' .
390 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s',
391 $this->db->quote($right,
'integer'),
392 $this->db->quote($right,
'integer'),
393 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
395 $res = $this->db->manipulate($query);
405 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
406 'WHERE child = %s ' .
407 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
408 $this->db->quote($a_pos,
'integer'),
409 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
411 $res = $this->db->query($query);
412 $r = $this->db->fetchObject($res);
415 if (
$r->parent != $a_parent_id) {
424 if ($this->
getTree()->__isMainTree()) {
426 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
427 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
428 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ',
429 $this->db->quote($right,
'integer'),
430 $this->db->quote($right,
'integer')
432 $res = $this->db->manipulate($query);
435 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
436 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
437 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ' .
438 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s',
439 $this->db->quote($right,
'integer'),
440 $this->db->quote($right,
'integer'),
441 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
443 $res = $this->db->manipulate($query);
450 $depth = $this->
getTree()->getDepth($a_parent_id) + 1;
454 'INSERT INTO ' . $this->
getTree()->getTreeTable() .
' (' . $this->
getTree()->getTreePk() .
',child,parent,lft,rgt,depth) ' .
455 'VALUES (%s,%s,%s,%s,%s,%s)',
456 $this->db->quote($this->getTree()->getTreeId(),
'integer'),
457 $this->db->quote($a_node_id,
'integer'),
458 $this->db->quote($a_parent_id,
'integer'),
459 $this->db->quote($lft,
'integer'),
460 $this->db->quote($rgt,
'integer'),
461 $this->db->quote($depth,
'integer')
463 $res = $this->db->manipulate($query);
466 if ($this->
getTree()->__isMainTree()) {
467 $ilAtomQuery = $this->db->buildAtomQuery();
468 $ilAtomQuery->addTableLock(
'tree');
469 $ilAtomQuery->addQueryCallable($insert_node_callable);
472 $insert_node_callable($this->db);
481 $delete_tree_callable =
function (
ilDBInterface $db) use ($a_node_id):
void {
484 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
485 'WHERE child = ' . $this->db->quote($a_node_id,
'integer') .
' ' .
486 'AND ' . $this->
getTree()->getTreePk() .
' = ' . $this->db->quote(
490 $res = $this->db->query($query);
499 'DELETE FROM ' . $this->
getTree()->getTreeTable() .
' ' .
500 'WHERE lft BETWEEN %s AND %s ' .
501 'AND rgt BETWEEN %s AND %s ' .
502 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
503 $this->db->quote($node[
'lft'],
'integer'),
504 $this->db->quote($node[
'rgt'],
'integer'),
505 $this->db->quote($node[
'lft'],
'integer'),
506 $this->db->quote($node[
'rgt'],
'integer'),
507 $this->db->quote($node[$this->
getTree()->getTreePk()],
'integer')
509 $res = $this->db->manipulate($query);
515 $diff = $node[
"rgt"] - $node[
"lft"] + 1;
517 $node[$this->
getTree()->getTreePk()] >= 0 &&
518 $node[
'rgt'] - $node[
'lft'] >= $this->
getTree()->getGap() * 2
520 if ($this->
getTree()->__isMainTree()) {
522 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
523 'lft = CASE WHEN lft > %s THEN lft - %s ELSE lft END, ' .
524 'rgt = CASE WHEN rgt > %s THEN rgt - %s ELSE rgt END ',
525 $this->db->quote($node[
'lft'],
'integer'),
526 $this->db->quote($diff,
'integer'),
527 $this->db->quote($node[
'lft'],
'integer'),
528 $this->db->quote($diff,
'integer')
530 $res = $this->db->manipulate($query);
533 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
534 'lft = CASE WHEN lft > %s THEN lft - %s ELSE lft END, ' .
535 'rgt = CASE WHEN rgt > %s THEN rgt - %s ELSE rgt END ' .
536 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
537 $this->db->quote($node[
'lft'],
'integer'),
538 $this->db->quote($diff,
'integer'),
539 $this->db->quote($node[
'lft'],
'integer'),
540 $this->db->quote($diff,
'integer'),
541 $this->db->quote($node[$this->
getTree()->getTreePk()],
'integer')
543 $res = $this->db->manipulate($query);
549 if ($this->
getTree()->__isMainTree()) {
550 $ilAtomQuery = $this->db->buildAtomQuery();
551 $ilAtomQuery->addTableLock(
'tree');
552 $ilAtomQuery->addQueryCallable($delete_tree_callable);
555 $delete_tree_callable($this->db);
564 $move_to_trash_callable =
function (
ilDBInterface $db) use ($a_node_id):
void {
565 $node = $this->
getTree()->getNodeTreeData($a_node_id);
567 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' ' .
568 'SET tree = ' . $this->db->quote(-1 * $node[
'child'],
'integer') .
' ' .
569 'WHERE ' . $this->
getTree()->getTreePk() .
' = ' . $this->db->quote(
573 'AND lft BETWEEN ' . $this->db->quote(
576 ) .
' AND ' . $this->db->quote($node[
'rgt'],
'integer') .
' ';
578 $this->db->manipulate($query);
583 if ($this->
getTree()->__isMainTree()) {
584 $ilAtomQuery = $this->db->buildAtomQuery();
585 $ilAtomQuery->addTableLock(
"tree");
586 $ilAtomQuery->addQueryCallable($move_to_trash_callable);
589 $move_to_trash_callable($this->db);
606 $takeId = $a_startnode_id == 0;
608 $depth_cache = $this->
getTree()->getDepthCache();
609 $parent_cache = $this->
getTree()->getParentCache();
612 $this->
getTree()->__isMainTree() &&
613 isset($depth_cache[$a_endnode_id]) &&
614 isset($parent_cache[$a_endnode_id])) {
615 $nodeDepth = $depth_cache[$a_endnode_id];
616 $parentId = $parent_cache[$a_endnode_id];
618 $nodeDepth = $this->
getTree()->getDepth($a_endnode_id);
619 $parentId = $this->
getTree()->getParentId($a_endnode_id);
628 } elseif ($nodeDepth == 1) {
629 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
631 $pathIds[] = $a_endnode_id;
633 } elseif ($nodeDepth == 2) {
634 $takeId = $takeId || $parentId == $a_startnode_id;
636 $pathIds[] = $parentId;
638 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
640 $pathIds[] = $a_endnode_id;
642 } elseif ($nodeDepth == 3) {
643 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
645 $pathIds[] = $this->
getTree()->getRootId();
647 $takeId = $takeId || $parentId == $a_startnode_id;
649 $pathIds[] = $parentId;
651 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
653 $pathIds[] = $a_endnode_id;
655 } elseif ($nodeDepth < 32) {
665 $qSelect =
't1.child c0';
667 for ($i = 1; $i < $nodeDepth - 2; $i++) {
668 $qSelect .=
', t' . $i .
'.parent c' . $i;
669 if ($this->
getTree()->__isMainTree()) {
670 $qJoin .=
' JOIN ' . $this->
getTree()->getTreeTable() .
' t' . $i .
' ON ' .
671 't' . $i .
'.child=t' . ($i - 1) .
'.parent ';
673 $qJoin .=
' JOIN ' . $this->
getTree()->getTreeTable() .
' t' . $i .
' ON ' .
674 't' . $i .
'.child=t' . ($i - 1) .
'.parent AND ' .
675 't' . $i .
'.' . $this->
getTree()->getTreePk() .
' = ' . $this->
getTree()->getTreeId();
679 if ($this->
getTree()->__isMainTree()) {
680 $types = array(
'integer');
681 $data = array($parentId);
682 $query =
'SELECT ' . $qSelect .
' ' .
683 'FROM ' . $this->
getTree()->getTreeTable() .
' t0 ' . $qJoin .
' ' .
684 'WHERE t0.child = %s ';
686 $types = array(
'integer',
'integer');
687 $data = array($this->
getTree()->getTreeId(), $parentId);
688 $query =
'SELECT ' . $qSelect .
' ' .
689 'FROM ' . $this->
getTree()->getTreeTable() .
' t0 ' . $qJoin .
' ' .
690 'WHERE t0.' . $this->
getTree()->getTreePk() .
' = %s ' .
691 'AND t0.child = %s ';
694 $this->db->setLimit(1, 0);
695 $res = $this->db->queryF($query, $types,
$data);
697 if (
$res->numRows() == 0) {
701 $row = $this->db->fetchAssoc(
$res);
703 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
705 $pathIds[] = $this->
getTree()->getRootId();
707 for ($i = $nodeDepth - 4; $i >= 0; $i--) {
708 $takeId = $takeId || $row[
'c' . $i] == $a_startnode_id;
710 $pathIds[] = (
int) $row[
'c' . $i];
713 $takeId = $takeId || $parentId == $a_startnode_id;
715 $pathIds[] = $parentId;
717 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
719 $pathIds[] = $a_endnode_id;
741 if ($this->
getTree()->__isMainTree()) {
742 $fields = array(
'integer');
743 $data = array($a_endnode_id);
744 $query =
"SELECT T2.child " .
745 "FROM " . $this->
getTree()->getTreeTable() .
" T1, " . $this->
getTree()->getTreeTable() .
" T2 " .
746 "WHERE T1.child = %s " .
747 "AND T1.lft BETWEEN T2.lft AND T2.rgt " .
750 $fields = array(
'integer',
'integer',
'integer');
751 $data = array($a_endnode_id, $this->
getTree()->getTreeId(), $this->
getTree()->getTreeId());
752 $query =
"SELECT T2.child " .
753 "FROM " . $this->
getTree()->getTreeTable() .
" T1, " . $this->
getTree()->getTreeTable() .
" T2 " .
754 "WHERE T1.child = %s " .
755 "AND T1.lft BETWEEN T2.lft AND T2.rgt " .
756 "AND T1." . $this->
getTree()->getTreePk() .
" = %s " .
757 "AND T2." . $this->
getTree()->getTreePk() .
" = %s " .
761 $res = $this->db->queryF($query, $fields,
$data);
763 $takeId = $a_startnode_id == 0;
765 while ($row = $this->db->fetchAssoc(
$res)) {
766 if ($takeId || $row[
'child'] == $a_startnode_id) {
768 $pathIds[] = (
int) $row[
'child'];
777 public function moveTree(
int $a_source_id,
int $a_target_id,
int $a_position): void
779 $move_tree_callable =
function (
ilDBInterface $ilDB) use ($a_source_id, $a_target_id, $a_position):
void {
781 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
782 'WHERE ( child = %s OR child = %s ) ' .
783 'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
784 $res = $this->db->queryF($query, array(
'integer',
'integer',
'integer'), array(
791 if (
$res->numRows() != 2) {
795 $source_lft = $target_lft = $source_rgt = $target_rgt = $source_depth = $target_depth = $source_parent = 0;
796 while ($row = $this->db->fetchObject(
$res)) {
797 if ($row->child == $a_source_id) {
798 $source_lft = $row->lft;
799 $source_rgt = $row->rgt;
800 $source_depth = $row->depth;
801 $source_parent = $row->parent;
803 $target_lft = $row->lft;
804 $target_rgt = $row->rgt;
805 $target_depth = $row->depth;
810 if ($target_lft >= $source_lft && $target_rgt <= $source_rgt) {
817 $spread_diff = $source_rgt - $source_lft + 1;
818 #var_dump("<pre>","SPREAD_DIFF: ",$spread_diff,"<pre>"); 820 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
821 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
822 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ';
824 if ($this->
getTree()->__isMainTree()) {
825 $res = $this->db->manipulateF($query, array(
'integer',
'integer',
'integer',
'integer'), [
832 $query .= (
'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ');
833 $res = $this->db->manipulateF(
835 array(
'integer',
'integer',
'integer',
'integer',
'integer'),
848 if ($source_lft > $target_rgt) {
849 $where_offset = $spread_diff;
850 $move_diff = $target_rgt - $source_lft - $spread_diff;
853 $move_diff = $target_rgt - $source_lft;
855 $depth_diff = $target_depth - $source_depth + 1;
857 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
858 'parent = CASE WHEN parent = %s THEN %s ELSE parent END, ' .
861 'depth = depth + %s ' .
865 if ($this->
getTree()->__isMainTree()) {
866 $res = $this->db->manipulateF(
868 array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
875 $source_lft + $where_offset,
876 $source_rgt + $where_offset
880 $query .=
'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
881 $res = $this->db->manipulateF(
883 array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
890 $source_lft + $where_offset,
891 $source_rgt + $where_offset,
898 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
899 'lft = CASE WHEN lft >= %s THEN lft - %s ELSE lft END, ' .
900 'rgt = CASE WHEN rgt >= %s THEN rgt - %s ELSE rgt END ';
902 if ($this->
getTree()->__isMainTree()) {
903 $res = $this->db->manipulateF($query, array(
'integer',
'integer',
'integer',
'integer'), [
904 $source_lft + $where_offset,
906 $source_rgt + $where_offset,
910 $query .= (
'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ');
912 $res = $this->db->manipulateF(
914 array(
'integer',
'integer',
'integer',
'integer',
'integer'),
916 $source_lft + $where_offset,
918 $source_rgt + $where_offset,
926 if ($this->
getTree()->__isMainTree()) {
927 $ilAtomQuery = $this->db->buildAtomQuery();
928 $ilAtomQuery->addTableLock(
'tree');
929 $ilAtomQuery->addQueryCallable($move_tree_callable);
932 $move_tree_callable($this->db);
942 $query =
"SELECT t2.lft lft, t2.rgt rgt, t2.child child, t2.parent parent, type " .
943 "FROM " . $this->
getTree()->getTreeTable() .
" t1 " .
944 "JOIN " . $this->
getTree()->getTreeTable() .
" t2 ON (t2.lft BETWEEN t1.lft AND t1.rgt) " .
945 "JOIN " . $this->
getTree()->getTableReference() .
" obr ON t2.child = obr.ref_id " .
946 "JOIN " . $this->
getTree()->getObjectDataTable() .
" obd ON obr.obj_id = obd.obj_id " .
947 "WHERE t1.child = " . $this->db->quote($a_endnode_id,
'integer') .
" " .
948 "AND t1." . $this->
getTree()->getTreePk() .
" = " . $this->db->quote(
952 "AND t2." . $this->
getTree()->getTreePk() .
" = " . $this->db->quote(
958 $res = $this->db->query($query);
961 $nodes[(
int) $row->child][
'lft'] = (
int) $row->lft;
962 $nodes[(
int) $row->child][
'rgt'] = (
int) $row->rgt;
963 $nodes[(
int) $row->child][
'child'] = (
int) $row->child;
964 $nodes[(
int) $row->child][
'parent'] = (
int) $row->parent;
965 $nodes[(
int) $row->child][
'type'] = (
string) $row->type;
977 $query =
'select ' . $this->
getTree()->getTreePk() .
', child from ' . $this->
getTree()->getTreeTable() .
' child where not exists ' .
979 'select child from ' . $this->
getTree()->getTreeTable() .
' parent where child.parent = parent.child and (parent.lft < child.lft) and (parent.rgt > child.rgt) ' .
981 'and ' . $this->
getTree()->getTreePk() .
' = ' . $this->
getTree()->getTreeId() .
' and child <> 1';
982 $res = $this->db->query($query);
986 $failures[] = $row[$this->
getTree()->getTreePk()];
997 if (!isset($a_node)) {
1004 $query =
'SELECT count(*) cnt FROM ' . $this->
getTree()->getTreeTable() .
' ' .
1005 $this->
getTree()->buildJoin() .
1006 'WHERE lft <= %s ' .
1008 'AND parent = %s ' .
1009 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = %s ';
1011 $res = $this->db->queryF($query, array(
'integer',
'text',
'integer',
'integer'), array(
1018 $query =
'SELECT count(*) cnt FROM ' . $this->
getTree()->getTreeTable() .
' ' .
1019 $this->
getTree()->buildJoin() .
1020 'WHERE lft <= %s ' .
1021 'AND parent = %s ' .
1022 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = %s ';
1024 $res = $this->db->queryF($query, array(
'integer',
'integer',
'integer'), array(
1030 $row = $this->db->fetchAssoc(
$res);
1031 return (
int) $row[
"cnt"];
1042 $query =
'SELECT lft FROM ' . $this->
getTree()->getTreeTable() .
' ' .
1043 'WHERE ' . $this->
getTree()->getTreeTable() .
'.child = %s ' .
1044 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = %s ';
1045 $res = $this->db->queryF($query, array(
'integer',
'integer'), array(
1049 $curr_node = $this->db->fetchAssoc(
$res);
1052 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
1053 $this->
getTree()->buildJoin() .
1055 'AND ' . $this->
getTree()->getObjectDataTable() .
'.type = %s ' .
1056 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = %s ' .
1058 $this->db->setLimit(1, 0);
1059 $res = $this->db->queryF($query, array(
'integer',
'text',
'integer'), array(
1065 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
1066 $this->
getTree()->buildJoin() .
1068 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = %s ' .
1070 $this->db->setLimit(1, 0);
1071 $res = $this->db->queryF($query, array(
'integer',
'integer'), array(
1077 if (
$res->numRows() < 1) {
1080 $row = $this->db->fetchAssoc(
$res);
1081 return $this->
getTree()->fetchNodeData($row);
1092 if (!isset($a_node_id)) {
1099 $query =
'SELECT lft FROM ' . $this->
getTree()->getTreeTable() .
' ' .
1100 'WHERE ' . $this->
getTree()->getTreeTable() .
'.child = %s ' .
1101 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = %s ';
1102 $res = $this->db->queryF($query, array(
'integer',
'integer'), array(
1107 $curr_node = $this->db->fetchAssoc(
$res);
1110 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
1111 $this->
getTree()->buildJoin() .
1113 'AND ' . $this->
getTree()->getObjectDataTable().
'.type = %s ' .
1114 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = %s ' .
1115 'ORDER BY lft DESC';
1116 $this->db->setLimit(1, 0);
1117 $res = $this->db->queryF($query, array(
'integer',
'text',
'integer'), array(
1123 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
1124 $this->
getTree()->buildJoin() .
1126 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = %s ' .
1127 'ORDER BY lft DESC';
1128 $this->db->setLimit(1, 0);
1129 $res = $this->db->queryF($query, array(
'integer',
'integer'), array(
1135 if (
$res->numRows() < 1) {
1138 $row = $this->db->fetchAssoc(
$res);
1139 return $this->
getTree()->fetchNodeData($row);
Thrown if invalid tree strucutes are found.
insertNode(int $a_node_id, int $a_parent_id, int $a_pos)
getSubTreeQuery(array $a_node, array $a_types=[], bool $a_force_join_reference=true, array $a_fields=[])
Get subtree.
static getLogger(string $a_component_id)
Get component logger.
fetchPredecessorNode(int $a_node_id, string $a_type="")
get node data of predecessor node
fetchSuccessorNode(int $a_node_id, string $a_type="")
get node data of successor node
Base class for nested set path based trees.
getSubTreeIds(int $a_node_id)
Get subtree ids int[].
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
getPathIds(int $a_endnode, int $a_startnode=0)
Get path ids from a startnode to a given endnode.
getRelation(array $a_node_a, array $a_node_b)
Get relation of two nodes.
__construct(ilTree $a_tree)
Constructor.
deleteTree(int $a_node_id)
Delete tree.
moveTree(int $a_source_id, int $a_target_id, int $a_position)
Move a source subtree to target.
getSubtreeInfo(int $a_endnode_id)
getTrashSubTreeQuery(array $a_node, array $a_types, bool $a_force_join_reference=true, array $a_fields=[])
Get subtree query for trashed tree items.
validateParentRelations()
Validate the parent relations of the tree implementation For nested set, validate the lft...
getPathIdsUsingNestedSets(int $a_endnode_id, int $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
Interface for tree implementations Currrently nested set or materialized path.
moveToTrash(int $a_node_id)
Move subtree to trash.
getChildSequenceNumber(array $a_node, string $type="")
get sequence number of node in sibling sequence
getPathIdsUsingAdjacencyMap(int $a_endnode_id, int $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...