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)) {
   998             $message = 
"No node_id given!";
  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)) {
  1093             $message = 
"No node_id given!";
  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[]. 
 
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...