4 include_once
'./Services/Tree/interfaces/interface.ilTreeImplementation.php';
26 $this->tree = $a_tree;
47 $query =
'SELECT s.child FROM '.
48 $this->
getTree()->getTreeTable().
' s, '.
49 $this->
getTree()->getTreeTable().
' t '.
50 'WHERE t.child = %s '.
53 'AND s.'.$this->getTree()->getTreePk().
' = %s';
57 array(
'integer',
'integer'),
62 $childs[] =
$row->child;
64 return $childs ? $childs :
array();
76 public function getSubTreeQuery($a_node, $a_types =
'', $a_force_join_reference =
true, $a_fields =
array())
81 if (is_array($a_types))
85 $type_str =
"AND ".$ilDB->in($this->
getTree()->getObjectDataTable().
".type", $a_types,
false,
"text");
88 else if(strlen($a_types))
90 $type_str =
"AND ".$this->getTree()->getObjectDataTable().
".type = ".$ilDB->quote($a_types,
"text");
94 if($type_str
or $a_force_join_reference)
96 $join = $this->
getTree()->buildJoin();
102 $fields = implode(
',',$a_fields);
107 "FROM ".$this->getTree()->getTreeTable().
" ".
109 "WHERE ".$this->getTree()->getTreeTable().
'.lft '.
110 'BETWEEN '.$ilDB->quote($a_node[
'lft'],
'integer').
' '.
111 'AND '.$ilDB->quote($a_node[
'rgt'],
'integer').
' '.
112 "AND ".$this->getTree()->getTreeTable().
".".$this->
getTree()->getTreePk().
" = ".$ilDB->quote($this->
getTree()->getTreeId(),
'integer').
' '.
114 "ORDER BY ".$this->getTree()->getTreeTable().
".lft";
116 #ilLoggerFactory::getLogger('tree')->debug('-----------------: '. $query); 130 if($a_node_a[
'child'] == $a_node_b[
'child'])
135 if($a_node_a[
'lft'] < $a_node_b[
'lft']
and $a_node_a[
'rgt'] > $a_node_b[
'rgt'])
140 if($a_node_b[
'lft'] < $a_node_a[
'lft']
and $a_node_b[
'rgt'] > $a_node_a[
'rgt'])
147 if($a_node_a[
'parent'] == $a_node_b[
'parent'])
179 $insert_node_callable =
function(
ilDBInterface $ilDB) use($a_node_id, $a_parent_id, $a_pos)
186 $query = sprintf(
'SELECT * FROM '.$this->
getTree()->getTreeTable().
' '.
188 'AND '.$this->
getTree()->getTreePk().
' = %s ',
189 $ilDB->quote($a_parent_id,
'integer'),
190 $ilDB->quote($this->
getTree()->getTreeId(),
'integer'));
193 $r = $ilDB->fetchObject($res);
195 if (
$r->parent == NULL)
206 $query = sprintf(
'UPDATE '.$this->
getTree()->getTreeTable().
' SET '.
207 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, '.
208 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END '.
209 'WHERE '.$this->
getTree()->getTreePk().
' = %s ',
210 $ilDB->quote($left,
'integer'),
211 $ilDB->quote($left,
'integer'),
212 $ilDB->quote($this->
getTree()->getTreeId(),
'integer'));
213 $res = $ilDB->manipulate(
$query);
218 if ($this->
getTree()->getGap() > 0)
221 $query = sprintf(
'SELECT rgt,lft,parent FROM '.$this->
getTree()->getTreeTable().
' '.
223 'AND '.$this->
getTree()->getTreePk().
' = %s',
224 $ilDB->quote($a_parent_id,
'integer'),
225 $ilDB->quote($this->
getTree()->getTreeId(),
'integer'));
226 $res = $ilDB->query(
$query);
227 $r = $ilDB->fetchAssoc($res);
229 if (
$r[
'parent'] == null)
234 $parentRgt =
$r[
'rgt'];
235 $parentLft =
$r[
'lft'];
238 $availableSpace = $parentRgt - $parentLft;
239 if ($availableSpace < 2)
250 $query = sprintf(
'SELECT MAX(rgt) max_rgt FROM '.$this->
getTree()->getTreeTable().
' '.
251 'WHERE parent = %s '.
252 'AND '.$this->
getTree()->getTreePk().
' = %s',
253 $ilDB->quote($a_parent_id,
'integer'),
254 $ilDB->quote($this->
getTree()->getTreeId(),
'integer'));
255 $res = $ilDB->query(
$query);
256 $r = $ilDB->fetchAssoc($res);
258 if (isset(
$r[
'max_rgt']))
262 $availableSpace = $parentRgt -
$r[
'max_rgt'];
263 $lft = $r[
'max_rgt'] + 1;
270 $lft = $parentLft + 1;
277 if ($availableSpace < 2)
280 $query = sprintf(
'UPDATE '.$this->
getTree()->getTreeTable().
' SET '.
281 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, '.
282 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END '.
283 'WHERE '.$this->
getTree()->getTreePk().
' = %s ',
284 $ilDB->quote($parentRgt,
'integer'),
285 $ilDB->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
286 $ilDB->quote($parentRgt,
'integer'),
287 $ilDB->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
288 $ilDB->quote($this->
getTree()->getTreeId(),
'integer'));
289 $res = $ilDB->manipulate(
$query);
297 $query = sprintf(
'SELECT * FROM '.$this->
getTree()->getTreeTable().
' '.
299 'AND '.$this->
getTree()->getTreePk().
' = %s ',
300 $ilDB->quote($a_parent_id,
'integer'),
301 $ilDB->quote($this->
getTree()->getTreeId(),
'integer'));
302 $res = $ilDB->query(
$query);
303 $r = $ilDB->fetchObject($res);
305 if (
$r->parent == null)
316 $query = sprintf(
'UPDATE '.$this->
getTree()->getTreeTable().
' SET '.
317 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, '.
318 'rgt = CASE WHEN rgt >= %s THEN rgt + 2 ELSE rgt END '.
319 'WHERE '.$this->
getTree()->getTreePk().
' = %s',
320 $ilDB->quote($right,
'integer'),
321 $ilDB->quote($right,
'integer'),
322 $ilDB->quote($this->
getTree()->getTreeId(),
'integer'));
323 $res = $ilDB->manipulate(
$query);
331 $query = sprintf(
'SELECT * FROM '.$this->
getTree()->getTreeTable().
' '.
333 'AND '.$this->
getTree()->getTreePk().
' = %s ',
334 $ilDB->quote($a_pos,
'integer'),
335 $ilDB->quote($this->
getTree()->getTreeId(),
'integer'));
336 $res = $ilDB->query(
$query);
337 $r = $ilDB->fetchObject($res);
340 if (
$r->parent != $a_parent_id)
351 $query = sprintf(
'UPDATE '.$this->
getTree()->getTreeTable().
' SET '.
352 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, '.
353 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END '.
354 'WHERE '.$this->
getTree()->getTreePk().
' = %s',
355 $ilDB->quote($right,
'integer'),
356 $ilDB->quote($right,
'integer'),
357 $ilDB->quote($this->
getTree()->getTreeId(),
'integer'));
358 $res = $ilDB->manipulate(
$query);
364 $depth = $this->
getTree()->getDepth($a_parent_id) + 1;
367 $query = sprintf(
'INSERT INTO '.$this->
getTree()->getTreeTable().
' ('.$this->
getTree()->getTreePk().
',child,parent,lft,rgt,depth) '.
368 'VALUES (%s,%s,%s,%s,%s,%s)',
369 $ilDB->quote($this->getTree()->getTreeId(),
'integer'),
370 $ilDB->quote($a_node_id,
'integer'),
371 $ilDB->quote($a_parent_id,
'integer'),
372 $ilDB->quote($lft,
'integer'),
373 $ilDB->quote($rgt,
'integer'),
374 $ilDB->quote($depth,
'integer'));
378 if($this->
getTree()->__isMainTree())
380 $ilAtomQuery = $ilDB->buildAtomQuery();
381 $ilAtomQuery->addTableLock(
'tree');
382 $ilAtomQuery->addQueryCallable($insert_node_callable);
386 $insert_node_callable($ilDB);
405 $query =
'SELECT * FROM '.$this->getTree()->getTreeTable().
' '.
406 'WHERE child = '.$ilDB->quote($a_node_id,
'integer').
' '.
407 'AND '.$this->getTree()->getTreePk().
' = '.$ilDB->quote($this->
getTree()->getTreeId(),
'integer');
412 $query = sprintf(
'DELETE FROM '.$this->
getTree()->getTreeTable().
' '.
413 'WHERE lft BETWEEN %s AND %s '.
414 'AND rgt BETWEEN %s AND %s '.
415 'AND '.$this->
getTree()->getTreePk().
' = %s',
416 $ilDB->quote($a_node[
'lft'],
'integer'),
417 $ilDB->quote($a_node[
'rgt'],
'integer'),
418 $ilDB->quote($a_node[
'lft'],
'integer'),
419 $ilDB->quote($a_node[
'rgt'],
'integer'),
420 $ilDB->quote($a_node[$this->
getTree()->getTreePk()],
'integer'));
427 $diff = $a_node[
"rgt"] - $a_node[
"lft"] + 1;
429 $a_node[$this->
getTree()->getTreePk()] >= 0 &&
430 $a_node[
'rgt'] - $a_node[
'lft'] >= $this->
getTree()->getGap() * 2
434 $query = sprintf(
'UPDATE '.$this->
getTree()->getTreeTable().
' SET '.
435 'lft = CASE WHEN lft > %s THEN lft - %s ELSE lft END, '.
436 'rgt = CASE WHEN rgt > %s THEN rgt - %s ELSE rgt END '.
437 'WHERE '.$this->
getTree()->getTreePk().
' = %s ',
438 $ilDB->quote($a_node[
'lft'],
'integer'),
439 $ilDB->quote($diff,
'integer'),
440 $ilDB->quote($a_node[
'lft'],
'integer'),
441 $ilDB->quote($diff,
'integer'),
442 $ilDB->quote($a_node[$this->
getTree()->getTreePk()],
'integer'));
444 $res = $ilDB->manipulate(
$query);
450 if($this->
getTree()->__isMainTree())
452 $ilAtomQuery = $ilDB->buildAtomQuery();
453 $ilAtomQuery->addTableLock(
'tree');
454 $ilAtomQuery->addQueryCallable($delete_tree_callable);
458 $delete_tree_callable($ilDB);
478 $node = $this->
getTree()->getNodeTreeData($a_node_id);
480 $query =
'UPDATE '.$this->getTree()->getTreeTable().
' '.
481 'SET tree = '.$ilDB->quote(-1 * $node[
'child'],
'integer').
' '.
482 'WHERE '.$this->getTree()->getTreePk().
' = '.$ilDB->quote($this->
getTree()->getTreeId(),
'integer').
' '.
483 'AND lft BETWEEN '.$ilDB->quote($node[
'lft'],
'integer').
' AND '.$ilDB->quote($node[
'rgt'],
'integer').
' ';
485 $ilDB->manipulate(
$query);
490 if ($this->
getTree()->__isMainTree())
492 $ilAtomQuery = $ilDB->buildAtomQuery();
493 $ilAtomQuery->addTableLock(
"tree");
495 $ilAtomQuery->addQueryCallable($move_to_trash_callable);
501 $move_to_trash_callable($ilDB);
525 $takeId = $a_startnode_id == 0;
527 $depth_cache = $this->
getTree()->getDepthCache();
528 $parent_cache = $this->
getTree()->getParentCache();
531 $this->
getTree()->__isMainTree() &&
532 isset($depth_cache[$a_endnode_id]) &&
533 isset($parent_cache[$a_endnode_id]))
535 $nodeDepth = $depth_cache[$a_endnode_id];
536 $parentId = $parent_cache[$a_endnode_id];
540 $nodeDepth = $this->
getTree()->getDepth($a_endnode_id);
541 $parentId = $this->
getTree()->getParentId($a_endnode_id);
552 else if ($nodeDepth == 1)
554 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
555 if ($takeId) $pathIds[] = $a_endnode_id;
557 else if ($nodeDepth == 2)
559 $takeId = $takeId || $parentId == $a_startnode_id;
560 if ($takeId) $pathIds[] = $parentId;
561 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
562 if ($takeId) $pathIds[] = $a_endnode_id;
564 else if ($nodeDepth == 3)
566 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
567 if ($takeId) $pathIds[] = $this->
getTree()->getRootId();
568 $takeId = $takeId || $parentId == $a_startnode_id;
569 if ($takeId) $pathIds[] = $parentId;
570 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
571 if ($takeId) $pathIds[] = $a_endnode_id;
573 else if ($nodeDepth < 32)
584 $qSelect =
't1.child c0';
586 for ($i = 1; $i < $nodeDepth - 2; $i++)
588 $qSelect .=
', t'.$i.
'.parent c'.$i;
589 $qJoin .=
' JOIN '.$this->getTree()->getTreeTable().
' t'.$i.
' ON '.
590 't'.$i.
'.child=t'.($i - 1).
'.parent AND '.
591 't'.$i.
'.'.$this->getTree()->getTreePk().
' = '.(int) $this->
getTree()->getTreeId();
594 $types =
array(
'integer',
'integer');
596 $query =
'SELECT '.$qSelect.
' '.
597 'FROM '.$this->getTree()->getTreeTable().
' t0 '.$qJoin.
' '.
598 'WHERE t0.'.$this->getTree()->getTreePk().
' = %s '.
599 'AND t0.child = %s ';
604 if (
$res->numRows() == 0)
611 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
612 if ($takeId) $pathIds[] = $this->
getTree()->getRootId();
613 for ($i = $nodeDepth - 4; $i >=0; $i--)
615 $takeId = $takeId ||
$row[
'c'.$i] == $a_startnode_id;
616 if ($takeId) $pathIds[] =
$row[
'c'.$i];
618 $takeId = $takeId || $parentId == $a_startnode_id;
619 if ($takeId) $pathIds[] = $parentId;
620 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
621 if ($takeId) $pathIds[] = $a_endnode_id;
649 $fields =
array(
'integer',
'integer',
'integer');
652 $query =
"SELECT T2.child ".
653 "FROM ".$this->getTree()->getTreeTable().
" T1, ".$this->
getTree()->getTreeTable().
" T2 ".
654 "WHERE T1.child = %s ".
655 "AND T1.lft BETWEEN T2.lft AND T2.rgt ".
656 "AND T1.".$this->getTree()->getTreePk().
" = %s ".
657 "AND T2.".$this->getTree()->getTreePk().
" = %s ".
662 $takeId = $a_startnode_id == 0;
663 while(
$row = $ilDB->fetchAssoc(
$res))
665 if ($takeId ||
$row[
'child'] == $a_startnode_id)
668 $pathIds[] =
$row[
'child'];
671 return $pathIds ? $pathIds :
array();
683 public function moveTree($a_source_id, $a_target_id, $a_position)
687 $move_tree_callable =
function(
ilDBInterface $ilDB) use ($a_source_id, $a_target_id, $a_position)
690 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
691 'WHERE ( child = %s OR child = %s ) ' .
692 'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
696 $this->
getTree()->getTreeId()));
699 if (
$res->numRows() != 2)
704 while (
$row = $ilDB->fetchObject(
$res))
706 if (
$row->child == $a_source_id)
708 $source_lft =
$row->lft;
709 $source_rgt =
$row->rgt;
710 $source_depth =
$row->depth;
711 $source_parent =
$row->parent;
715 $target_lft =
$row->lft;
716 $target_rgt =
$row->rgt;
717 $target_depth =
$row->depth;
722 if ($target_lft >= $source_lft
and $target_rgt <= $source_rgt)
730 $spread_diff = $source_rgt - $source_lft + 1;
731 #var_dump("<pre>","SPREAD_DIFF: ",$spread_diff,"<pre>"); 733 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
734 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
735 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ' .
736 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ';
737 $res = $ilDB->manipulateF(
$query,
array(
'integer',
'integer',
'integer',
'integer',
'integer'),
array(
742 $this->
getTree()->getTreeId()));
746 if ($source_lft > $target_rgt)
748 $where_offset = $spread_diff;
749 $move_diff = $target_rgt - $source_lft - $spread_diff;
754 $move_diff = $target_rgt - $source_lft;
756 $depth_diff = $target_depth - $source_depth + 1;
759 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
760 'parent = CASE WHEN parent = %s THEN %s ELSE parent END, ' .
763 'depth = depth + %s ' .
766 'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
767 $res = $ilDB->manipulateF(
$query,
array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
array(
773 $source_lft + $where_offset,
774 $source_rgt + $where_offset,
775 $this->
getTree()->getTreeId()));
778 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
779 'lft = CASE WHEN lft >= %s THEN lft - %s ELSE lft END, ' .
780 'rgt = CASE WHEN rgt >= %s THEN rgt - %s ELSE rgt END ' .
781 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ';
783 $res = $ilDB->manipulateF(
$query,
array(
'integer',
'integer',
'integer',
'integer',
'integer'),
array(
784 $source_lft + $where_offset,
786 $source_rgt + $where_offset,
788 $this->
getTree()->getTreeId()));
792 if ($this->
getTree()->__isMainTree())
795 $ilAtomQuery = $ilDB->buildAtomQuery();
796 $ilAtomQuery->addTableLock(
'tree');
797 $ilAtomQuery->addQueryCallable($move_tree_callable);
802 $move_tree_callable($ilDB);
816 $query =
"SELECT t2.lft lft, t2.rgt rgt, t2.child child, type ".
817 "FROM ".$this->getTree()->getTreeTable().
" t1 ".
818 "JOIN ".$this->getTree()->getTreeTable().
" t2 ON (t2.lft BETWEEN t1.lft AND t1.rgt) ".
819 "JOIN ".$this->getTree()->getTableReference().
" obr ON t2.child = obr.ref_id ".
820 "JOIN ".$this->getTree()->getObjectDataTable().
" obd ON obr.obj_id = obd.obj_id ".
821 "WHERE t1.child = ".$ilDB->quote($a_endnode_id,
'integer').
" ".
822 "AND t1.".$this->getTree()->getTreePk().
" = ".$ilDB->quote($this->
getTree()->getTreeId(),
'integer').
" ".
823 "AND t2.".$this->getTree()->getTreePk().
" = ".$ilDB->quote($this->
getTree()->getTreeId(),
'integer').
" ".
833 $nodes[
$row->child][
'lft'] =
$row->lft;
834 $nodes[
$row->child][
'rgt'] =
$row->rgt;
835 $nodes[
$row->child][
'child']=
$row->child;
836 $nodes[
$row->child][
'type'] =
$row->type;
839 return (
array) $nodes;
849 $query =
'select child from '.$this->getTree()->getTreeTable().
' child where not exists '.
851 'select child from '.$this->getTree()->getTreeTable().
' parent where child.parent = parent.child and (parent.lft < child.lft) and (parent.rgt > child.rgt) '.
853 'and '.$this->getTree()->getTreePk().
' = '.$this->
getTree()->getTreeId().
' and child <> 1';
Thrown if invalid tree strucutes are found.
getPathIdsUsingNestedSets($a_endnode_id, $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
getPathIdsUsingAdjacencyMap($a_endnode_id, $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
getPathIds($a_endnode, $a_startnode=0)
Get path ids.
getRelation($a_node_a, $a_node_b)
Get relation.
getSubTreeIds($a_node_id)
Get subtree ids.
getTree()
Get tree object.
Base class for nested set path based trees.
moveTree($a_source_id, $a_target_id, $a_position)
Move source subtree to target.
insertNode($a_node_id, $a_parent_id, $a_pos)
Insert tree node.
__construct(ilTree $a_tree)
Constructor.
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
Create styles array
The data for the language used.
getSubtreeInfo($a_endnode_id)
Get rbac subtree info type $ilDB.
deleteTree($a_node_id)
Delete a subtree.
getSubTreeQuery($a_node, $a_types='', $a_force_join_reference=true, $a_fields=array())
Get subtree.
validateParentRelations()
Validate the parent relations of the tree implementation For nested set, validate the lft...
static getLogger($a_component_id)
Get component logger.
moveToTrash($a_node_id)
Move to trash.
Interface for tree implementations Currrently nested set or materialize path.