4include_once
'./Services/Tree/interfaces/interface.ilTreeImplementation.php';
27 $this->tree = $a_tree;
58 $node = $this->
getTree()->getNodeTreeData($a_node_id);
59 $query =
'SELECT child FROM ' . $this->
getTree()->getTreeTable() .
' ' .
60 'WHERE path BETWEEN ' .
61 $ilDB->quote($node[
'path'],
'text') .
' AND ' .
62 $ilDB->quote($node[
'path'] .
'.Z',
'text') .
' ' .
64 'AND ' . $this->
getTree()->getTreePk() .
' = %s';
68 array(
'integer',
'integer'),
69 array($a_node_id, $this->
getTree()->getTreeId())
72 $childs[] =
$row[
'child'];
74 return $childs ? $childs : array();
85 if ($a_node_a[
'child'] == $a_node_b[
'child']) {
89 if (stripos($a_node_a[
'path'], $a_node_b[
'path'] .
'.') === 0) {
93 if (stripos($a_node_b[
'path'], $a_node_a[
'path'] .
'.') === 0) {
97 $path_a = substr($a_node_a[
'path'], 0, strrpos($a_node_a[
'path'],
'.'));
98 $path_b = substr($a_node_b[
'path'], 0, strrpos($a_node_b[
'path'],
'.'));
102 if ($a_node_a[
'path'] and (strcmp($path_a, $path_b) === 0)) {
120 public function getSubTreeQuery($a_node, $a_types =
'', $a_force_join_reference =
true, $a_fields = array())
125 if (is_array($a_types)) {
127 $type_str =
"AND " .
$ilDB->in($this->
getTree()->getObjectDataTable() .
".type", $a_types,
false,
"text");
129 } elseif (strlen($a_types)) {
130 $type_str =
"AND " . $this->
getTree()->getObjectDataTable() .
".type = " . $ilDB->quote($a_types,
"text");
134 if ($type_str or $a_force_join_reference) {
135 $join = $this->
getTree()->buildJoin();
139 if (count($a_fields)) {
140 $fields = implode(
',', $a_fields);
146 'FROM ' . $this->
getTree()->getTreeTable() .
' ' .
148 'WHERE ' . $this->
getTree()->getTreeTable() .
'.path ' .
150 $ilDB->quote($a_node[
'path'],
'text') .
' AND ' .
151 $ilDB->quote($a_node[
'path'] .
'.Z',
'text') .
' ' .
152 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = ' . $ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
' ' .
154 'ORDER BY ' . $this->
getTree()->getTreeTable() .
'.path';
170 $query =
'SELECT path FROM ' . $this->
getTree()->getTreeTable() .
' ' .
171 'WHERE child = ' . $ilDB->quote($a_endnode,
'integer') .
' ';
179 $pathIds = explode(
'.',
$path);
181 if ($a_startnode != 0) {
182 while (count($pathIds) > 0 && $pathIds[0] != $a_startnode) {
183 array_shift($pathIds);
201 $insert_node_callable =
function (
ilDBInterface $ilDB) use ($a_node_id, $a_parent_id, $a_pos) {
206 'SELECT parent, depth, path FROM ' . $this->
getTree()->getTreeTable() .
' ' .
207 'WHERE child = %s ' .
' ' .
208 'AND ' . $this->
getTree()->getTreePk() .
' = %s',
209 array(
'integer',
'integer'),
210 array($a_parent_id, $this->
getTree()->getTreeId())
216 if (
$r->parent ===
null) {
221 if (
$r->depth >= $this->getMaximumPossibleDepth()) {
226 $parentPath =
$r->path;
227 $depth =
$r->depth + 1;
232 $ilDB->insert($this->
getTree()->getTreeTable(), array($this->
getTree()->getTreePk() => array(
'integer', $this->
getTree()->getTreeId()),
233 'child' => array(
'integer', $a_node_id),
234 'parent' => array(
'integer', $a_parent_id),
235 'lft' => array(
'integer', $lft),
236 'rgt' => array(
'integer', $rgt),
237 'depth' => array(
'integer', $depth),
238 'path' => array(
'text', $parentPath .
"." . $a_node_id)));
243 if ($this->
getTree()->__isMainTree()) {
244 $ilAtomQuery =
$ilDB->buildAtomQuery();
245 $ilAtomQuery->addTableLock(
"tree");
247 $ilAtomQuery->addQueryCallable($insert_node_callable);
251 $insert_node_callable(
$ilDB);
266 $query =
'SELECT * FROM ' . $this->
getTree()->getTreeTable() .
' ' .
267 'WHERE ' . $this->
getTree()->getTreeTable() .
'.child = %s ' .
268 'AND ' . $this->
getTree()->getTreeTable() .
'.' . $this->
getTree()->getTreePk() .
' = %s ';
269 $res = $ilDB->queryF(
$query, array(
'integer',
'integer'), array(
271 $this->
getTree()->getTreeId()));
274 $query =
'DELETE FROM ' . $this->
getTree()->getTreeTable() .
' ' .
275 'WHERE path BETWEEN ' . $ilDB->quote(
$row[
'path'],
'text') .
' ' .
276 'AND ' .
$ilDB->quote(
$row[
'path'] .
'.Z',
'text') .
' ' .
277 'AND ' . $this->
getTree()->getTreePk() .
' = ' . $ilDB->quote($this->
getTree()->getTreeId(),
'integer');
282 if ($this->
getTree()->__isMainTree()) {
283 $ilAtomQuery =
$ilDB->buildAtomQuery();
284 $ilAtomQuery->addTableLock(
'tree');
285 $ilAtomQuery->addQueryCallable($delete_tree_callable);
288 $delete_tree_callable(
$ilDB);
305 $node = $this->
getTree()->getNodeTreeData($a_node_id);
310 UPDATE ' . $this->
getTree()->getTreeTable() .
' ' .
311 'SET tree = %s' .
' ' .
312 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ' .
313 'AND path BETWEEN %s AND %s',
314 array(
'integer',
'integer',
'text',
'text'),
315 array(-$a_node_id, $this->
getTree()->getTreeId(), $node[
'path'], $node[
'path'] .
'.Z')
321 if ($this->
getTree()->__isMainTree()) {
322 $ilAtomQuery =
$ilDB->buildAtomQuery();
323 $ilAtomQuery->addTableLock(
"tree");
325 $ilAtomQuery->addQueryCallable($move_to_trash_callable);
329 $move_to_trash_callable(
$ilDB);
344 public function moveTree($a_source_id, $a_target_id, $a_position)
348 $move_tree_callable =
function (
ilDBInterface $ilDB) use ($a_source_id, $a_target_id, $a_position) {
353 'SELECT depth, child, parent, path FROM ' . $this->
getTree()->getTreeTable() .
' ' .
354 'WHERE ' . $ilDB->in(
'child', array($a_source_id, $a_target_id),
false,
'integer') .
' ' .
355 'AND tree = ' .
$ilDB->quote($this->
getTree()->getTreeId(),
'integer')
361 throw new InvalidArgumentException(
'Error moving subtree');
365 if (
$row->child == $a_source_id) {
366 $source_path =
$row->path;
367 $source_depth =
$row->depth;
368 $source_parent =
$row->parent;
370 $target_path =
$row->path;
371 $target_depth =
$row->depth;
375 if ($target_depth >= $source_depth) {
382 'SELECT MAX(depth) max_depth ' .
383 'FROM ' . $this->
getTree()->getTreeTable() .
' ' .
384 'WHERE path BETWEEN %s AND %s' .
' ' .
386 array(
'text',
'text',
'integer'),
387 array($source_path, $source_path .
'.Z', $this->
getTree()->getTreeId())
392 if (
$row->max_depth - $source_depth + $target_depth + 1 > $this->getMaximumPossibleDepth()) {
398 if (substr($target_path .
'.', 0, strlen($source_path) .
'.') == $source_path .
'.') {
400 throw new InvalidArgumentException(
'Error moving subtree: target is child of source');
402 $depth_diff = $target_depth - $source_depth + 1;
406 UPDATE ' . $this->
getTree()->getTreeTable() .
'
407 SET parent = CASE WHEN parent = ' . $ilDB->quote($source_parent,
'integer') .
'
408 THEN ' .
$ilDB->quote($a_target_id,
'integer') .
'
411 path = ' .
$ilDB->concat(array(
412 array(
$ilDB->quote($target_path,
'text'),
'text'),
413 array(
$ilDB->substr(
'path', strrpos(
'.' . $source_path,
'.')),
'text'))) .
' ,
415 depth = depth + ' .
$ilDB->quote($depth_diff,
'integer') .
'
417 WHERE path BETWEEN ' .
$ilDB->quote($source_path,
'text') .
'
418 AND ' .
$ilDB->quote($source_path .
'.Z',
'text') .
'
420 AND tree = ' .
$ilDB->quote($this->
getTree()->getTreeId(),
'integer');
428 if ($this->
getTree()->__isMainTree()) {
429 $ilAtomQuery =
$ilDB->buildAtomQuery();
430 $ilAtomQuery->addTableLock(
"tree");
431 $ilAtomQuery->addQueryCallable($move_tree_callable);
434 $move_tree_callable(
$ilDB);
445 $r =
$ilDB->queryF(
'SELECT DISTINCT * FROM tree WHERE parent = %s', array(
'integer'), array(0));
464 SET path = CONCAT(COALESCE(' .
$ilDB->quote($parentPath,
'text') .
', \'\'), COALESCE( ' .
$ilDB->cast(
"child",
"text") .
' , \'\'))
466 $r =
$ilDB->manipulateF($q, array(
'integer'), array($parent));
468 $r =
$ilDB->queryF(
'SELECT child FROM tree WHERE parent = %s', array(
'integer'), array($parent));
489 $query =
"SELECT t2.child child, type, t2.path path " .
490 "FROM " . $this->
getTree()->getTreeTable() .
" t1 " .
491 "JOIN " . $this->
getTree()->getTreeTable() .
" t2 ON (t2.path BETWEEN t1.path AND CONCAT(t1.path, '.Z')) " .
492 "JOIN " . $this->
getTree()->getTableReference() .
" obr ON t2.child = obr.ref_id " .
493 "JOIN " . $this->
getTree()->getObjectDataTable() .
" obd ON obr.obj_id = obd.obj_id " .
494 "WHERE t1.child = " . $ilDB->quote($a_endnode_id,
'integer') .
" " .
495 "AND t1." . $this->
getTree()->getTreePk() .
" = " . $ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
" " .
496 "AND t2." . $this->
getTree()->getTreePk() .
" = " . $ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
" " .
503 #$nodes[$row->child]['lft'] = $row->lft;
504 #$nodes[$row->child]['rgt'] = $row->rgt;
505 $nodes[
$row->child][
'child'] =
$row->child;
506 $nodes[
$row->child][
'type'] =
$row->type;
507 $nodes[
$row->child][
'path'] =
$row->path;
510 $depth_first_compare =
function ($a, $b) {
511 $a_exploded = explode(
'.', $a[
'path']);
512 #ilLoggerFactory::getLogger('tree')->debug(print_r($a_exploded,TRUE));
513 $b_exploded = explode(
'.', $b[
'path']);
516 foreach ($a_exploded as $num) {
517 $a_padded .= (str_pad((
string) $num, 14,
'0', STR_PAD_LEFT));
520 foreach ($b_exploded as $num) {
521 $b_padded .= (str_pad((
string) $num, 14,
'0', STR_PAD_LEFT));
524 #ilLoggerFactory::getLogger('tree')->debug($a_padded);
525 return strcasecmp($a_padded, $b_padded);
528 #ilLoggerFactory::getLogger('tree')->debug(print_r($nodes,TRUE));
530 uasort($nodes, $depth_first_compare);
532 #ilLoggerFactory::getLogger('tree')->debug(print_r($nodes,TRUE));
534 return (array) $nodes;
545 $query =
'select child from ' . $this->
getTree()->getTreeTable() .
' child where not exists ' .
547 'select child from ' . $this->
getTree()->getTreeTable() .
' parent where child.parent = parent.child and ' .
548 '(child.path BETWEEN parent.path AND CONCAT(parent.path,' . $ilDB->quote(
'Z',
'text') .
') )' .
')' .
549 'and ' . $this->
getTree()->getTreePk() .
' = ' . $this->
getTree()->getTreeId() .
' and child <> 1';
An exception for terminatinating execution or to throw for unit testing.
Thrown if invalid tree strucutes are found.
static getLogger($a_component_id)
Get component logger.
Base class for materialize path based trees Based on implementation of Werner Randelshofer.
moveTree($a_source_id, $a_target_id, $a_position)
move source subtree to target node
getPathIds($a_endnode, $a_startnode=0)
Get path ids.
validateParentRelations()
Validaate parent relations.
getSubTreeIds($a_node_id)
Get subtree ids.
getTree()
Get tree object.
deleteTree($a_node_id)
Delete a subtree.
getSubtreeInfo($a_endnode_id)
getSubTreeQuery($a_node, $a_types='', $a_force_join_reference=true, $a_fields=array())
Get subtree query.
__construct(ilTree $a_tree)
Constructor.
getMaximumPossibleDepth()
Get maximum possible depth.
moveToTrash($a_node_id)
Move subtree to trash.
getRelation($a_node_a, $a_node_b)
Get relation of two nodes.
insertNode($a_node_id, $a_parent_id, $a_pos)
Insert new node under parent node.
static createMaterializedPath($parent, $parentPath)
static createFromParentReleation()
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
Interface for tree implementations Currrently nested set or materialize path.
foreach($_POST as $key=> $value) $res