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...