ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
ilMaterializedPathTree Class Reference

Base class for materialize path based trees Based on implementation of Werner Randelshofer. More...

+ Inheritance diagram for ilMaterializedPathTree:
+ Collaboration diagram for ilMaterializedPathTree:

Public Member Functions

 __construct (ilTree $a_tree)
 Constructor. More...
 
 getTree ()
 Get tree object. More...
 
 getSubTreeIds ($a_node_id)
 Get subtree ids. More...
 
 getRelation ($a_node_a, $a_node_b)
 Get relation of two nodes. More...
 
 getTrashSubTreeQuery ($a_node, $a_types, $a_force_join_reference=true, $a_fields=[])
 Get subtree query for trashed tree items.
Parameters
$a_node
$a_types
bool$a_force_join_reference
array$a_fields
Returns
mixed
More...
 
 getSubTreeQuery ($a_node, $a_types='', $a_force_join_reference=true, $a_fields=array())
 Get subtree query. More...
 
 getPathIds ($a_endnode, $a_startnode=0)
 Get path ids. More...
 
 insertNode ($a_node_id, $a_parent_id, $a_pos)
 Insert new node under parent node. More...
 
 deleteTree ($a_node_id)
 Delete a subtree. More...
 
 moveToTrash ($a_node_id)
 Move subtree to trash. More...
 
 moveTree ($a_source_id, $a_target_id, $a_position)
 move source subtree to target node More...
 
 getSubtreeInfo ($a_endnode_id)
 
 validateParentRelations ()
 Validaate parent relations. More...
 

Static Public Member Functions

static createFromParentReleation ()
 

Protected Member Functions

 getMaximumPossibleDepth ()
 Get maximum possible depth. More...
 

Static Private Member Functions

static createMaterializedPath ($parent, $parentPath)
 

Private Attributes

 $maximum_possible_depth = 100
 
 $tree = null
 

Detailed Description

Base class for materialize path based trees Based on implementation of Werner Randelshofer.

Author
Stefan Meyer meyer.nosp@m.@lei.nosp@m.fos.c.nosp@m.om
Version
$Id$

Definition at line 16 of file class.ilMaterializedPathTree.php.

Constructor & Destructor Documentation

◆ __construct()

ilMaterializedPathTree::__construct ( ilTree  $a_tree)

Constructor.

Parameters
ilTree$a_tree

Definition at line 25 of file class.ilMaterializedPathTree.php.

26  {
27  $this->tree = $a_tree;
28  }

Member Function Documentation

◆ createFromParentReleation()

static ilMaterializedPathTree::createFromParentReleation ( )
static

Definition at line 496 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, and $success.

Referenced by ilSCTreeTasksGUI\repairStructure().

497  {
498  global $DIC;
499 
500  $ilDB = $DIC['ilDB'];
501 
502  $r = $ilDB->queryF('SELECT DISTINCT * FROM tree WHERE parent = %s', array('integer'), array(0));
503 
504  while ($row = $ilDB->fetchAssoc($r)) {
505  $success = self::createMaterializedPath(0, '');
506 
507  if ($success !== true) {
508  }
509  }
510  }
$success
Definition: Utf8Test.php:86
global $DIC
Definition: goto.php:24
global $ilDB
+ Here is the caller graph for this function:

◆ createMaterializedPath()

static ilMaterializedPathTree::createMaterializedPath (   $parent,
  $parentPath 
)
staticprivate
Parameters
type$parent
type$parentPath
Returns
bool

Definition at line 517 of file class.ilMaterializedPathTree.php.

References $DIC, and $ilDB.

