4 include_once
'./Services/Tree/interfaces/interface.ilTreeImplementation.php';
27 $this->tree = $a_tree;
57 $node = $this->
getTree()->getNodeTreeData($a_node_id);
58 $query =
'SELECT child FROM '.$this->getTree()->getTreeTable().
' '.
59 'WHERE path BETWEEN '.
60 $ilDB->quote($node[
'path'],
'text').
' AND '.
61 $ilDB->quote($node[
'path'].
'.Z',
'text').
' '.
63 'AND '.$this->getTree()->getTreePk().
' = %s';
67 array(
'integer',
'integer'),
68 array($a_node_id, $this->
getTree()->getTreeId())
70 while(
$row = $ilDB->fetchAssoc(
$res))
72 $childs[] =
$row[
'child'];
74 return $childs ? $childs : array();
84 if($a_node_a[
'child'] == $a_node_b[
'child'])
86 $GLOBALS[
'ilLog']->write(__METHOD__.
': EQUALS');
89 if(stristr($a_node_a[
'path'], $a_node_b[
'path']))
91 $GLOBALS[
'ilLog']->write(__METHOD__.
': CHILD');
94 if(stristr($a_node_b[
'path'], $a_node_a[
'path']))
96 $GLOBALS[
'ilLog']->write(__METHOD__.
': PARENT');
99 $path_a = substr($a_node_a[
'path'],0,strrpos($a_node_a[
'path'],
'.'));
100 $path_b = substr($a_node_b[
'path'],0,strrpos($a_node_b[
'path'],
'.'));
101 $GLOBALS[
'ilLog']->write(__METHOD__.
': Comparing '.$path_a .
' '.
'with '.$path_b);
103 if($a_node_a[
'path'] and (strcmp($path_a,$path_b) === 0))
105 $GLOBALS[
'ilLog']->write(__METHOD__.
': SIBLING');
109 $GLOBALS[
'ilLog']->write(__METHOD__.
': NONE');
119 public function getSubTreeQuery($a_node, $a_types =
'', $a_force_join_reference =
true, $a_fields = array())
124 if(is_array($a_types))
128 $type_str =
"AND ".$ilDB->in($this->
getTree()->getObjectDataTable().
".type", $a_types,
false,
"text");
131 else if(strlen($a_types))
133 $type_str =
"AND ".$this->getTree()->getObjectDataTable().
".type = ".$ilDB->quote($a_types,
"text");
137 if($type_str or $a_force_join_reference)
139 $join = $this->
getTree()->buildJoin();
145 $fields = implode(
',',$a_fields);
151 'FROM '.$this->getTree()->getTreeTable().
' '.
153 'WHERE '.$this->getTree()->getTreeTable().
'.path '.
155 $ilDB->quote($a_node[
'path'],
'text').
' AND '.
156 $ilDB->quote($a_node[
'path'].
'.Z',
'text').
' '.
157 'AND '.$this->getTree()->getTreeTable().
'.'.$this->
getTree()->getTreePk().
' = '.$ilDB->quote($this->
getTree()->getTreeId(),
'integer').
' '.
159 'ORDER BY '.$this->getTree()->getTreeTable().
'.path';
174 $query =
'SELECT path FROM ' . $this->
getTree()->getTreeTable() .
' '.
175 'WHERE child = '. $ilDB->quote($a_endnode,
'integer').
' ';
179 while (
$row = $ilDB->fetchAssoc(
$res))
184 $pathIds = explode(
'.',
$path);
186 if ($a_startnode != 0)
188 while (count($pathIds) > 0 && $pathIds[0] != $a_startnode)
190 array_shift($pathIds);
207 if ($this->
getTree()->__isMainTree())
217 $res = $ilDB->queryF(
218 'SELECT parent, depth, path FROM ' . $this->
getTree()->getTreeTable() .
' ' .
219 'WHERE child = %s '.
' '.
220 'AND ' . $this->
getTree()->getTreePk() .
' = %s', array(
'integer',
'integer'),
221 array($a_parent_id, $this->
getTree()->getTreeId()));
224 $r = $ilDB->fetchObject(
$res);
226 if ($r->parent == NULL)
228 if ($this->
getTree()->__isMainTree())
230 $ilDB->unlockTables();
236 if ($r->depth >= $this->getMaximumPossibleDepth())
239 if ($this->
getTree()->__isMainTree())
241 $ilDB->unlockTables();
247 $parentPath = $r->path;
248 $depth = $r->depth + 1;
253 $ilDB->insert($this->
getTree()->getTreeTable(), array($this->
getTree()->getTreePk() => array(
'integer', $this->
getTree()->getTreeId()),
254 'child' => array(
'integer', $a_node_id),
255 'parent' => array(
'integer', $a_parent_id),
256 'lft' => array(
'integer', $lft),
257 'rgt' => array(
'integer', $rgt),
258 'depth' => array(
'integer', $depth),
259 'path' => array(
'text', $parentPath .
"." . $a_node_id)));
262 if ($this->
getTree()->__isMainTree())
264 $ilDB->unlockTables();
277 $a_node = $this->
getTree()->getNodeData($a_node_id);
279 $query =
'DELETE FROM '.$this->getTree()->getTreeTable().
' '.
280 'WHERE path BETWEEN '.$ilDB->quote($a_node[
'path'],
'text').
' '.
281 'AND '.$ilDB->quote($a_node[
'path'].
'.Z',
'text').
' '.
282 'AND '.$this->getTree()->getTreePk().
' = '.$ilDB->quote($a_node[$this->
getTree()->getTreePk()]);
283 $ilDB->manipulate(
$query);
296 if ($this->
getTree()->__isMainTree())
304 $node = $this->
getTree()->getNodeTreeData($a_node_id);
308 if ($this->
getTree()->__isMainTree())
310 $ilDB->unlockTables();
318 UPDATE ' . $this->
getTree()->getTreeTable().
' '.
319 'SET tree = %s' .
' '.
320 'WHERE ' . $this->
getTree()->getTreePk() .
' = %s ' .
321 'AND path BETWEEN %s AND %s',
322 array(
'integer',
'integer',
'text',
'text'),
323 array(-$a_node_id, $this->
getTree()->getTreeId(), $node[
'path'], $node[
'path'] .
'.Z'));
327 if ($this->
getTree()->__isMainTree())
329 $ilDB->unlockTables();
340 public function moveTree($a_source_id, $a_target_id, $a_position)
344 if ($this->
getTree()->__isMainTree())
354 'SELECT depth, child, parent, path FROM ' . $this->
getTree()->getTreeTable() .
' '.
355 'WHERE ' . $ilDB->in(
'child', array($a_source_id, $a_target_id),
false,
'integer') .
' '.
356 'AND tree = ' . $ilDB->quote($this->
getTree()->getTreeId(),
'integer')
360 if ($ilDB->numRows(
$res) != 2)
362 if ($this->
getTree()->__isMainTree())
364 $ilDB->unlockTables();
367 $GLOBALS[
'ilLog']->write(__METHOD__.
': Objects not found in tree');
368 throw new InvalidArgumentException(
'Error moving subtree');
371 while (
$row = $ilDB->fetchObject(
$res))
373 if (
$row->child == $a_source_id)
375 $source_path =
$row->path;
376 $source_depth =
$row->depth;
377 $source_parent =
$row->parent;
381 $target_path =
$row->path;
382 $target_depth =
$row->depth;
386 if ($target_depth >= $source_depth)
393 $res = $ilDB->queryF(
394 'SELECT MAX(depth) max_depth '.
395 'FROM ' . $this->
getTree()->getTreeTable() .
' '.
396 'WHERE path BETWEEN %s AND %s'.
' '.
398 array(
'text',
'text',
'integer'), array($source_path, $source_path .
'.Z', $this->
getTree()->getTreeId()));
402 if (
$row->max_depth - $source_depth + $target_depth + 1 > $this->getMaximumPossibleDepth())
404 if ($this->
getTree()->__isMainTree())
406 $ilDB->unlockTables();
409 $GLOBALS[
'ilLog']->write(__METHOD__.
': Objects not found in tree');
414 if (substr($target_path .
'.', 0, strlen($source_path) .
'.') == $source_path .
'.')
416 if ($this->
getTree()->__isMainTree())
418 $ilDB->unlockTables();
421 $GLOBALS[
'ilLog']->write(__METHOD__.
': Target is child of source');
422 throw new ilInvalidArgumentException(
'Error moving subtree: target is child of source');
424 $depth_diff = $target_depth - $source_depth + 1;
428 UPDATE ' . $this->
getTree()->getTreeTable() .
'
429 SET parent = CASE WHEN parent = ' . $ilDB->quote($source_parent,
'integer') .
'
430 THEN ' . $ilDB->quote($a_target_id,
'integer') .
'
433 path = ' . $ilDB->concat(array(
434 array($ilDB->quote($target_path,
'text'),
'text'),
435 array($ilDB->substr(
'path', strrpos(
'.' . $source_path,
'.')),
'text'))) .
' ,
437 depth = depth + ' . $ilDB->quote($depth_diff,
'integer') .
'
439 WHERE path BETWEEN ' . $ilDB->quote($source_path,
'text') .
'
440 AND ' . $ilDB->quote($source_path .
'.Z',
'text') .
'
442 AND tree = ' . $ilDB->quote($this->
getTree()->getTreeId(),
'integer');
447 $ilDB->manipulate(
$query);
448 if ($this->
getTree()->__isMainTree())
450 $ilDB->unlockTables();
460 $r = $ilDB->queryF(
'SELECT DISTINCT * FROM tree WHERE parent = %s', array(
'integer'), array(0));
462 while (
$row = $ilDB->fetchAssoc($r))
477 SET path = CONCAT(COALESCE(' . $ilDB->quote($parentPath,
'text') .
', \'\'), COALESCE(child, \'\'))
479 $r = $ilDB->manipulateF($q, array(
'integer'), array($parent));
481 $r = $ilDB->queryF(
'SELECT child FROM tree WHERE parent = %s', array(
'integer'), array($parent));
483 while (
$row = $ilDB->fetchAssoc($r))
499 $query =
"SELECT t2.child child, type, t2.path path " .
500 "FROM " . $this->
getTree()->getTreeTable() .
" t1 " .
501 "JOIN " . $this->
getTree()->getTreeTable() .
" t2 ON (t2.path BETWEEN t1.path AND CONCAT(t1.path, '.Z')) " .
502 "JOIN " . $this->
getTree()->getTableReference() .
" obr ON t2.child = obr.ref_id " .
503 "JOIN " . $this->
getTree()->getObjectDataTable() .
" obd ON obr.obj_id = obd.obj_id " .
504 "WHERE t1.child = " . $ilDB->quote($a_endnode_id,
'integer') .
" " .
505 "AND t1." . $this->
getTree()->getTreePk() .
" = " . $ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
" " .
506 "AND t2." . $this->
getTree()->getTreePk() .
" = " . $ilDB->quote($this->
getTree()->getTreeId(),
'integer') .
" " .
514 #$nodes[$row->child]['lft'] = $row->lft;
515 #$nodes[$row->child]['rgt'] = $row->rgt;
516 $nodes[
$row->child][
'child'] =
$row->child;
517 $nodes[
$row->child][
'type'] =
$row->type;
518 $nodes[
$row->child][
'path'] =
$row->path;
521 $depth_first_compare =
function($a, $b)
523 $a_exploded = explode(
'.', $a[
'path']);
524 #$GLOBALS['ilLog']->write(__METHOD__.': '.print_r($a_exploded,TRUE));
525 $b_exploded = explode(
'.', $b[
'path']);
528 foreach($a_exploded as $num)
530 $a_padded .= (str_pad((
string) $num, 14,
'0', STR_PAD_LEFT));
533 foreach($b_exploded as $num)
535 $b_padded .= (str_pad((
string) $num, 14,
'0', STR_PAD_LEFT));
537 #$GLOBALS['ilLog']->write(__METHOD__.': '.$a_padded);
538 #$GLOBALS['ilLog']->write(__METHOD__.': '.$a_padded);
539 return strcasecmp($a_padded, $b_padded);
542 #$GLOBALS['ilLog']->write(__METHOD__.': '.print_r($nodes,TRUE));
544 uasort($nodes,$depth_first_compare);
546 #$GLOBALS['ilLog']->write(__METHOD__.': '.print_r($nodes,TRUE));
548 return (array) $nodes;