ILIAS  trunk Revision v11.0_alpha-1744-gb0451eebef4
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator 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...
 
 getSubTreeIds (int $a_node_id)
 Get subtree ids. More...
 
 getRelation (array $a_node_a, array $a_node_b)
 Get relation of two nodes. More...
 
 getTrashSubTreeQuery (array $a_node, array $a_types, bool $a_force_join_reference=true, array $a_fields=[])
 Get subtree query for trashed tree items. More...
 
 getSubTreeQuery (array $a_node, array $a_types=[], bool $a_force_join_reference=true, array $a_fields=[])
 Get subtree query. More...
 
 getPathIds (int $a_endnode, int $a_startnode=0)
 Get path ids from a startnode to a given endnode.
Parameters
int$a_endnode
int$a_startnode
Returns
int[]
More...
 
 insertNode (int $a_node_id, int $a_parent_id, int $a_pos)
 
Exceptions
ilInvalidTreeStructureException
More...
 
 deleteTree (int $a_node_id)
 Delete tree. More...
 
 moveToTrash (int $a_node_id)
 Move subtree to trash. More...
 
 moveTree (int $a_source_id, int $a_target_id, int $a_position)
 Move a source subtree to target.
Exceptions
InvalidArgumentException
More...
 
 getSubtreeInfo (int $a_endnode_id)
 
 validateParentRelations ()
 Validate the parent relations of the tree implementation For nested set, validate the lft, rgt against child <-> parent For materialized path validate path against child <-> parent.
Returns
int[] array of failure nodes
More...
 

Static Public Member Functions

static createFromParentRelation (ilDBInterface $db)
 

Protected Member Functions

 getMaximumPossibleDepth ()
 Get maximum possible depth. More...
 
 getTree ()
 Get tree object. More...
 

Protected Attributes

ilTree $tree
 
ilDBInterface $db
 
ilLogger $logger
 

Static Private Member Functions

static createMaterializedPath (ilDBInterface $db, int $parent, string $parentPath)
 

Private Attributes

const MAXIMUM_POSSIBLE_DEPTH = 100
 

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 28 of file class.ilMaterializedPathTree.php.

Constructor & Destructor Documentation

◆ __construct()

ilMaterializedPathTree::__construct ( ilTree  $a_tree)

Constructor.

Parameters
ilTree$a_tree

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

References $DIC, ilContext\getType(), and ILIAS\Repository\logger().

41  {
42  global $DIC;
43 
44  $this->tree = $a_tree;
45  $this->db = $DIC->database();
46  if (ilContext::getType() != "") {
47  $this->logger = $DIC->logger()->tree();
48  }
49  }
global $DIC
Definition: shib_login.php:22
static getType()
Get context type.
+ Here is the call graph for this function:

Member Function Documentation

◆ createFromParentRelation()

static ilMaterializedPathTree::createFromParentRelation ( ilDBInterface  $db)
static

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

References ilDBInterface\fetchAssoc(), and ilDBInterface\queryF().

Referenced by ilTreeImplementationSwitch\achieve(), and ilSCTreeTasksGUI\repairStructure().

475  : void
476  {
477  $result = $db->queryF('SELECT DISTINCT * FROM tree WHERE parent = %s', ['integer'], [0]);
478 
479  while ($row = $db->fetchAssoc($result)) {
480  self::createMaterializedPath($db, 0, '');
481  }
482  }
fetchAssoc(ilDBStatement $statement)
queryF(string $query, array $types, array $values)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ createMaterializedPath()

static ilMaterializedPathTree::createMaterializedPath ( ilDBInterface  $db,
int  $parent,
string  $parentPath 
)
staticprivate

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

References $q, ilDBInterface\cast(), ilDBInterface\fetchAssoc(), ilDBInterface\manipulateF(), ilDBInterface\queryF(), and ilDBInterface\quote().