518  {
519  global $DIC;
520 
521  $ilDB = $DIC['ilDB'];
522  $q = ' UPDATE tree
523  SET path = CONCAT(COALESCE(' . $ilDB->quote($parentPath, 'text') . ', \'\'), COALESCE( ' . $ilDB->cast("child", "text") . ' , \'\'))
524  WHERE parent = %s';
525  $r = $ilDB->manipulateF($q, array('integer'), array($parent));
526 
527  $r = $ilDB->queryF('SELECT child FROM tree WHERE parent = %s', array('integer'), array($parent));
528 
529  while ($row = $ilDB->fetchAssoc($r)) {
530  self::createMaterializedPath($row['child'], $parentPath . $row['child'] . '.');
531  }
532 
533  return true;
534  }
global $DIC
Definition: goto.php:24
global $ilDB

◆ deleteTree()

ilMaterializedPathTree::deleteTree (   $a_node_id)

Delete a subtree.

Parameters
int$a_node_id
Returns
bool

Implements ilTreeImplementation.

Definition at line 314 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, $query, $res, and getTree().

315  {
316  global $DIC;
317 
318  $ilDB = $DIC['ilDB'];
319  $delete_tree_callable = function (ilDBInterface $ilDB) use ($a_node_id) {
320  $query = 'SELECT * FROM ' . $this->getTree()->getTreeTable() . ' ' .
321  'WHERE ' . $this->getTree()->getTreeTable() . '.child = %s ' .
322  'AND ' . $this->getTree()->getTreeTable() . '.' . $this->getTree()->getTreePk() . ' = %s ';
323  $res = $ilDB->queryF($query, array('integer','integer'), array(
324  $a_node_id,
325  $this->getTree()->getTreeId()));
326  $row = $ilDB->fetchAssoc($res);
327 
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');
332  $ilDB->manipulate($query);
333  };
334 
335  // get lft and rgt values. Don't trust parameter lft/rgt values of $a_node
336  if ($this->getTree()->__isMainTree()) {
337  $ilAtomQuery = $ilDB->buildAtomQuery();
338  $ilAtomQuery->addTableLock('tree');
339  $ilAtomQuery->addQueryCallable($delete_tree_callable);
340  $ilAtomQuery->run();
341  } else {
342  $delete_tree_callable($ilDB);
343  }
344 
345  return true;
346  }
foreach($_POST as $key=> $value) $res
global $DIC
Definition: goto.php:24
$query
global $ilDB
+ Here is the call graph for this function:

◆ getMaximumPossibleDepth()

ilMaterializedPathTree::getMaximumPossibleDepth ( )
protected

Get maximum possible depth.

Returns
int

Definition at line 35 of file class.ilMaterializedPathTree.php.

References $maximum_possible_depth.

◆ getPathIds()

ilMaterializedPathTree::getPathIds (   $a_endnode,
  $a_startnode = 0 
)

Get path ids.

Parameters
int$a_endnode
int$a_startnode
Returns
array

Implements ilTreeImplementation.

Definition at line 213 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, $query, $res, and getTree().

214  {
215  global $DIC;
216 
217  $ilDB = $DIC['ilDB'];
218 
219  $ilDB->setLimit(1);
220  $query = 'SELECT path FROM ' . $this->getTree()->getTreeTable() . ' ' .
221  'WHERE child = ' . $ilDB->quote($a_endnode, 'integer') . ' ';
222  $res = $ilDB->query($query);
223 
224  $path = null;
225  while ($row = $ilDB->fetchAssoc($res)) {
226  $path = $row['path'];
227  }
228 
229  $pathIds = explode('.', $path);
230 
231  if ($a_startnode != 0) {
232  while (count($pathIds) > 0 && $pathIds[0] != $a_startnode) {
233  array_shift($pathIds);
234  }
235  }
236  return $pathIds;
237  }
foreach($_POST as $key=> $value) $res
global $DIC
Definition: goto.php:24
$query
global $ilDB
+ Here is the call graph for this function:

◆ getRelation()

ilMaterializedPathTree::getRelation (   $a_node_a,
  $a_node_b 
)

Get relation of two nodes.

Parameters
type$a_node_a
type$a_node_b
Returns
int

Implements ilTreeImplementation.

Definition at line 85 of file class.ilMaterializedPathTree.php.

References ilLoggerFactory\getLogger(), ilTree\RELATION_CHILD, ilTree\RELATION_EQUALS, ilTree\RELATION_NONE, ilTree\RELATION_PARENT, and ilTree\RELATION_SIBLING.

86  {
87  if ($a_node_a['child'] == $a_node_b['child']) {
88  ilLoggerFactory::getLogger('tree')->debug('EQUALS');
90  }
91  if (stripos($a_node_a['path'], $a_node_b['path'] . '.') === 0) {
92  ilLoggerFactory::getLogger('tree')->debug('CHILD');
94  }
95  if (stripos($a_node_b['path'], $a_node_a['path'] . '.') === 0) {
96  ilLoggerFactory::getLogger('tree')->debug('PARENT');
98  }
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 
102  ilLoggerFactory::getLogger('tree')->debug('Comparing ' . $path_a . ' ' . 'with ' . $path_b);
103 
104  if ($a_node_a['path'] and (strcmp($path_a, $path_b) === 0)) {
105  ilLoggerFactory::getLogger('tree')->debug('SIBLING');
107  }
108 
109  ilLoggerFactory::getLogger('tree')->debug('NONE');
110  return ilTree::RELATION_NONE;
111  }
const RELATION_PARENT
const RELATION_EQUALS
const RELATION_CHILD
const RELATION_NONE
const RELATION_SIBLING
static getLogger($a_component_id)
Get component logger.
+ Here is the call graph for this function:

◆ getSubTreeIds()

ilMaterializedPathTree::getSubTreeIds (   $a_node_id)

Get subtree ids.

Parameters
type$a_node_id
Returns
array

Implements ilTreeImplementation.

Definition at line 54 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, $query, $res, and getTree().

55  {
56  global $DIC;
57 
58  $ilDB = $DIC['ilDB'];
59 
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') . ' ' .
65  'AND child != %s ' .
66  'AND ' . $this->getTree()->getTreePk() . ' = %s';
67 
68  $res = $ilDB->queryF(
69  $query,
70  array('integer', 'integer'),
71  array($a_node_id, $this->getTree()->getTreeId())
72  );
73  while ($row = $ilDB->fetchAssoc($res)) {
74  $childs[] = $row['child'];
75  }
76  return $childs ? $childs : array();
77  }
foreach($_POST as $key=> $value) $res
global $DIC
Definition: goto.php:24
$query
global $ilDB
+ Here is the call graph for this function:

◆ getSubtreeInfo()

ilMaterializedPathTree::getSubtreeInfo (   $a_endnode_id)
Parameters
int$a_endnode_id
Returns
array

Implements ilTreeImplementation.

Definition at line 540 of file class.ilMaterializedPathTree.php.

References Vendor\Package\$a, Vendor\Package\$b, $DIC, $ilDB, $query, $res, and getTree().

541  {
542  global $DIC;
543 
544  $ilDB = $DIC['ilDB'];
545 
546  if ($this->getTree()->__isMainTree() && $this->getTree()->getTreeId() == 1) {
547  $treeClause1 = '';
548  $treeClause2 = '';
549  } else {
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');
552  }
553 
554  // first query for the path of the given node
555  $query = "
556  SELECT t1." . $this->getTree()->getTreePk() . ", t1.path
557  FROM " . $this->getTree()->getTreeTable() . " t1
558  WHERE t1.child = " . $ilDB->quote($a_endnode_id, 'integer') .
559  $treeClause1;
560 
561  $res = $ilDB->query($query);
562  $row = $ilDB->fetchAssoc($res);
563  if ($row[$this->getTree()->getTreePk()] == $this->getTree()->getTreeId()) {
564  $path = $row['path'];
565  } else {
566  return [];
567  }
568 
569  // then query for the nodes in that 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') .
575  $treeClause2 . ' ' .
576  "ORDER BY t2.path";
577 
578 
579  $res = $ilDB->query($query);
580  $nodes = [];
581  while ($row = $ilDB->fetchAssoc($res)) {
582  // filter out deleted items if tree is repository
583  if ($row[$this->getTree()->getTreePk()] != $this->getTree()->getTreeId()) {
584  continue;
585  }
586 
587  $nodes[$row['child']]['child'] = $row['child'];
588  $nodes[$row['child']]['type'] = $row['type'];
589  $nodes[$row['child']]['path'] = $row['path'];
590  }
591 
592  $depth_first_compare = static function ($a, $b) {
593  $a_exploded = explode('.', $a['path']);
594  $b_exploded = explode('.', $b['path']);
595 
596  $a_padded = '';
597  foreach ($a_exploded as $num) {
598  $a_padded .= (str_pad((string) $num, 14, '0', STR_PAD_LEFT));
599  }
600  $b_padded = '';
601  foreach ($b_exploded as $num) {
602  $b_padded .= (str_pad((string) $num, 14, '0', STR_PAD_LEFT));
603  }
604 
605  return strcasecmp($a_padded, $b_padded);
606  };
607 
608  uasort($nodes, $depth_first_compare);
609 
610  return (array) $nodes;
611  }
foreach($_POST as $key=> $value) $res
global $DIC
Definition: goto.php:24
$query
global $ilDB
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
+ Here is the call graph for this function:

◆ getSubTreeQuery()

ilMaterializedPathTree::getSubTreeQuery (   $a_node,
  $a_types = '',
  $a_force_join_reference = true,
  $a_fields = array() 
)

Get subtree query.

Parameters
type$a_node
string$a_types
bool$a_force_join_reference
array$a_fields
Returns
string query

Implements ilTreeImplementation.

Definition at line 166 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, $query, and getTree().

167  {
168  global $DIC;
169 
170  $ilDB = $DIC['ilDB'];
171 
172  $type_str = '';
173  if (is_array($a_types)) {
174  if ($a_types) {
175  $type_str = "AND " . $ilDB->in($this->getTree()->getObjectDataTable() . ".type", $a_types, false, "text");
176  }
177  } elseif (strlen($a_types)) {
178  $type_str = "AND " . $this->getTree()->getObjectDataTable() . ".type = " . $ilDB->quote($a_types, "text");
179  }
180 
181  $join = '';
182  if ($type_str or $a_force_join_reference) {
183  $join = $this->getTree()->buildJoin();
184  }
185 
186  $fields = '* ';
187  if (count($a_fields)) {
188  $fields = implode(',', $a_fields);
189  }
190 
191  // @todo order by
192  $query = 'SELECT ' .
193  $fields . ' ' .
194  'FROM ' . $this->getTree()->getTreeTable() . ' ' .
195  $join . ' ' .
196  'WHERE ' . $this->getTree()->getTreeTable() . '.path ' .
197  'BETWEEN ' .
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') . ' ' .
201  $type_str . ' ' .
202  'ORDER BY ' . $this->getTree()->getTreeTable() . '.path';
203 
204  return $query;
205  }
global $DIC
Definition: goto.php:24
$query
global $ilDB
+ Here is the call graph for this function:

◆ getTrashSubTreeQuery()

ilMaterializedPathTree::getTrashSubTreeQuery (   $a_node,
  $a_types,
  $a_force_join_reference = true,
  $a_fields = [] 
)

Get subtree query for trashed tree items.

Parameters
$a_node
$a_types
bool$a_force_join_reference
array$a_fields
Returns
mixed

Implements ilTreeImplementation.

Definition at line 116 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, $query, and getTree().

117  {
118  global $DIC;
119 
120  $ilDB = $DIC->database();
121 
122  $type_str = '';
123  if (is_array($a_types)) {
124  if ($a_types) {
125  $type_str = "AND " . $ilDB->in($this->getTree()->getObjectDataTable() . ".type", $a_types, false, "text");
126  }
127  } elseif (strlen($a_types)) {
128  $type_str = "AND " . $this->getTree()->getObjectDataTable() . ".type = " . $ilDB->quote($a_types, "text");
129  }
130 
131  $join = '';
132  if ($type_str or $a_force_join_reference) {
133  $join = $this->getTree()->buildJoin();
134  }
135 
136  $fields = '* ';
137  if (count($a_fields)) {
138  $fields = implode(',', $a_fields);
139  }
140 
141  // @todo order by
142  $query = 'SELECT ' .
143  $fields . ' ' .
144  'FROM ' . $this->getTree()->getTreeTable() . ' ' .
145  $join . ' ' .
146  'WHERE ' . $this->getTree()->getTreeTable() . '.path ' .
147  'BETWEEN ' .
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 ' .
151  $type_str . ' ' .
152  'ORDER BY ' . $this->getTree()->getTreeTable() . '.path';
153 
154  return $query;
155  }
global $DIC
Definition: goto.php:24
$query
global $ilDB
+ Here is the call graph for this function:

◆ getTree()

ilMaterializedPathTree::getTree ( )

Get tree object.

Returns
ilTree $tree

Definition at line 44 of file class.ilMaterializedPathTree.php.

References $tree.

Referenced by deleteTree(), getPathIds(), getSubTreeIds(), getSubtreeInfo(), getSubTreeQuery(), getTrashSubTreeQuery(), insertNode(), moveToTrash(), moveTree(), and validateParentRelations().

+ Here is the caller graph for this function:

◆ insertNode()

ilMaterializedPathTree::insertNode (   $a_node_id,
  $a_parent_id,
  $a_pos 
)

Insert new node under parent node.

Parameters
int$a_node_id
int$a_parent_id
int$a_pos
Exceptions
ilInvalidTreeStructureException

Implements ilTreeImplementation.

Definition at line 247 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, $res, ilLogLevel\ERROR, ilLoggerFactory\getLogger(), and getTree().

248  {
249  global $DIC;
250 
251  $ilDB = $DIC['ilDB'];
252 
253  $insert_node_callable = function (ilDBInterface $ilDB) use ($a_node_id, $a_parent_id, $a_pos) {
254  // get path and depth of parent
255  $ilDB->setLimit(1);
256 
257  $res = $ilDB->queryF(
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())
263  );
264 
265 
266  $r = $ilDB->fetchObject($res);
267 
268  if ($r->parent === null) {
270  throw new ilInvalidTreeStructureException('Parent node not found in tree');
271  }
272 
273  if ($r->depth >= $this->getMaximumPossibleDepth()) {
275  throw new ilInvalidTreeStructureException('Maximum tree depth exceeded');
276  }
277 
278  $parentPath = $r->path;
279  $depth = $r->depth + 1;
280  $lft = 0;
281  $rgt = 0;
282 
283 
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)));
291  };
292 
293  // use ilAtomQuery to lock tables if tree is main tree
294  // otherwise just call this closure without locking
295  if ($this-> getTree()->__isMainTree()) {
296  $ilAtomQuery = $ilDB->buildAtomQuery();
297  $ilAtomQuery->addTableLock("tree");
298 
299  $ilAtomQuery->addQueryCallable($insert_node_callable);
300 
301  $ilAtomQuery->run();
302  } else {
303  $insert_node_callable($ilDB);
304  }
305  }
Thrown if invalid tree strucutes are found.
foreach($_POST as $key=> $value) $res
global $DIC
Definition: goto.php:24
global $ilDB
static getLogger($a_component_id)
Get component logger.
+ Here is the call graph for this function:

