3 declare(strict_types=1);
24 $this->tree = $a_tree;
25 $this->db = $DIC->database();
39 $query =
'SELECT s.child FROM ' .
40 $this->
getTree()->getTreeTable() .
' s, ' .
41 $this->
getTree()->getTreeTable() .
' t ' .
42 'WHERE t.child = %s ' .
43 'AND s.lft > t.lft ' .
44 'AND s.rgt < t.rgt ' .
45 'AND s.' . $this->
getTree()->getTreePk() .
' = %s';
47 $res = $this->db->queryF(
49 array(
'integer',
'integer'),
50 array($a_node_id, $this->
getTree()->getTreeId())
54 $childs[] = (
int) $row->child;
65 bool $a_force_join_reference =
true,
69 if (is_array($a_types)) {
71 $type_str =
"AND " . $this->db->in(
72 $this->
getTree()->getObjectDataTable() .
".type",
81 if ($type_str || $a_force_join_reference) {
82 $join = $this->
getTree()->buildJoin();
86 if (count($a_fields)) {
87 $fields = implode(
',', $a_fields);
92 "FROM " . $this->
getTree()->getTreeTable() .
" " .
94 "WHERE " . $this->
getTree()->getTreeTable() .
'.lft ' .
95 'BETWEEN ' . $this->db->quote($a_node[
'lft'],
'integer') .
' ' .
96 'AND ' . $this->db->quote($a_node[
'rgt'],
'integer') .
' ' .
97 "AND " . $this->
getTree()->getTreeTable() .
"." . $this->
getTree()->getTreePk() .
' < 0 ' .
99 "ORDER BY " . $this->
getTree()->getTreeTable() .
".lft";
110 bool $a_force_join_reference =
true,
114 if (count($a_types)) {
116 $type_str =
"AND " . $this->db->in(
117 $this->
getTree()->getObjectDataTable() .
".type",
127 if ($type_str || $a_force_join_reference) {
128 $join = $this->
getTree()->buildJoin();
132 if (count($a_fields)) {
133 $fields = implode(
',', $a_fields);
138 "FROM " . $this->
getTree()->getTreeTable() .
" " .
140 "WHERE " . $this->
getTree()->getTreeTable() .
'.lft ' .
141 'BETWEEN ' . $this->db->quote($a_node[
'lft'],
'integer') .
' ' .
142 'AND ' . $this->db->quote($a_node[
'rgt'],
'integer') .
' ' .
143 "AND " . $this->
getTree()->getTreeTable() .
"." . $this->
getTree()->getTreePk() .
" = " . $this->db->quote(
148 "ORDER BY " . $this->
getTree()->getTreeTable() .
".lft";
157 if ($a_node_a === [] || $a_node_b === []) {
160 if ($a_node_a[
'child'] == $a_node_b[
'child']) {
163 if ($a_node_a[
'lft'] < $a_node_b[
'lft'] && $a_node_a[
'rgt'] > $a_node_b[
'rgt']) {
166 if ($a_node_b[
'lft'] < $a_node_a[
'lft'] && $a_node_b[
'rgt'] > $a_node_a[
'rgt']) {
171 if ($a_node_a[
'parent'] == $a_node_b[
'parent']) {
177 public function getPathIds(
int $a_endnode,
int $a_startnode = 0): array
185 public function insertNode(
int $a_node_id,
int $a_parent_id,
int $a_pos): void
187 $insert_node_callable =
function (
ilDBInterface $db) use ($a_node_id, $a_parent_id, $a_pos):
void {
193 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
194 'WHERE child = %s ' .
195 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
196 $this->db->quote($a_parent_id,
'integer'),
197 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
200 $res = $this->db->query($query);
201 $r = $this->db->fetchObject($res);
203 if (
$r->parent === null) {
212 if ($this->
getTree()->__isMainTree()) {
214 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
215 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
216 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ',
217 $this->db->quote($left,
'integer'),
218 $this->db->quote($left,
'integer')
220 $res = $this->db->manipulate($query);
223 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
224 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
225 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ' .
226 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
227 $this->db->quote($left,
'integer'),
228 $this->db->quote($left,
'integer'),
229 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
231 $res = $this->db->manipulate($query);
238 if ($this->
getTree()->getGap() > 0) {
241 'SELECT rgt,lft,parent FROM ' . $this->
getTree()->getTreeTable() .
' ' .
242 'WHERE child = %s ' .
243 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
244 $this->db->quote($a_parent_id,
'integer'),
245 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
247 $res = $this->db->query($query);
248 $r = $this->db->fetchAssoc($res);
250 if (
$r[
'parent'] === null) {
254 $parentRgt = (
int)
$r[
'rgt'];
255 $parentLft = (
int)
$r[
'lft'];
258 $availableSpace = $parentRgt - $parentLft;
259 if ($availableSpace < 2) {
267 if ($this->
getTree()->__isMainTree()) {
269 'SELECT MAX(rgt) max_rgt FROM ' . $this->
getTree()->getTreeTable() .
' ' .
270 'WHERE parent = %s ',
271 $this->db->quote($a_parent_id,
'integer')
273 $res = $this->db->query($query);
274 $r = $this->db->fetchAssoc($res);
277 'SELECT MAX(rgt) max_rgt FROM ' . $this->
getTree()->getTreeTable() .
' ' .
278 'WHERE parent = %s ' .
279 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
280 $this->db->quote($a_parent_id,
'integer'),
281 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
283 $res = $this->db->query($query);
284 $r = $this->db->fetchAssoc($res);
287 if (isset(
$r[
'max_rgt'])) {
290 $availableSpace = $parentRgt -
$r[
'max_rgt'];
291 $lft = $r[
'max_rgt'] + 1;
296 $lft = $parentLft + 1;
302 if ($availableSpace < 2) {
303 if ($this->
getTree()->__isMainTree()) {
305 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
306 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
307 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ',
308 $this->db->quote($parentRgt,
'integer'),
309 $this->db->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
310 $this->db->quote($parentRgt,
'integer'),
311 $this->db->quote((2 + $this->
getTree()->getGap() * 2),
'integer')
313 $res = $this->db->manipulate($query);
316 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
317 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
318 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ' .
319 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
320 $this->db->quote($parentRgt,
'integer'),
321 $this->db->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
322 $this->db->quote($parentRgt,
'integer'),
323 $this->db->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
324 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
326 $res = $this->db->manipulate($query);
332 if ($this->
getTree()->__isMainTree()) {
334 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
336 $this->db->quote($a_parent_id,
'integer')
338 $res = $this->db->query($query);
341 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
342 'WHERE child = %s ' .
343 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
344 $this->db->quote($a_parent_id,
'integer'),
345 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
347 $res = $this->db->query($query);
349 $r = $this->db->fetchObject($res);
351 if (
$r->parent === null) {
361 if ($this->
getTree()->__isMainTree()) {
363 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
364 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
365 'rgt = CASE WHEN rgt >= %s THEN rgt + 2 ELSE rgt END ',
366 $this->db->quote($right,
'integer'),
367 $this->db->quote($right,
'integer')
369 $res = $this->db->manipulate($query);
372 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
373 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
374 'rgt = CASE WHEN rgt >= %s THEN rgt + 2 ELSE rgt END ' .
375 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s',
376 $this->db->quote($right,
'integer'),
377 $this->db->quote($right,
'integer'),
378 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
380 $res = $this->db->manipulate($query);
390 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
391 'WHERE child = %s ' .
392 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
393 $this->db->quote($a_pos,
'integer'),
394 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
396 $res = $this->db->query($query);
397 $r = $this->db->fetchObject($res);
400 if (
$r->parent != $a_parent_id) {
409 if ($this->
getTree()->__isMainTree()) {
411 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
412 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
413 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ',
414 $this->db->quote($right,
'integer'),
415 $this->db->quote($right,
'integer')
417 $res = $this->db->manipulate($query);
420 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
421 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
422 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ' .
423 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s',
424 $this->db->quote($right,
'integer'),
425 $this->db->quote($right,
'integer'),
426 $this->db->quote($this->
getTree()->getTreeId(),
'integer')
428 $res = $this->db->manipulate($query);
435 $depth = $this->
getTree()->getDepth($a_parent_id) + 1;
439 'INSERT INTO ' . $this->
getTree()->getTreeTable() .
' (' . $this->
getTree()->getTreePk() .
',child,parent,lft,rgt,depth) ' .
440 'VALUES (%s,%s,%s,%s,%s,%s)',
441 $this->db->quote($this->getTree()->getTreeId(),
'integer'),
442 $this->db->quote($a_node_id,
'integer'),
443 $this->db->quote($a_parent_id,
'integer'),
444 $this->db->quote($lft,
'integer'),
445 $this->db->quote($rgt,
'integer'),
446 $this->db->quote($depth,
'integer')
448 $res = $this->db->manipulate($query);
451 if ($this->
getTree()->__isMainTree()) {
452 $ilAtomQuery = $this->db->buildAtomQuery();
453 $ilAtomQuery->addTableLock(
'tree');
454 $ilAtomQuery->addQueryCallable($insert_node_callable);
457 $insert_node_callable($this->db);
466 $delete_tree_callable =
function (
ilDBInterface $db) use ($a_node_id):
void {
469 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
470 'WHERE child = ' . $this->db->quote($a_node_id,
'integer') .
' ' .
471 'AND ' . $this->
getTree()->getTreePk() .
' = ' . $this->db->quote(
475 $res = $this->db->query($query);
484 'DELETE FROM ' . $this->
getTree()->getTreeTable() .
' ' .
485 'WHERE lft BETWEEN %s AND %s ' .
486 'AND rgt BETWEEN %s AND %s ' .
487 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
488 $this->db->quote($node[
'lft'],
'integer'),
489 $this->db->quote($node[
'rgt'],
'integer'),
490 $this->db->quote($node[
'lft'],
'integer'),
491 $this->db->quote($node[
'rgt'],
'integer'),
492 $this->db->quote($node[$this->
getTree()->getTreePk()],
'integer')
494 $res = $this->db->manipulate($query);
500 $diff = $node[
"rgt"] - $node[
"lft"] + 1;
502 $node[$this->
getTree()->getTreePk()] >= 0 &&
503 $node[
'rgt'] - $node[
'lft'] >= $this->
getTree()->getGap() * 2
505 if ($this->
getTree()->__isMainTree()) {
507 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
508 'lft = CASE WHEN lft > %s THEN lft - %s ELSE lft END, ' .
509 'rgt = CASE WHEN rgt > %s THEN rgt - %s ELSE rgt END ',
510 $this->db->quote($node[
'lft'],
'integer'),
511 $this->db->quote($diff,
'integer'),
512 $this->db->quote($node[
'lft'],
'integer'),
513 $this->db->quote($diff,
'integer')
515 $res = $this->db->manipulate($query);
518 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
519 'lft = CASE WHEN lft > %s THEN lft - %s ELSE lft END, ' .
520 'rgt = CASE WHEN rgt > %s THEN rgt - %s ELSE rgt END ' .
521 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
522 $this->db->quote($node[
'lft'],
'integer'),
523 $this->db->quote($diff,
'integer'),
524 $this->db->quote($node[
'lft'],
'integer'),
525 $this->db->quote($diff,
'integer'),
526 $this->db->quote($node[$this->
getTree()->getTreePk()],
'integer')
528 $res = $this->db->manipulate($query);
534 if ($this->
getTree()->__isMainTree()) {
535 $ilAtomQuery = $this->db->buildAtomQuery();
536 $ilAtomQuery->addTableLock(
'tree');
537 $ilAtomQuery->addQueryCallable($delete_tree_callable);
540 $delete_tree_callable($this->db);
549 $move_to_trash_callable =
function (
ilDBInterface $db) use ($a_node_id):
void {
550 $node = $this->
getTree()->getNodeTreeData($a_node_id);
552 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' ' .
553 'SET tree = ' . $this->db->quote(-1 * $node[
'child'],
'integer') .
' ' .
554 'WHERE ' . $this->
getTree()->getTreePk() .
' = ' . $this->db->quote(
558 'AND lft BETWEEN ' . $this->db->quote(
561 ) .
' AND ' . $this->db->quote($node[
'rgt'],
'integer') .
' ';
563 $this->db->manipulate($query);
568 if ($this->
getTree()->__isMainTree()) {
569 $ilAtomQuery = $this->db->buildAtomQuery();
570 $ilAtomQuery->addTableLock(
"tree");
571 $ilAtomQuery->addQueryCallable($move_to_trash_callable);
574 $move_to_trash_callable($this->db);
591 $takeId = $a_startnode_id == 0;
593 $depth_cache = $this->
getTree()->getDepthCache();
594 $parent_cache = $this->
getTree()->getParentCache();
597 $this->
getTree()->__isMainTree() &&
598 isset($depth_cache[$a_endnode_id]) &&
599 isset($parent_cache[$a_endnode_id])) {
600 $nodeDepth = $depth_cache[$a_endnode_id];
601 $parentId = $parent_cache[$a_endnode_id];
603 $nodeDepth = $this->
getTree()->getDepth($a_endnode_id);
604 $parentId = $this->
getTree()->getParentId($a_endnode_id);
613 } elseif ($nodeDepth == 1) {
614 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
616 $pathIds[] = $a_endnode_id;
618 } elseif ($nodeDepth == 2) {
619 $takeId = $takeId || $parentId == $a_startnode_id;
621 $pathIds[] = $parentId;
623 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
625 $pathIds[] = $a_endnode_id;
627 } elseif ($nodeDepth == 3) {
628 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
630 $pathIds[] = $this->
getTree()->getRootId();
632 $takeId = $takeId || $parentId == $a_startnode_id;
634 $pathIds[] = $parentId;
636 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
638 $pathIds[] = $a_endnode_id;
640 } elseif ($nodeDepth < 32) {
650 $qSelect =
't1.child c0';
652 for ($i = 1; $i < $nodeDepth - 2; $i++) {
653 $qSelect .=
', t' . $i .
'.parent c' . $i;
654 if ($this->
getTree()->__isMainTree()) {
655 $qJoin .=
' JOIN ' . $this->
getTree()->getTreeTable() .
' t' . $i .
' ON ' .
656 't' . $i .
'.child=t' . ($i - 1) .
'.parent ';
658 $qJoin .=
' JOIN ' . $this->
getTree()->getTreeTable() .
' t' . $i .
' ON ' .
659 't' . $i .
'.child=t' . ($i - 1) .
'.parent AND ' .
660 't' . $i .
'.' . $this->
getTree()->getTreePk() .
' = ' . $this->
getTree()->getTreeId();
664 if ($this->
getTree()->__isMainTree()) {
665 $types = array(
'integer');
666 $data = array($parentId);
667 $query =
'SELECT ' . $qSelect .
' ' .
668 'FROM ' . $this->
getTree()->getTreeTable() .
' t0 ' . $qJoin .
' ' .
669 'WHERE t0.child = %s ';
671 $types = array(
'integer',
'integer');
672 $data = array($this->
getTree()->getTreeId(), $parentId);
673 $query =
'SELECT ' . $qSelect .
' ' .
674 'FROM ' . $this->
getTree()->getTreeTable() .
' t0 ' . $qJoin .
' ' .
675 'WHERE t0.' . $this->
getTree()->getTreePk() .
' = %s ' .
676 'AND t0.child = %s ';
679 $this->db->setLimit(1, 0);
680 $res = $this->db->queryF($query, $types,
$data);
682 if (
$res->numRows() == 0) {
686 $row = $this->db->fetchAssoc(
$res);
688 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
690 $pathIds[] = $this->
getTree()->getRootId();
692 for ($i = $nodeDepth - 4; $i >= 0; $i--) {
693 $takeId = $takeId || $row[
'c' . $i] == $a_startnode_id;
695 $pathIds[] = (
int) $row[
'c' . $i];
698 $takeId = $takeId || $parentId == $a_startnode_id;
700 $pathIds[] = $parentId;
702 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
704 $pathIds[] = $a_endnode_id;
726 if ($this->
getTree()->__isMainTree()) {
727 $fields = array(
'integer');
728 $data = array($a_endnode_id);
729 $query =
"SELECT T2.child " .
730 "FROM " . $this->
getTree()->getTreeTable() .
" T1, " . $this->
getTree()->getTreeTable() .
" T2 " .
731 "WHERE T1.child = %s " .
732 "AND T1.lft BETWEEN T2.lft AND T2.rgt " .
735 $fields = array(
'integer',
'integer',
'integer');
736 $data = array($a_endnode_id, $this->
getTree()->getTreeId(), $this->
getTree()->getTreeId());
737 $query =
"SELECT T2.child " .
738 "FROM " . $this->
getTree()->getTreeTable() .
" T1, " . $this->
getTree()->getTreeTable() .
" T2 " .
739 "WHERE T1.child = %s " .
740 "AND T1.lft BETWEEN T2.lft AND T2.rgt " .
741 "AND T1." . $this->
getTree()->getTreePk() .
" = %s " .
742 "AND T2." . $this->
getTree()->getTreePk() .
" = %s " .
746 $res = $this->db->queryF($query, $fields,
$data);
748 $takeId = $a_startnode_id == 0;
750 while ($row = $this->db->fetchAssoc(
$res)) {
751 if ($takeId || $row[
'child'] == $a_startnode_id) {
753 $pathIds[] = (
int) $row[
'child'];
762 public function moveTree(
int $a_source_id,
int $a_target_id,
int $a_position): void
764 $move_tree_callable =
function (
ilDBInterface $ilDB) use ($a_source_id, $a_target_id, $a_position):
void {
766 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
767 'WHERE ( child = %s OR child = %s ) ' .
768 'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
769 $res = $this->db->queryF($query, array(
'integer',
'integer',
'integer'), array(
776 if (
$res->numRows() != 2) {
780 $source_lft = $target_lft = $source_rgt = $target_rgt = $source_depth = $target_depth = $source_parent = 0;
781 while ($row = $this->db->fetchObject(
$res)) {
782 if ($row->child == $a_source_id) {
783 $source_lft = $row->lft;
784 $source_rgt = $row->rgt;
785 $source_depth = $row->depth;
786 $source_parent = $row->parent;
788 $target_lft = $row->lft;
789 $target_rgt = $row->rgt;
790 $target_depth = $row->depth;
795 if ($target_lft >= $source_lft && $target_rgt <= $source_rgt) {
802 $spread_diff = $source_rgt - $source_lft + 1;
803 #var_dump("<pre>","SPREAD_DIFF: ",$spread_diff,"<pre>"); 805 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
806 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
807 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ';
809 if ($this->
getTree()->__isMainTree()) {
810 $res = $this->db->manipulateF($query, array(
'integer',
'integer',
'integer',
'integer'), [
817 $query .= (
'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ');
818 $res = $this->db->manipulateF(
820 array(
'integer',
'integer',
'integer',
'integer',
'integer'),
833 if ($source_lft > $target_rgt) {
834 $where_offset = $spread_diff;
835 $move_diff = $target_rgt - $source_lft - $spread_diff;
838 $move_diff = $target_rgt - $source_lft;
840 $depth_diff = $target_depth - $source_depth + 1;
842 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
843 'parent = CASE WHEN parent = %s THEN %s ELSE parent END, ' .
846 'depth = depth + %s ' .
850 if ($this->
getTree()->__isMainTree()) {
851 $res = $this->db->manipulateF(
853 array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
860 $source_lft + $where_offset,
861 $source_rgt + $where_offset
865 $query .=
'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
866 $res = $this->db->manipulateF(
868 array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
875 $source_lft + $where_offset,
876 $source_rgt + $where_offset,
883 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
884 'lft = CASE WHEN lft >= %s THEN lft - %s ELSE lft END, ' .
885 'rgt = CASE WHEN rgt >= %s THEN rgt - %s ELSE rgt END ';
887 if ($this->
getTree()->__isMainTree()) {
888 $res = $this->db->manipulateF($query, array(
'integer',
'integer',
'integer',
'integer'), [
889 $source_lft + $where_offset,
891 $source_rgt + $where_offset,
895 $query .= (
'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ');
897 $res = $this->db->manipulateF(
899 array(
'integer',
'integer',
'integer',
'integer',
'integer'),
901 $source_lft + $where_offset,
903 $source_rgt + $where_offset,
911 if ($this->
getTree()->__isMainTree()) {
912 $ilAtomQuery = $this->db->buildAtomQuery();
913 $ilAtomQuery->addTableLock(
'tree');
914 $ilAtomQuery->addQueryCallable($move_tree_callable);
917 $move_tree_callable($this->db);
927 $query =
"SELECT t2.lft lft, t2.rgt rgt, t2.child child, t2.parent parent, type " .
928 "FROM " . $this->
getTree()->getTreeTable() .
" t1 " .
929 "JOIN " . $this->
getTree()->getTreeTable() .
" t2 ON (t2.lft BETWEEN t1.lft AND t1.rgt) " .
930 "JOIN " . $this->
getTree()->getTableReference() .
" obr ON t2.child = obr.ref_id " .
931 "JOIN " . $this->
getTree()->getObjectDataTable() .
" obd ON obr.obj_id = obd.obj_id " .
932 "WHERE t1.child = " . $this->db->quote($a_endnode_id,
'integer') .
" " .
933 "AND t1." . $this->
getTree()->getTreePk() .
" = " . $this->db->quote(
937 "AND t2." . $this->
getTree()->getTreePk() .
" = " . $this->db->quote(
943 $res = $this->db->query($query);
946 $nodes[(
int) $row->child][
'lft'] = (
int) $row->lft;
947 $nodes[(
int) $row->child][
'rgt'] = (
int) $row->rgt;
948 $nodes[(
int) $row->child][
'child'] = (
int) $row->child;
949 $nodes[(
int) $row->child][
'parent'] = (
int) $row->parent;
950 $nodes[(
int) $row->child][
'type'] = (
string) $row->type;
962 $query =
'select ' . $this->
getTree()->getTreePk() .
', child from ' . $this->
getTree()->getTreeTable() .
' child where not exists ' .
964 'select child from ' . $this->
getTree()->getTreeTable() .
' parent where child.parent = parent.child and (parent.lft < child.lft) and (parent.rgt > child.rgt) ' .
966 'and ' . $this->
getTree()->getTreePk() .
' = ' . $this->
getTree()->getTreeId() .
' and child <> 1';
967 $res = $this->db->query($query);
971 $failures[] = $row[$this->
getTree()->getTreePk()];
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.
Base class for nested set path based trees.
getSubTreeIds(int $a_node_id)
Get subtree ids int[].
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.
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...