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 ' .
51 'AND s.lft > t.lft ' .
52 'AND s.rgt < t.rgt ' .
53 'AND s.' . $this->
getTree()->getTreePk() .
' = %s';
57 array(
'integer',
'integer'),
61 $childs[] =
$row->child;
63 return $childs ? $childs :
array();
75 public function getSubTreeQuery($a_node, $a_types =
'', $a_force_join_reference =
true, $a_fields =
array())
80 if (is_array($a_types)) {
82 $type_str =
"AND " . $ilDB->in($this->
getTree()->getObjectDataTable() .
".type", $a_types,
false,
"text");
84 } elseif (strlen($a_types)) {
85 $type_str =
"AND " . $this->
getTree()->getObjectDataTable() .
".type = " . $ilDB->quote($a_types,
"text");
89 if ($type_str or $a_force_join_reference) {
90 $join = $this->
getTree()->buildJoin();
94 if (count($a_fields)) {
95 $fields = implode(
',', $a_fields);
100 "FROM " . $this->
getTree()->getTreeTable() .
" " .
102 "WHERE " . $this->
getTree()->getTreeTable() .
'.lft ' .
103 'BETWEEN ' . $ilDB->quote($a_node[
'lft'],
'integer') .
' ' .
104 'AND ' . $ilDB->quote($a_node[
'rgt'],
'integer') .
' ' .
105 "AND " . $this->
getTree()->getTreeTable() .
"." . $this->
getTree()->getTreePk() .
" = " . $ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
' ' .
107 "ORDER BY " . $this->
getTree()->getTreeTable() .
".lft";
109 #ilLoggerFactory::getLogger('tree')->debug('-----------------: '. $query); 123 if ($a_node_a[
'child'] == $a_node_b[
'child']) {
127 if ($a_node_a[
'lft'] < $a_node_b[
'lft'] and $a_node_a[
'rgt'] > $a_node_b[
'rgt']) {
131 if ($a_node_b[
'lft'] < $a_node_a[
'lft'] and $a_node_b[
'rgt'] > $a_node_a[
'rgt']) {
137 if ($a_node_a[
'parent'] == $a_node_b[
'parent']) {
168 $insert_node_callable =
function (
ilDBInterface $ilDB) use ($a_node_id, $a_parent_id, $a_pos) {
174 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
175 'WHERE child = %s ' .
176 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
177 $ilDB->quote($a_parent_id,
'integer'),
178 $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
182 $r = $ilDB->fetchObject($res);
184 if (
$r->parent === null) {
195 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
196 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
197 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ' .
198 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
199 $ilDB->quote($left,
'integer'),
200 $ilDB->quote($left,
'integer'),
201 $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
203 $res = $ilDB->manipulate(
$query);
208 if ($this->
getTree()->getGap() > 0) {
211 'SELECT rgt,lft,parent FROM ' . $this->
getTree()->getTreeTable() .
' ' .
212 'WHERE child = %s ' .
213 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
214 $ilDB->quote($a_parent_id,
'integer'),
215 $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
217 $res = $ilDB->query(
$query);
218 $r = $ilDB->fetchAssoc($res);
220 if (
$r[
'parent'] === null) {
224 $parentRgt =
$r[
'rgt'];
225 $parentLft =
$r[
'lft'];
228 $availableSpace = $parentRgt - $parentLft;
229 if ($availableSpace < 2) {
238 'SELECT MAX(rgt) max_rgt FROM ' . $this->
getTree()->getTreeTable() .
' ' .
239 'WHERE parent = %s ' .
240 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
241 $ilDB->quote($a_parent_id,
'integer'),
242 $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
244 $res = $ilDB->query(
$query);
245 $r = $ilDB->fetchAssoc($res);
247 if (isset(
$r[
'max_rgt'])) {
250 $availableSpace = $parentRgt -
$r[
'max_rgt'];
251 $lft = $r[
'max_rgt'] + 1;
256 $lft = $parentLft + 1;
263 if ($availableSpace < 2) {
266 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
267 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
268 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ' .
269 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
270 $ilDB->quote($parentRgt,
'integer'),
271 $ilDB->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
272 $ilDB->quote($parentRgt,
'integer'),
273 $ilDB->quote((2 + $this->
getTree()->getGap() * 2),
'integer'),
274 $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
276 $res = $ilDB->manipulate(
$query);
284 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
285 'WHERE child = %s ' .
286 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
287 $ilDB->quote($a_parent_id,
'integer'),
288 $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
290 $res = $ilDB->query(
$query);
291 $r = $ilDB->fetchObject($res);
293 if (
$r->parent === null) {
304 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
305 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
306 'rgt = CASE WHEN rgt >= %s THEN rgt + 2 ELSE rgt END ' .
307 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s',
308 $ilDB->quote($right,
'integer'),
309 $ilDB->quote($right,
'integer'),
310 $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
312 $res = $ilDB->manipulate(
$query);
321 'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
322 'WHERE child = %s ' .
323 'AND ' . $this->
getTree()->getTreePk() .
' = %s ',
324 $ilDB->quote($a_pos,
'integer'),
325 $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
327 $res = $ilDB->query(
$query);
328 $r = $ilDB->fetchObject($res);
331 if (
$r->parent != $a_parent_id) {
342 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
343 'lft = CASE WHEN lft > %s THEN lft + 2 ELSE lft END, ' .
344 'rgt = CASE WHEN rgt > %s THEN rgt + 2 ELSE rgt END ' .
345 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s',
346 $ilDB->quote($right,
'integer'),
347 $ilDB->quote($right,
'integer'),
348 $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
350 $res = $ilDB->manipulate(
$query);
356 $depth = $this->
getTree()->getDepth($a_parent_id) + 1;
360 'INSERT INTO ' . $this->
getTree()->getTreeTable() .
' (' . $this->
getTree()->getTreePk() .
',child,parent,lft,rgt,depth) ' .
361 'VALUES (%s,%s,%s,%s,%s,%s)',
362 $ilDB->quote($this->getTree()->getTreeId(),
'integer'),
363 $ilDB->quote($a_node_id,
'integer'),
364 $ilDB->quote($a_parent_id,
'integer'),
365 $ilDB->quote($lft,
'integer'),
366 $ilDB->quote($rgt,
'integer'),
367 $ilDB->quote($depth,
'integer')
372 if ($this->
getTree()->__isMainTree()) {
373 $ilAtomQuery = $ilDB->buildAtomQuery();
374 $ilAtomQuery->addTableLock(
'tree');
375 $ilAtomQuery->addQueryCallable($insert_node_callable);
378 $insert_node_callable($ilDB);
396 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
397 'WHERE child = ' . $ilDB->quote($a_node_id,
'integer') .
' ' .
398 'AND ' . $this->
getTree()->getTreePk() .
' = ' . $ilDB->quote($this->
getTree()->getTreeId(),
'integer');
404 'DELETE FROM ' . $this->
getTree()->getTreeTable() .
' ' .
405 'WHERE lft BETWEEN %s AND %s ' .
406 'AND rgt BETWEEN %s AND %s ' .
407 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
408 $ilDB->quote($a_node[
'lft'],
'integer'),
409 $ilDB->quote($a_node[
'rgt'],
'integer'),
410 $ilDB->quote($a_node[
'lft'],
'integer'),
411 $ilDB->quote($a_node[
'rgt'],
'integer'),
412 $ilDB->quote($a_node[$this->
getTree()->getTreePk()],
'integer')
420 $diff = $a_node[
"rgt"] - $a_node[
"lft"] + 1;
422 $a_node[$this->
getTree()->getTreePk()] >= 0 &&
423 $a_node[
'rgt'] - $a_node[
'lft'] >= $this->
getTree()->getGap() * 2
427 'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
428 'lft = CASE WHEN lft > %s THEN lft - %s ELSE lft END, ' .
429 'rgt = CASE WHEN rgt > %s THEN rgt - %s ELSE rgt END ' .
430 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ',
431 $ilDB->quote($a_node[
'lft'],
'integer'),
432 $ilDB->quote($diff,
'integer'),
433 $ilDB->quote($a_node[
'lft'],
'integer'),
434 $ilDB->quote($diff,
'integer'),
435 $ilDB->quote($a_node[$this->
getTree()->getTreePk()],
'integer')
438 $res = $ilDB->manipulate(
$query);
443 if ($this->
getTree()->__isMainTree()) {
444 $ilAtomQuery = $ilDB->buildAtomQuery();
445 $ilAtomQuery->addTableLock(
'tree');
446 $ilAtomQuery->addQueryCallable($delete_tree_callable);
449 $delete_tree_callable($ilDB);
468 $node = $this->
getTree()->getNodeTreeData($a_node_id);
470 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' ' .
471 'SET tree = ' . $ilDB->quote(-1 * $node[
'child'],
'integer') .
' ' .
472 'WHERE ' . $this->
getTree()->getTreePk() .
' = ' . $ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
' ' .
473 'AND lft BETWEEN ' . $ilDB->quote($node[
'lft'],
'integer') .
' AND ' . $ilDB->quote($node[
'rgt'],
'integer') .
' ';
475 $ilDB->manipulate(
$query);
480 if ($this->
getTree()->__isMainTree()) {
481 $ilAtomQuery = $ilDB->buildAtomQuery();
482 $ilAtomQuery->addTableLock(
"tree");
484 $ilAtomQuery->addQueryCallable($move_to_trash_callable);
488 $move_to_trash_callable($ilDB);
512 $takeId = $a_startnode_id == 0;
514 $depth_cache = $this->
getTree()->getDepthCache();
515 $parent_cache = $this->
getTree()->getParentCache();
518 $this->
getTree()->__isMainTree() &&
519 isset($depth_cache[$a_endnode_id]) &&
520 isset($parent_cache[$a_endnode_id])) {
521 $nodeDepth = $depth_cache[$a_endnode_id];
522 $parentId = $parent_cache[$a_endnode_id];
524 $nodeDepth = $this->
getTree()->getDepth($a_endnode_id);
525 $parentId = $this->
getTree()->getParentId($a_endnode_id);
534 } elseif ($nodeDepth == 1) {
535 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
537 $pathIds[] = $a_endnode_id;
539 } elseif ($nodeDepth == 2) {
540 $takeId = $takeId || $parentId == $a_startnode_id;
542 $pathIds[] = $parentId;
544 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
546 $pathIds[] = $a_endnode_id;
548 } elseif ($nodeDepth == 3) {
549 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
551 $pathIds[] = $this->
getTree()->getRootId();
553 $takeId = $takeId || $parentId == $a_startnode_id;
555 $pathIds[] = $parentId;
557 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
559 $pathIds[] = $a_endnode_id;
561 } elseif ($nodeDepth < 32) {
571 $qSelect =
't1.child c0';
573 for (
$i = 1;
$i < $nodeDepth - 2;
$i++) {
574 $qSelect .=
', t' .
$i .
'.parent c' .
$i;
575 $qJoin .=
' JOIN ' . $this->
getTree()->getTreeTable() .
' t' .
$i .
' ON ' .
576 't' .
$i .
'.child=t' . (
$i - 1) .
'.parent AND ' .
577 't' .
$i .
'.' . $this->
getTree()->getTreePk() .
' = ' . (int) $this->
getTree()->getTreeId();
580 $types =
array(
'integer',
'integer');
582 $query =
'SELECT ' . $qSelect .
' ' .
583 'FROM ' . $this->
getTree()->getTreeTable() .
' t0 ' . $qJoin .
' ' .
584 'WHERE t0.' . $this->
getTree()->getTreePk() .
' = %s ' .
585 'AND t0.child = %s ';
590 if (
$res->numRows() == 0) {
596 $takeId = $takeId || $this->
getTree()->getRootId() == $a_startnode_id;
598 $pathIds[] = $this->
getTree()->getRootId();
600 for (
$i = $nodeDepth - 4;
$i >=0;
$i--) {
601 $takeId = $takeId ||
$row[
'c' .
$i] == $a_startnode_id;
603 $pathIds[] =
$row[
'c' .
$i];
606 $takeId = $takeId || $parentId == $a_startnode_id;
608 $pathIds[] = $parentId;
610 $takeId = $takeId || $a_endnode_id == $a_startnode_id;
612 $pathIds[] = $a_endnode_id;
639 $fields =
array(
'integer',
'integer',
'integer');
642 $query =
"SELECT T2.child " .
643 "FROM " . $this->
getTree()->getTreeTable() .
" T1, " . $this->
getTree()->getTreeTable() .
" T2 " .
644 "WHERE T1.child = %s " .
645 "AND T1.lft BETWEEN T2.lft AND T2.rgt " .
646 "AND T1." . $this->
getTree()->getTreePk() .
" = %s " .
647 "AND T2." . $this->
getTree()->getTreePk() .
" = %s " .
652 $takeId = $a_startnode_id == 0;
653 while (
$row = $ilDB->fetchAssoc(
$res)) {
654 if ($takeId ||
$row[
'child'] == $a_startnode_id) {
656 $pathIds[] =
$row[
'child'];
659 return $pathIds ? $pathIds :
array();
671 public function moveTree($a_source_id, $a_target_id, $a_position)
675 $move_tree_callable =
function (
ilDBInterface $ilDB) use ($a_source_id, $a_target_id, $a_position) {
677 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
678 'WHERE ( child = %s OR child = %s ) ' .
679 'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
683 $this->
getTree()->getTreeId()));
686 if (
$res->numRows() != 2) {
690 while (
$row = $ilDB->fetchObject(
$res)) {
691 if (
$row->child == $a_source_id) {
692 $source_lft =
$row->lft;
693 $source_rgt =
$row->rgt;
694 $source_depth =
$row->depth;
695 $source_parent =
$row->parent;
697 $target_lft =
$row->lft;
698 $target_rgt =
$row->rgt;
699 $target_depth =
$row->depth;
704 if ($target_lft >= $source_lft and $target_rgt <= $source_rgt) {
711 $spread_diff = $source_rgt - $source_lft + 1;
712 #var_dump("<pre>","SPREAD_DIFF: ",$spread_diff,"<pre>"); 714 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
715 'lft = CASE WHEN lft > %s THEN lft + %s ELSE lft END, ' .
716 'rgt = CASE WHEN rgt >= %s THEN rgt + %s ELSE rgt END ' .
717 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ';
718 $res = $ilDB->manipulateF(
$query,
array(
'integer',
'integer',
'integer',
'integer',
'integer'),
array(
723 $this->
getTree()->getTreeId()));
727 if ($source_lft > $target_rgt) {
728 $where_offset = $spread_diff;
729 $move_diff = $target_rgt - $source_lft - $spread_diff;
732 $move_diff = $target_rgt - $source_lft;
734 $depth_diff = $target_depth - $source_depth + 1;
737 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
738 'parent = CASE WHEN parent = %s THEN %s ELSE parent END, ' .
741 'depth = depth + %s ' .
744 'AND ' . $this->
getTree()->getTreePk() .
' = %s ';
745 $res = $ilDB->manipulateF(
$query,
array(
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer'),
array(
751 $source_lft + $where_offset,
752 $source_rgt + $where_offset,
753 $this->
getTree()->getTreeId()));
756 $query =
'UPDATE ' . $this->
getTree()->getTreeTable() .
' SET ' .
757 'lft = CASE WHEN lft >= %s THEN lft - %s ELSE lft END, ' .
758 'rgt = CASE WHEN rgt >= %s THEN rgt - %s ELSE rgt END ' .
759 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ';
761 $res = $ilDB->manipulateF(
$query,
array(
'integer',
'integer',
'integer',
'integer',
'integer'),
array(
762 $source_lft + $where_offset,
764 $source_rgt + $where_offset,
766 $this->
getTree()->getTreeId()));
770 if ($this->
getTree()->__isMainTree()) {
771 $ilAtomQuery = $ilDB->buildAtomQuery();
772 $ilAtomQuery->addTableLock(
'tree');
773 $ilAtomQuery->addQueryCallable($move_tree_callable);
776 $move_tree_callable($ilDB);
790 $query =
"SELECT t2.lft lft, t2.rgt rgt, t2.child child, type " .
791 "FROM " . $this->
getTree()->getTreeTable() .
" t1 " .
792 "JOIN " . $this->
getTree()->getTreeTable() .
" t2 ON (t2.lft BETWEEN t1.lft AND t1.rgt) " .
793 "JOIN " . $this->
getTree()->getTableReference() .
" obr ON t2.child = obr.ref_id " .
794 "JOIN " . $this->
getTree()->getObjectDataTable() .
" obd ON obr.obj_id = obd.obj_id " .
795 "WHERE t1.child = " . $ilDB->quote($a_endnode_id,
'integer') .
" " .
796 "AND t1." . $this->
getTree()->getTreePk() .
" = " . $ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
" " .
797 "AND t2." . $this->
getTree()->getTreePk() .
" = " . $ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
" " .
806 $nodes[
$row->child][
'lft'] =
$row->lft;
807 $nodes[
$row->child][
'rgt'] =
$row->rgt;
808 $nodes[
$row->child][
'child']=
$row->child;
809 $nodes[
$row->child][
'type'] =
$row->type;
811 return (
array) $nodes;
821 $query =
'select child from ' . $this->
getTree()->getTreeTable() .
' child where not exists ' .
823 'select child from ' . $this->
getTree()->getTreeTable() .
' parent where child.parent = parent.child and (parent.lft < child.lft) and (parent.rgt > child.rgt) ' .
825 '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.
foreach($_POST as $key=> $value) $res
__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.