◆ moveToTrash()

ilMaterializedPathTree::moveToTrash (   $a_node_id)

Move subtree to trash.

Parameters
type$a_node_id
Returns
bool

Implements ilTreeImplementation.

Definition at line 354 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, and getTree().

355  {
356  global $DIC;
357 
358  $ilDB = $DIC['ilDB'];
359 
360  $move_to_trash_callable = function (ilDBInterface $ilDB) use ($a_node_id) {
361  $node = $this->getTree()->getNodeTreeData($a_node_id);
362 
363  // Set the nodes deleted (negative tree id)
364  $ilDB->manipulateF(
365  '
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')
372  );
373  };
374 
375  // use ilAtomQuery to lock tables if tree is main tree
376  // otherwise just call this closure without locking
377  if ($this->getTree()->__isMainTree()) {
378  $ilAtomQuery = $ilDB->buildAtomQuery();
379  $ilAtomQuery->addTableLock("tree");
380 
381  $ilAtomQuery->addQueryCallable($move_to_trash_callable);
382 
383  $ilAtomQuery->run();
384  } else {
385  $move_to_trash_callable($ilDB);
386  }
387 
388  return true;
389  }
global $DIC
Definition: goto.php:24
global $ilDB
+ Here is the call graph for this function:

◆ moveTree()

