4include_once 
'./Services/Tree/interfaces/interface.ilTreeImplementation.php';
 
   27        $this->tree = $a_tree;
 
   60        $node = $this->
getTree()->getNodeTreeData($a_node_id);
 
   61        $query = 
'SELECT child FROM ' . $this->
getTree()->getTreeTable() . 
' ' .
 
   62                'WHERE path BETWEEN ' .
 
   63                $ilDB->quote($node[
'path'], 
'text') . 
' AND ' .
 
   64                $ilDB->quote($node[
'path'] . 
'.Z', 
'text') . 
' ' .
 
   66                'AND ' . $this->
getTree()->getTreePk() . 
' = %s';
 
   70            array(
'integer', 
'integer'),
 
   71            array($a_node_id, $this->
getTree()->getTreeId())
 
   74            $childs[] = $row[
'child'];
 
   76        return $childs ? $childs : array();
 
   87        if ($a_node_a[
'child'] == $a_node_b[
'child']) {
 
   91        if (stripos($a_node_a[
'path'], $a_node_b[
'path'] . 
'.') === 0) {
 
   95        if (stripos($a_node_b[
'path'], $a_node_a[
'path'] . 
'.') === 0) {
 
   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'], 
'.'));
 
  104        if ($a_node_a[
'path'] and (strcmp($path_a, $path_b) === 0)) {
 
  123        if (is_array($a_types)) {
 
  125                $type_str = 
"AND " . 
$ilDB->in($this->
getTree()->getObjectDataTable() . 
".type", $a_types, 
false, 
"text");
 
  127        } elseif (strlen($a_types)) {
 
  128            $type_str = 
"AND " . $this->
getTree()->getObjectDataTable() . 
".type = " . 
$ilDB->quote($a_types, 
"text");
 
  132        if ($type_str or $a_force_join_reference) {
 
  133            $join = $this->
getTree()->buildJoin();
 
  137        if (count($a_fields)) {
 
  138            $fields = implode(
',', $a_fields);
 
  144            'FROM ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  146            'WHERE ' . $this->
getTree()->getTreeTable() . 
'.path ' .
 
  148            $ilDB->quote($a_node[
'path'], 
'text') . 
' AND ' .
 
  149            $ilDB->quote($a_node[
'path'] . 
'.Z', 
'text') . 
' ' .
 
  150            'AND ' . $this->
getTree()->getTreeTable() . 
'.' . $this->
getTree()->getTreePk() . 
' < 0 ' .
 
  152            'ORDER BY ' . $this->
getTree()->getTreeTable() . 
'.path';
 
  166    public function getSubTreeQuery($a_node, $a_types = 
'', $a_force_join_reference = 
true, $a_fields = array())
 
  173        if (is_array($a_types)) {
 
  175                $type_str = 
"AND " . 
$ilDB->in($this->
getTree()->getObjectDataTable() . 
".type", $a_types, 
false, 
"text");
 
  177        } elseif (strlen($a_types)) {
 
  178            $type_str = 
"AND " . $this->
getTree()->getObjectDataTable() . 
".type = " . 
$ilDB->quote($a_types, 
"text");
 
  182        if ($type_str or $a_force_join_reference) {
 
  183            $join = $this->
getTree()->buildJoin();
 
  187        if (count($a_fields)) {
 
  188            $fields = implode(
',', $a_fields);
 
  194                'FROM ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  196                'WHERE ' . $this->
getTree()->getTreeTable() . 
'.path ' .
 
  198                $ilDB->quote($a_node[
'path'], 
'text') . 
' AND ' .
 
  199                $ilDB->quote($a_node[
'path'] . 
'.Z', 
'text') . 
' ' .
 
  200                'AND ' . $this->
getTree()->getTreeTable() . 
'.' . $this->
getTree()->getTreePk() . 
' = ' . 
$ilDB->quote($this->
getTree()->getTreeId(), 
'integer') . 
' ' .
 
  202                'ORDER BY ' . $this->
getTree()->getTreeTable() . 
'.path';
 
  220        $query = 
'SELECT path FROM ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  221            'WHERE child = ' . 
$ilDB->quote($a_endnode, 
'integer') . 
' ';
 
  226            $path = $row[
'path'];
 
  229        $pathIds = explode(
'.', $path);
 
  231        if ($a_startnode != 0) {
 
  232            while (count($pathIds) > 0 && $pathIds[0] != $a_startnode) {
 
  233                array_shift($pathIds);
 
  253        $insert_node_callable = 
function (
ilDBInterface $ilDB) use ($a_node_id, $a_parent_id, $a_pos) {
 
  258                'SELECT parent, depth, path FROM ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  259                'WHERE child = %s ' . 
' ' .
 
  260                'AND ' . $this->
getTree()->getTreePk() . 
' = %s',
 
  261                array(
'integer', 
'integer'),
 
  262                array($a_parent_id, $this->
getTree()->getTreeId())
 
  268            if ($r->parent === 
null) {
 
  273            if ($r->depth >= $this->getMaximumPossibleDepth()) {
 
  278            $parentPath = $r->path;
 
  279            $depth = $r->depth + 1;
 
  284            $ilDB->insert($this->
getTree()->getTreeTable(), array($this->
getTree()->getTreePk() => array(
'integer', $this->
getTree()->getTreeId()),
 
  285                'child' => array(
'integer', $a_node_id),
 
  286                'parent' => array(
'integer', $a_parent_id),
 
  287                'lft' => array(
'integer', $lft),
 
  288                'rgt' => array(
'integer', $rgt),
 
  289                'depth' => array(
'integer', $depth),
 
  290                'path' => array(
'text', $parentPath . 
"." . $a_node_id)));
 
  295        if ($this-> 
getTree()->__isMainTree()) {
 
  296            $ilAtomQuery = 
$ilDB->buildAtomQuery();
 
  297            $ilAtomQuery->addTableLock(
"tree");
 
  299            $ilAtomQuery->addQueryCallable($insert_node_callable);
 
  303            $insert_node_callable(
$ilDB);
 
  320            $query = 
'SELECT * FROM ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  321                'WHERE ' . $this->
getTree()->getTreeTable() . 
'.child = %s ' .
 
  322                'AND ' . $this->
getTree()->getTreeTable() . 
'.' . $this->
getTree()->getTreePk() . 
' = %s ';
 
  325                $this->
getTree()->getTreeId()));
 
  328            $query = 
'DELETE FROM ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  329                'WHERE path BETWEEN ' . 
$ilDB->quote($row[
'path'], 
'text') . 
' ' .
 
  330                'AND ' . 
$ilDB->quote($row[
'path'] . 
'.Z', 
'text') . 
' ' .
 
  331                'AND ' . $this->
getTree()->getTreePk() . 
' = ' . 
$ilDB->quote($this->
getTree()->getTreeId(), 
'integer');
 
  336        if ($this->
getTree()->__isMainTree()) {
 
  337            $ilAtomQuery = 
$ilDB->buildAtomQuery();
 
  338            $ilAtomQuery->addTableLock(
'tree');
 
  339            $ilAtomQuery->addQueryCallable($delete_tree_callable);
 
  342            $delete_tree_callable(
$ilDB);
 
  361            $node = $this->
getTree()->getNodeTreeData($a_node_id);
 
  366                                UPDATE ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  367                'SET tree = %s' . 
' ' .
 
  368                'WHERE ' . $this->
getTree()->getTreePk() . 
' = %s ' .
 
  369                'AND path BETWEEN %s AND %s',
 
  370                array(
'integer', 
'integer', 
'text', 
'text'),
 
  371                array(-$a_node_id, $this->
getTree()->getTreeId(), $node[
'path'], $node[
'path'] . 
'.Z')
 
  377        if ($this->
getTree()->__isMainTree()) {
 
  378            $ilAtomQuery = 
$ilDB->buildAtomQuery();
 
  379            $ilAtomQuery->addTableLock(
"tree");
 
  381            $ilAtomQuery->addQueryCallable($move_to_trash_callable);
 
  385            $move_to_trash_callable(
$ilDB);
 
  400    public function moveTree($a_source_id, $a_target_id, $a_position)
 
  406        $move_tree_callable = 
function (
ilDBInterface $ilDB) use ($a_source_id, $a_target_id, $a_position) {
 
  411                'SELECT depth, child, parent, path FROM ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  412                'WHERE ' . 
$ilDB->in(
'child', array($a_source_id, $a_target_id), 
false, 
'integer') . 
' ' .
 
  413                'AND tree = ' . 
$ilDB->quote($this->
getTree()->getTreeId(), 
'integer')
 
  419                throw new InvalidArgumentException(
'Error moving subtree');
 
  422            while ($row = 
$ilDB->fetchObject(
$res)) {
 
  423                if ($row->child == $a_source_id) {
 
  424                    $source_path = $row->path;
 
  425                    $source_depth = $row->depth;
 
  426                    $source_parent = $row->parent;
 
  428                    $target_path = $row->path;
 
  429                    $target_depth = $row->depth;
 
  433            if ($target_depth >= $source_depth) {
 
  440                    'SELECT  MAX(depth) max_depth ' .
 
  441                    'FROM    ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  442                    'WHERE   path BETWEEN %s AND %s' . 
' ' .
 
  444                    array(
'text', 
'text', 
'integer'),
 
  445                    array($source_path, $source_path . 
'.Z', $this->
getTree()->getTreeId())
 
  450                if ($row->max_depth - $source_depth + $target_depth + 1 > $this->getMaximumPossibleDepth()) {
 
  456            if (substr($target_path . 
'.', 0, strlen($source_path) . 
'.') == $source_path . 
'.') {
 
  458                throw new InvalidArgumentException(
'Error moving subtree: target is child of source');
 
  460            $depth_diff = $target_depth - $source_depth + 1;
 
  464                'UPDATE ' . $this->
getTree()->getTreeTable() . 
' ' .
 
  465                'SET parent = CASE WHEN parent = ' . 
$ilDB->quote($source_parent, 
'integer') . 
' ' .
 
  466                             'THEN ' . 
$ilDB->quote($a_target_id, 
'integer') . 
' ' .
 
  467                             'ELSE parent END, path = ' .
 
  469                    array(
$ilDB->quote($target_path, 
'text'), 
'text'),
 
  470                    array(
$ilDB->substr(
'path', strrpos(
'.' . $source_path, 
'.')), 
'text'))) . 
' ' .
 
  471                ',depth = depth + ' . 
$ilDB->quote($depth_diff, 
'integer') . 
' ' .
 
  472                'WHERE path  BETWEEN ' . 
$ilDB->quote($source_path, 
'text') . 
' ' .
 
  473                'AND ' . 
$ilDB->quote($source_path . 
'.Z', 
'text') . 
' ';
 
  475            if (!$this->
getTree()->__isMainTree()) {
 
  483        if ($this->
getTree()->__isMainTree()) {
 
  484            $ilAtomQuery = 
$ilDB->buildAtomQuery();
 
  485            $ilAtomQuery->addTableLock(
"tree");
 
  486            $ilAtomQuery->addQueryCallable($move_tree_callable);
 
  489            $move_tree_callable(
$ilDB);
 
  502        $r = 
$ilDB->queryF(
'SELECT DISTINCT * FROM tree WHERE parent = %s', array(
'integer'), array(0));
 
  504        while ($row = 
$ilDB->fetchAssoc($r)) {
 
  523                        SET path = CONCAT(COALESCE(' . 
$ilDB->quote($parentPath, 
'text') . 
', \'\'), COALESCE( ' . 
$ilDB->cast(
"child", 
"text") . 
' , \'\')) 
  525        $r = 
$ilDB->manipulateF($q, array(
'integer'), array($parent));
 
  527        $r = 
$ilDB->queryF(
'SELECT child FROM tree WHERE parent = %s', array(
'integer'), array($parent));
 
  529        while ($row = 
$ilDB->fetchAssoc($r)) {
 
  546        if ($this->
getTree()->__isMainTree() && $this->
getTree()->getTreeId() == 1) {
 
  550            $treeClause1 = 
' AND t1.' . $this->
getTree()->getTreePk() . 
' = ' . 
$ilDB->quote($this->
getTree()->getTreeId(), 
'integer');
 
  551            $treeClause2 = 
' AND t2.' . $this->
getTree()->getTreePk() . 
' = ' . 
$ilDB->quote($this->
getTree()->getTreeId(), 
'integer');
 
  556            SELECT t1." . $this->
getTree()->getTreePk() . 
", t1.path 
  557            FROM " . $this->
getTree()->getTreeTable() . 
" t1  
  558            WHERE t1.child = " . 
$ilDB->quote($a_endnode_id, 
'integer') .
 
  563        if ($row[$this->
getTree()->getTreePk()] == $this->
getTree()->getTreeId()) {
 
  564            $path = $row[
'path'];
 
  570        $query = 
"SELECT t2." . $this->
getTree()->getTreePk() . 
", t2.child child, type, t2.path path " .
 
  571            "FROM " . $this->
getTree()->getTreeTable() . 
" t2 " .
 
  572                "JOIN " . $this->
getTree()->getTableReference() . 
" obr ON t2.child = obr.ref_id " .
 
  573                "JOIN " . $this->
getTree()->getObjectDataTable() . 
" obd ON obr.obj_id = obd.obj_id " .
 
  574            "WHERE t2.path BETWEEN " . 
$ilDB->quote($path, 
'text') . 
" AND " . 
$ilDB->quote($path . 
'.Z', 
'text') .
 
  583            if ($row[$this->
getTree()->getTreePk()] != $this->
getTree()->getTreeId()) {
 
  587            $nodes[$row[
'child']][
'child'] = $row[
'child'];
 
  588            $nodes[$row[
'child']][
'type'] = $row[
'type'];
 
  589            $nodes[$row[
'child']][
'path'] = $row[
'path'];
 
  592        $depth_first_compare = 
static function (
$a, 
$b) {
 
  593            $a_exploded = explode(
'.', 
$a[
'path']);
 
  594            $b_exploded = explode(
'.', 
$b[
'path']);
 
  597            foreach ($a_exploded as $num) {
 
  598                $a_padded .= (str_pad((
string) $num, 14, 
'0', STR_PAD_LEFT));
 
  601            foreach ($b_exploded as $num) {
 
  602                $b_padded .= (str_pad((
string) $num, 14, 
'0', STR_PAD_LEFT));
 
  605            return strcasecmp($a_padded, $b_padded);
 
  608        uasort($nodes, $depth_first_compare);
 
  610        return (array) $nodes;
 
  623        $query = 
'select child from ' . $this->
getTree()->getTreeTable() . 
' child where not exists ' .
 
  625                    'select child from ' . $this->
getTree()->getTreeTable() . 
' parent where child.parent = parent.child and ' .
 
  626                    '(child.path BETWEEN parent.path AND CONCAT(parent.path,' . 
$ilDB->quote(
'Z', 
'text') . 
') )' . 
')' .
 
  627                'and ' . $this->
getTree()->getTreePk() . 
' = ' . $this->
getTree()->getTreeId() . 
' and child <> 1';
 
  634            $failures[] = $row[$this->
getTree()->getTreePk()];
 
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.
getTrashSubTreeQuery($a_node, $a_types, $a_force_join_reference=true, $a_fields=[])
Get subtree query for trashed tree items.mixed
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.
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
foreach($_POST as $key=> $value) $res