484  : void
485  {
486  $q = ' UPDATE tree
487  SET path = CONCAT(COALESCE(' . $db->quote($parentPath, 'text') . ', \'\'), COALESCE( ' . $db->cast(
488  "child",
489  "text"
490  ) . ' , \'\')) WHERE parent = %s';
491  $db->manipulateF($q, ['integer'], [$parent]);
492  $result = $db->queryF('SELECT child FROM tree WHERE parent = %s', ['integer'], [$parent]);
493 
494  while ($row = $db->fetchAssoc($result)) {
495  self::createMaterializedPath(
496  $db,
497  (int) $row['child'],
498  $parentPath . $row['child'] . '.'
499  );
500  }
501  }
manipulateF(string $query, array $types, array $values)
fetchAssoc(ilDBStatement $statement)
quote($value, string $type)
cast(string $a_field_name, string $a_dest_type)
queryF(string $query, array $types, array $values)
$q
Definition: shib_logout.php:21
+ Here is the call graph for this function:

◆ deleteTree()

ilMaterializedPathTree::deleteTree ( int  $a_node_id)

Delete tree.

Implements ilTreeImplementation.

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

References $ilDB, $res, getTree(), and null.

309  : void
310  {
311  $delete_tree_callable = function (ilDBInterface $ilDB) use ($a_node_id): void {
312  $query = 'SELECT * FROM ' . $this->getTree()->getTreeTable() . ' ' .
313  'WHERE ' . $this->getTree()->getTreeTable() . '.child = %s ' .
314  'AND ' . $this->getTree()->getTreeTable() . '.' . $this->getTree()->getTreePk() . ' = %s ';
315  $res = $this->db->queryF($query, array('integer', 'integer'), array(
316  $a_node_id,
317  $this->getTree()->getTreeId()
318  ));
319  $node = $this->db->fetchAssoc($res);
320 
321  if($node === null) {
322  return; //Nothing to delete. $node does not exists
323  }
324 
325  $query = 'DELETE FROM ' . $this->getTree()->getTreeTable() . ' ' .
326  'WHERE path BETWEEN ' . $this->db->quote($node['path'], 'text') . ' ' .
327  'AND ' . $this->db->quote($node['path'] . '.Z', 'text') . ' ' .
328  'AND ' . $this->getTree()->getTreePk() . ' = ' . $this->db->quote(
329  $this->getTree()->getTreeId(),
330  'integer'
331  );
332  $this->db->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 = $this->db->buildAtomQuery();
338  $ilAtomQuery->addTableLock('tree');
339  $ilAtomQuery->addQueryCallable($delete_tree_callable);
340  $ilAtomQuery->run();
341  } else {
342  $delete_tree_callable($this->db);
343  }
344  }
$res
Definition: ltiservices.php:66
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
+ Here is the call graph for this function:

◆ getMaximumPossibleDepth()

ilMaterializedPathTree::getMaximumPossibleDepth ( )
protected

Get maximum possible depth.

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

54  : int
55  {
56  return self::MAXIMUM_POSSIBLE_DEPTH;
57  }

◆ getPathIds()

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

Get path ids from a startnode to a given endnode.

Parameters
int$a_endnode
int$a_startnode
Returns
int[]

Implements ilTreeImplementation.

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

References $path, $res, and getTree().

225  : array
226  {
227  $this->db->setLimit(1, 0);
228  $query = 'SELECT path FROM ' . $this->getTree()->getTreeTable() . ' ' .
229  'WHERE child = ' . $this->db->quote($a_endnode, 'integer') . ' ';
230  $res = $this->db->query($query);
231 
232  $path = "";
233  while ($row = $this->db->fetchAssoc($res)) {
234  $path = (string) $row['path'];
235  }
236 
237  $pathIds = array_map('intval', explode('.', $path));
238 
239  if ($a_startnode != 0) {
240  while (count($pathIds) > 0 && $pathIds[0] != $a_startnode) {
241  array_shift($pathIds);
242  }
243  }
244  return $pathIds;
245  }
$res
Definition: ltiservices.php:66
$path
Definition: ltiservices.php:29
+ Here is the call graph for this function:

◆ getRelation()

ilMaterializedPathTree::getRelation ( array  $a_node_a,
array  $a_node_b 
)

Get relation of two nodes.

Todo:
add test

Implements ilTreeImplementation.

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

References ilTree\RELATION_CHILD, ilTree\RELATION_EQUALS, ilTree\RELATION_NONE, ilTree\RELATION_PARENT, and ilTree\RELATION_SIBLING.

98  : int
99  {
100  if ($a_node_a === [] || $a_node_b === []) {
101  return ilTree::RELATION_NONE;
102  }
103  if ($a_node_a['child'] == $a_node_b['child']) {
105  }
106  if (stripos($a_node_a['path'], $a_node_b['path'] . '.') === 0) {
107  return ilTree::RELATION_CHILD;
108  }
109  if (stripos($a_node_b['path'], $a_node_a['path'] . '.') === 0) {
111  }
112  $path_a = substr($a_node_a['path'], 0, strrpos($a_node_a['path'], '.'));
113  $path_b = substr($a_node_b['path'], 0, strrpos($a_node_b['path'], '.'));
114  if ($a_node_a['path'] && $path_a === $path_b) {
116  }
117  return ilTree::RELATION_NONE;
118  }
const RELATION_PARENT
const RELATION_EQUALS
const RELATION_CHILD
const RELATION_NONE
const RELATION_SIBLING

◆ getSubTreeIds()

ilMaterializedPathTree::getSubTreeIds ( int  $a_node_id)

Get subtree ids.

Parameters
int$a_node_id
Returns
int[]

Implements ilTreeImplementation.

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

References $res, getTree(), and ILIAS\Repository\int().

72  : array
73  {
74  $node = $this->getTree()->getNodeTreeData($a_node_id);
75  $query = 'SELECT child FROM ' . $this->getTree()->getTreeTable() . ' ' .
76  'WHERE path BETWEEN ' .
77  $this->db->quote($node['path'], 'text') . ' AND ' .
78  $this->db->quote($node['path'] . '.Z', 'text') . ' ' .
79  'AND child != %s ' .
80  'AND ' . $this->getTree()->getTreePk() . ' = %s';
81 
82  $res = $this->db->queryF(
83  $query,
84  array('integer', 'integer'),
85  array($a_node_id, $this->getTree()->getTreeId())
86  );
87  $childs = [];
88  while ($row = $this->db->fetchAssoc($res)) {
89  $childs[] = (int) $row['child'];
90  }
91  return $childs;
92  }
$res
Definition: ltiservices.php:66
+ Here is the call graph for this function:

◆ getSubtreeInfo()

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

Implements ilTreeImplementation.

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

References Vendor\Package\$a, Vendor\Package\$b, $path, $res, getTree(), ILIAS\Repository\int(), and null.

507  : array
508  {
509  if ($this->getTree()->__isMainTree() && $this->getTree()->getTreeId() == 1) {
510  $treeClause1 = '';
511  $treeClause2 = '';
512  } else {
513  $treeClause1 = ' AND t1.' . $this->getTree()->getTreePk() . ' = ' . $this->db->quote(
514  $this->getTree()->getTreeId(),
515  'integer'
516  );
517  $treeClause2 = ' AND t2.' . $this->getTree()->getTreePk() . ' = ' . $this->db->quote(
518  $this->getTree()->getTreeId(),
519  'integer'
520  );
521  }
522 
523  // first query for the path of the given node
524  $query = "
525  SELECT t1." . $this->getTree()->getTreePk() . ", t1.path
526  FROM " . $this->getTree()->getTreeTable() . " t1
527  WHERE t1.child = " . $this->db->quote($a_endnode_id, 'integer') .
528  $treeClause1;
529 
530  $res = $this->db->query($query);
531  $row = $this->db->fetchAssoc($res);
532  if ($row[$this->getTree()->getTreePk()] ?? null == $this->getTree()->getTreeId()) {
533  $path = (string) $row['path'];
534  } else {
535  return [];
536  }
537 
538  // then query for the nodes in that path
539  $query = "SELECT t2." . $this->getTree()->getTreePk() . ", t2.child child, t2.parent parent, type, t2.path path " .
540  "FROM " . $this->getTree()->getTreeTable() . " t2 " .
541  "JOIN " . $this->getTree()->getTableReference() . " obr ON t2.child = obr.ref_id " .
542  "JOIN " . $this->getTree()->getObjectDataTable() . " obd ON obr.obj_id = obd.obj_id " .
543  "WHERE t2.path BETWEEN " . $this->db->quote($path, 'text') . " AND " . $this->db->quote(
544  $path . '.Z',
545  'text'
546  ) .
547  $treeClause2 . ' ' .
548  "ORDER BY t2.path";
549 
550  $res = $this->db->query($query);
551  $nodes = [];
552  while ($row = $this->db->fetchAssoc($res)) {
553  // filter out deleted items if tree is repository
554  if ($row[$this->getTree()->getTreePk()] != $this->getTree()->getTreeId()) {
555  continue;
556  }
557 
558  $nodes[$row['child']]['child'] = (int) $row['child'];
559  $nodes[$row['child']]['parent'] = (int) $row['parent'];
560  $nodes[$row['child']]['type'] = (string) $row['type'];
561  $nodes[$row['child']]['path'] = (string) $row['path'];
562  }
563 
564  $depth_first_compare = static function (array $a, array $b): int {
565  $a_exploded = explode('.', $a['path']);
566  $b_exploded = explode('.', $b['path']);
567 
568  $a_padded = '';
569  foreach ($a_exploded as $num) {
570  $a_padded .= (str_pad((string) $num, 14, '0', STR_PAD_LEFT));
571  }
572  $b_padded = '';
573  foreach ($b_exploded as $num) {
574  $b_padded .= (str_pad((string) $num, 14, '0', STR_PAD_LEFT));
575  }
576 
577  return strcasecmp($a_padded, $b_padded);
578  };
579 
580  uasort($nodes, $depth_first_compare);
581 
582  return $nodes;
583  }
$res
Definition: ltiservices.php:66
$path
Definition: ltiservices.php:29
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
$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 ( array  $a_node,
array  $a_types = [],
bool  $a_force_join_reference = true,
array  $a_fields = [] 
)

Get subtree query.

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

Implements ilTreeImplementation.

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

References getTree().

180  : string {
181  $type_str = '';
182  if (count($a_types)) {
183  if ($a_types) {
184  $type_str = "AND " . $this->db->in(
185  $this->getTree()->getObjectDataTable() . ".type",
186  $a_types,
187  false,
188  "text"
189  );
190  }
191  }
192 
193  $join = '';
194  if ($type_str || $a_force_join_reference) {
195  $join = $this->getTree()->buildJoin();
196  }
197 
198  $fields = '* ';
199  if (count($a_fields)) {
200  $fields = implode(',', $a_fields);
201  }
202 
203  // @todo order by
204  $query = 'SELECT ' .
205  $fields . ' ' .
206  'FROM ' . $this->getTree()->getTreeTable() . ' ' .
207  $join . ' ' .
208  'WHERE ' . $this->getTree()->getTreeTable() . '.path ' .
209  'BETWEEN ' .
210  $this->db->quote($a_node['path'], 'text') . ' AND ' .
211  $this->db->quote($a_node['path'] . '.Z', 'text') . ' ' .
212  'AND ' . $this->getTree()->getTreeTable() . '.' . $this->getTree()->getTreePk() . ' = ' . $this->db->quote(
213  $this->getTree()->getTreeId(),
214  'integer'
215  ) . ' ' .
216  $type_str . ' ' .
217  'ORDER BY ' . $this->getTree()->getTreeTable() . '.path';
218 
219  return $query;
220  }
+ Here is the call graph for this function:

◆ getTrashSubTreeQuery()

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

Get subtree query for trashed tree items.

Implements ilTreeImplementation.

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

References getTree().

128  : string {
129  $type_str = '';
130  if (is_array($a_types)) {
131  if ($a_types) {
132  $type_str = "AND " . $this->db->in(
133  $this->getTree()->getObjectDataTable() . ".type",
134  $a_types,
135  false,
136  "text"
137  );
138  }
139  }
140 
141  $join = '';
142  if ($type_str || $a_force_join_reference) {
143  $join = $this->getTree()->buildJoin();
144  }
145 
146  $fields = '* ';
147  if (count($a_fields)) {
148  $fields = implode(',', $a_fields);
149  }
150 
151  // @todo order by
152  $query = 'SELECT ' .
153  $fields . ' ' .
154  'FROM ' . $this->getTree()->getTreeTable() . ' ' .
155  $join . ' ' .
156  'WHERE ' . $this->getTree()->getTreeTable() . '.path ' .
157  'BETWEEN ' .
158  $this->db->quote($a_node['path'], 'text') . ' AND ' .
159  $this->db->quote($a_node['path'] . '.Z', 'text') . ' ' .
160  'AND ' . $this->getTree()->getTreeTable() . '.' . $this->getTree()->getTreePk() . ' < 0 ' .
161  $type_str . ' ' .
162  'ORDER BY ' . $this->getTree()->getTreeTable() . '.path';
163 
164  return $query;
165  }
+ Here is the call graph for this function:

◆ getTree()

ilMaterializedPathTree::getTree ( )
protected

Get tree object.

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

References $tree.

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

62  : \ilTree
63  {
64  return $this->tree;
65  }
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
+ Here is the caller graph for this function:

◆ insertNode()

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

Exceptions
ilInvalidTreeStructureException

Implements ilTreeImplementation.

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

References $ilDB, $r, $res, ilLogLevel\ERROR, getTree(), ILIAS\Repository\int(), ILIAS\Repository\logger(), and null.

250  : void
251  {
252  $insert_node_callable = function (ilDBInterface $ilDB) use ($a_node_id, $a_parent_id, $a_pos): void {
253  // get path and depth of parent
254  $this->db->setLimit(1, 0);
255 
256  $res = $this->db->queryF(
257  'SELECT parent, depth, path FROM ' . $this->getTree()->getTreeTable() . ' ' .
258  'WHERE child = %s ' . ' ' .
259  'AND ' . $this->getTree()->getTreePk() . ' = %s',
260  array('integer', 'integer'),
261  array($a_parent_id, $this->getTree()->getTreeId())
262  );
263 
264  $r = $this->db->fetchObject($res);
265 
266  if ($r->parent === null) {
267  $this->logger->logStack(ilLogLevel::ERROR);
268  throw new ilInvalidTreeStructureException('Parent node not found in tree');
269  }
270 
271  if ($r->depth >= $this->getMaximumPossibleDepth()) {
272  $this->logger->logStack(ilLogLevel::ERROR);
273  throw new ilInvalidTreeStructureException('Maximum tree depth exceeded');
274  }
275 
276  $parentPath = $r->path;
277  $depth = (int) $r->depth + 1;
278  $lft = 0;
279  $rgt = 0;
280 
281  $this->db->insert(
282  $this->getTree()->getTreeTable(),
283  array($this->getTree()->getTreePk() => array('integer', $this->getTree()->getTreeId()),
284  'child' => array('integer', $a_node_id),
285  'parent' => array('integer', $a_parent_id),
286  'lft' => array('integer', $lft),
287  'rgt' => array('integer', $rgt),
288  'depth' => array('integer', $depth),
289  'path' => array('text', $parentPath . "." . $a_node_id)
290  )
291  );
292  };
293 
294  // use ilAtomQuery to lock tables if tree is main tree
295  // otherwise just call this closure without locking
296  if ($this->getTree()->__isMainTree()) {
297  $ilAtomQuery = $this->db->buildAtomQuery();
298  $ilAtomQuery->addTableLock("tree");
299  $ilAtomQuery->addQueryCallable($insert_node_callable);
300  $ilAtomQuery->run();
301  } else {
302  $insert_node_callable($this->db);
303  }
304  }
Thrown if invalid tree strucutes are found.
$res
Definition: ltiservices.php:66
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
$r
+ Here is the call graph for this function:

◆ moveToTrash()

ilMaterializedPathTree::moveToTrash ( int  $a_node_id)

Move subtree to trash.

Implements ilTreeImplementation.

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

References $ilDB, and getTree().

349  : void
350  {
351  $move_to_trash_callable = function (ilDBInterface $ilDB) use ($a_node_id): void {
352  $node = $this->getTree()->getNodeTreeData($a_node_id);
353 
354  // Set the nodes deleted (negative tree id)
355  $this->db->manipulateF(
356  '
357  UPDATE ' . $this->getTree()->getTreeTable() . ' ' .
358  'SET tree = %s' . ' ' .
359  'WHERE ' . $this->getTree()->getTreePk() . ' = %s ' .
360  'AND path BETWEEN %s AND %s',
361  array('integer', 'integer', 'text', 'text'),
362  array(-$a_node_id, $this->getTree()->getTreeId(), $node['path'], $node['path'] . '.Z')
363  );
364  };
365 
366  // use ilAtomQuery to lock tables if tree is main tree
367  // otherwise just call this closure without locking
368  if ($this->getTree()->__isMainTree()) {
369  $ilAtomQuery = $this->db->buildAtomQuery();
370  $ilAtomQuery->addTableLock("tree");
371 
372  $ilAtomQuery->addQueryCallable($move_to_trash_callable);
373 
374  $ilAtomQuery->run();
375  } else {
376  $move_to_trash_callable($this->db);
377  }
378  }
+ Here is the call graph for this function:

◆ moveTree()

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

Move a source subtree to target.

Exceptions
InvalidArgumentException

Todo:
check "$this->db->substr(..." call with parameters

Implements ilTreeImplementation.

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

References $ilDB, $res, ilLogLevel\ERROR, getTree(), ILIAS\Repository\logger(), and ilDBConstants\T_INTEGER.

384  : void
385  {
386  $move_tree_callable = function (ilDBInterface $ilDB) use ($a_source_id, $a_target_id, $a_position): void {
387  // Receive node infos for source and target
388  $this->db->setLimit(2, 0);
389 
390  $res = $this->db->query(
391  'SELECT depth, child, parent, path FROM ' . $this->getTree()->getTreeTable() . ' ' .
392  'WHERE ' . $this->db->in('child', array($a_source_id, $a_target_id), false, 'integer') . ' ' .
393  'AND tree = ' . $this->db->quote($this->getTree()->getTreeId(), 'integer')
394  );
395 
396  // Check in tree
397  if ($this->db->numRows($res) != 2) {
398  $this->logger->logStack(ilLogLevel::ERROR, 'Objects not found in tree');
399  throw new InvalidArgumentException('Error moving subtree');
400  }
401 
402  $source_depth = $target_depth = 0;
403  $source_path = $target_path = '';
404  $source_parent = 0;
405  while ($row = $this->db->fetchObject($res)) {
406  if ($row->child == $a_source_id) {
407  $source_path = $row->path;
408  $source_depth = $row->depth;
409  $source_parent = $row->parent;
410  } else {
411  $target_path = $row->path;
412  $target_depth = $row->depth;
413  }
414  }
415 
416  if ($target_depth >= $source_depth) {
417  // We move nodes deeper into the tree. Therefore we need to
418  // check whether we might exceed the maximal path length.
419  // We use FOR UPDATE here, because we don't want anyone to
420  // insert new nodes while we move the subtree.
421 
422  $res = $this->db->queryF(
423  'SELECT MAX(depth) max_depth ' .
424  'FROM ' . $this->getTree()->getTreeTable() . ' ' .
425  'WHERE path BETWEEN %s AND %s' . ' ' .
426  'AND tree = %s ',
427  array('text', 'text', 'integer'),
428  array($source_path, $source_path . '.Z', $this->getTree()->getTreeId())
429  );
430 
431  $row = $this->db->fetchObject($res);
432 
433  if ($row->max_depth - $source_depth + $target_depth + 1 > $this->getMaximumPossibleDepth()) {
434  $this->logger->logStack(ilLogLevel::ERROR, 'Objects not found in tree');
435  throw new ilInvalidTreeStructureException('Maximum tree depth exceeded');
436  }
437  }
438  // Check target not child of source
439  if ((substr($target_path . '.', 0, strlen($source_path)) . '.') == $source_path . '.') {
440  $this->logger->logStack(ilLogLevel::ERROR, 'Target is child of source');
441  throw new InvalidArgumentException('Error moving subtree: target is child of source');
442  }
443  $depth_diff = $target_depth - $source_depth + 1;
444 
445  // move subtree:
446  $query =
447  'UPDATE ' . $this->getTree()->getTreeTable() . ' ' .
448  'SET parent = CASE WHEN parent = ' . $this->db->quote($source_parent, 'integer') . ' ' .
449  'THEN ' . $this->db->quote($a_target_id, 'integer') . ' ' .
450  'ELSE parent END, path = ' .
451  $this->db->concat(array(
452  array($this->db->quote($target_path, 'text'), 'text'),
453  array($this->db->substr('path', strrpos('.' . $source_path, '.')), 'text')
454  )) . ' ' .
455  ',depth = depth + ' . $this->db->quote($depth_diff, 'integer') . ' ' .
456  'WHERE path BETWEEN ' . $this->db->quote($source_path, 'text') . ' ' .
457  'AND ' . $this->db->quote($source_path . '.Z', 'text') . ' ';
458 
459  if (!$this->getTree()->__isMainTree()) {
460  $query .= ('AND ' . $this->db->quote($this->getTree()->getTreeId(), \ilDBConstants::T_INTEGER));
461  }
462  $this->db->manipulate($query);
463  };
464 
465  if ($this->getTree()->__isMainTree()) {
466  $ilAtomQuery = $this->db->buildAtomQuery();
467  $ilAtomQuery->addTableLock("tree");
468  $ilAtomQuery->addQueryCallable($move_tree_callable);
469  $ilAtomQuery->run();
470  } else {
471  $move_tree_callable($this->db);
472  }
473  }
Thrown if invalid tree strucutes are found.
$res
Definition: ltiservices.php:66
+ Here is the call graph for this function:

◆ validateParentRelations()

ilMaterializedPathTree::validateParentRelations ( )

Validate the parent relations of the tree implementation For nested set, validate the lft, rgt against child <-> parent For materialized path validate path against child <-> parent.

Returns
int[] array of failure nodes

Implements ilTreeImplementation.

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

References $res, ilDBConstants\FETCHMODE_ASSOC, and getTree().

588  : array
589  {
590  $query = 'select ' . $this->getTree()->getTreePk() .', child from ' . $this->getTree()->getTreeTable() . ' child where not exists ' .
591  '( ' .
592  'select child from ' . $this->getTree()->getTreeTable() . ' parent where child.parent = parent.child and ' .
593  '(child.path BETWEEN parent.path AND CONCAT(parent.path,' . $this->db->quote('Z', 'text') . ') )' . ')' .
594  'and ' . $this->getTree()->getTreePk() . ' = ' . $this->getTree()->getTreeId() . ' and child <> 1';
595  $res = $this->db->query($query);
596  $failures = array();
597  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
598  $failures[] = $row[$this->getTree()->getTreePk()];
599  }
600  return $failures;
601  }
$res
Definition: ltiservices.php:66
+ Here is the call graph for this function:

Field Documentation

◆ $db

ilDBInterface ilMaterializedPathTree::$db
protected

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

◆ $logger

ilLogger ilMaterializedPathTree::$logger
protected

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

◆ $tree

ilTree ilMaterializedPathTree::$tree
protected

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

Referenced by getTree().

◆ MAXIMUM_POSSIBLE_DEPTH

const ilMaterializedPathTree::MAXIMUM_POSSIBLE_DEPTH = 100
private

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


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