ilMaterializedPathTree::moveTree (   $a_source_id,
  $a_target_id,
  $a_position 
)

move source subtree to target node

Parameters
int$a_source_id
int$a_target_id
int$a_position
Returns
bool
Exceptions
InvalidArgumentException

Implements ilTreeImplementation.

Definition at line 400 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, $query, $res, ilLogLevel\ERROR, ilLoggerFactory\getLogger(), getTree(), and ilDBConstants\T_INTEGER.

401  {
402  global $DIC;
403 
404  $ilDB = $DIC['ilDB'];
405 
406  $move_tree_callable = function (ilDBInterface $ilDB) use ($a_source_id, $a_target_id, $a_position) {
407  // Receive node infos for source and target
408  $ilDB->setLimit(2);
409 
410  $res = $ilDB->query(
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')
414  );
415 
416  // Check in tree
417  if ($ilDB->numRows($res) != 2) {
418  ilLoggerFactory::getLogger('tree')->logStack(ilLogLevel::ERROR, 'Objects not found in tree');
419  throw new InvalidArgumentException('Error moving subtree');
420  }
421 
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;
427  } else {
428  $target_path = $row->path;
429  $target_depth = $row->depth;
430  }
431  }
432 
433  if ($target_depth >= $source_depth) {
434  // We move nodes deeper into the tree. Therefore we need to
435  // check whether we might exceed the maximal path length.
436  // We use FOR UPDATE here, because we don't want anyone to
437  // insert new nodes while we move the subtree.
438 
439  $res = $ilDB->queryF(
440  'SELECT MAX(depth) max_depth ' .
441  'FROM ' . $this->getTree()->getTreeTable() . ' ' .
442  'WHERE path BETWEEN %s AND %s' . ' ' .
443  'AND tree = %s ',
444  array('text', 'text', 'integer'),
445  array($source_path, $source_path . '.Z', $this->getTree()->getTreeId())
446  );
447 
448  $row = $ilDB->fetchObject($res);
449 
450  if ($row->max_depth - $source_depth + $target_depth + 1 > $this->getMaximumPossibleDepth()) {
451  ilLoggerFactory::getLogger('tree')->logStack(ilLogLevel::ERROR, 'Objects not found in tree');
452  throw new ilInvalidTreeStructureException('Maximum tree depth exceeded');
453  }
454  }
455  // Check target not child of source
456  if (substr($target_path . '.', 0, strlen($source_path) . '.') == $source_path . '.') {
457  ilLoggerFactory::getLogger('tree')->logStack(ilLogLevel::ERROR, 'Target is child of source');
458  throw new InvalidArgumentException('Error moving subtree: target is child of source');
459  }
460  $depth_diff = $target_depth - $source_depth + 1;
461 
462  // move subtree:
463  $query =
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 = ' .
468  $ilDB->concat(array(
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') . ' ';
474 
475  if (!$this->getTree()->__isMainTree()) {
476  $query .= ('AND ' . $ilDB->quote($this->getTree()->getTreeId(), \ilDBConstants::T_INTEGER));
477  }
478  \ilLoggerFactory::getLogger('tree')->debug('Query is: ' . $query);
479  $ilDB->manipulate($query);
480  };
481 
482 
483  if ($this->getTree()->__isMainTree()) {
484  $ilAtomQuery = $ilDB->buildAtomQuery();
485  $ilAtomQuery->addTableLock("tree");
486  $ilAtomQuery->addQueryCallable($move_tree_callable);
487  $ilAtomQuery->run();
488  } else {
489  $move_tree_callable($ilDB);
490  }
491 
492  return true;
493  }
Thrown if invalid tree strucutes are found.
foreach($_POST as $key=> $value) $res
global $DIC
Definition: goto.php:24
$query
global $ilDB
static getLogger($a_component_id)
Get component logger.
+ Here is the call graph for this function:

◆ validateParentRelations()

ilMaterializedPathTree::validateParentRelations ( )

Validaate parent relations.

Returns
int[] array of failure nodes

Implements ilTreeImplementation.

Definition at line 617 of file class.ilMaterializedPathTree.php.

References $DIC, $ilDB, $query, $res, ilDBConstants\FETCHMODE_ASSOC, ilLoggerFactory\getLogger(), and getTree().

618  {
619  global $DIC;
620 
621  $ilDB = $DIC['ilDB'];
622 
623  $query = 'select child from ' . $this->getTree()->getTreeTable() . ' child where not exists ' .
624  '( ' .
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';
628  $res = $ilDB->query($query);
629 
630  ilLoggerFactory::getLogger('tree')->debug($query);
631 
632  $failures = array();
633  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
634  $failures[] = $row[$this->getTree()->getTreePk()];
635  }
636  return $failures;
637  }
foreach($_POST as $key=> $value) $res
global $DIC
Definition: goto.php:24
$query
global $ilDB
static getLogger($a_component_id)
Get component logger.
+ Here is the call graph for this function:

Field Documentation

◆ $maximum_possible_depth

ilMaterializedPathTree::$maximum_possible_depth = 100
private

Definition at line 18 of file class.ilMaterializedPathTree.php.

Referenced by getMaximumPossibleDepth().

◆ $tree

ilMaterializedPathTree::$tree = null
private

Definition at line 19 of file class.ilMaterializedPathTree.php.

Referenced by getTree().


The documentation for this class was generated from the following file: