ILIAS  trunk Revision v13.0_alpha-62-g3b72d83f2e5
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 (protected ilTree $tree, protected ilDBInterface $db, protected LoggerInterface $logger)
 
 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...
 
 getSubTreeIds (int $a_node_id)
 Get subtree ids for a specific node. More...
 
 getSubTreeQuery (array $a_node, array $a_types=[], bool $a_force_join_reference=true, array $a_fields=[])
 Get subtree query. 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...
 
 getRelation (array $a_node_a, array $a_node_b)
 Get relation of two nodes. More...
 
 getPathIds (int $a_endnode, int $a_startnode=0)
 Get path ids from a startnode to a given endnode. More...
 
 insertNode (int $a_node_id, int $a_parent_id, int $a_pos)
 
 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. More...
 
 getSubtreeInfo (int $a_endnode_id)
 Get subtree info lft, rgt, path, child, type. More...
 
 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. More...
 

Static Public Member Functions

static createFromParentRelation (ilDBInterface $db)
 

Protected Member Functions

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

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

Constructor & Destructor Documentation

◆ __construct()

ilMaterializedPathTree::__construct ( protected ilTree  $tree,
protected ilDBInterface  $db,
protected LoggerInterface  $logger 
)

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

38 {
39 }

Member Function Documentation

◆ createFromParentRelation()

static ilMaterializedPathTree::createFromParentRelation ( ilDBInterface  $db)
static

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

465 : void
466 {
467 $result = $db->queryF('SELECT DISTINCT * FROM tree WHERE parent = %s', ['integer'], [0]);
468
469 while ($row = $db->fetchAssoc($result)) {
471 }
472 }
static createMaterializedPath(ilDBInterface $db, int $parent, string $parentPath)
fetchAssoc(ilDBStatement $statement)
queryF(string $query, array $types, array $values)

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

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

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

474 : void
475 {
476 $q = ' UPDATE tree
477 SET path = CONCAT(COALESCE(' . $db->quote($parentPath, 'text') . ', \'\'), COALESCE( ' . $db->cast(
478 "child",
479 "text"
480 ) . ' , \'\')) WHERE parent = %s';
481 $db->manipulateF($q, ['integer'], [$parent]);
482 $result = $db->queryF('SELECT child FROM tree WHERE parent = %s', ['integer'], [$parent]);
483
484 while ($row = $db->fetchAssoc($result)) {
486 $db,
487 (int) $row['child'],
488 $parentPath . $row['child'] . '.'
489 );
490 }
491 }
cast(string $a_field_name, string $a_dest_type)
quote($value, string $type)
manipulateF(string $query, array $types, array $values)

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

+ Here is the call graph for this function:

◆ deleteTree()

ilMaterializedPathTree::deleteTree ( int  $a_node_id)

Delete tree.

Implements ilTreeImplementation.

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

299 : void
300 {
301 $delete_tree_callable = function (ilDBInterface $ilDB) use ($a_node_id): void {
302 $query = 'SELECT * FROM ' . $this->getTree()->getTreeTable() . ' ' .
303 'WHERE ' . $this->getTree()->getTreeTable() . '.child = %s ' .
304 'AND ' . $this->getTree()->getTreeTable() . '.' . $this->getTree()->getTreePk() . ' = %s ';
305 $res = $this->db->queryF($query, array('integer', 'integer'), array(
306 $a_node_id,
307 $this->getTree()->getTreeId()
308 ));
309 $node = $this->db->fetchAssoc($res);
310
311 if ($node === null) {
312 return; //Nothing to delete. $node does not exists
313 }
314
315 $query = 'DELETE FROM ' . $this->getTree()->getTreeTable() . ' ' .
316 'WHERE path BETWEEN ' . $this->db->quote($node['path'], 'text') . ' ' .
317 'AND ' . $this->db->quote($node['path'] . '.Z', 'text') . ' ' .
318 'AND ' . $this->getTree()->getTreePk() . ' = ' . $this->db->quote(
319 $this->getTree()->getTreeId(),
320 'integer'
321 );
322 $this->db->manipulate($query);
323 };
324
325 // get lft and rgt values. Don't trust parameter lft/rgt values of $a_node
326 if ($this->getTree()->__isMainTree()) {
327 $ilAtomQuery = $this->db->buildAtomQuery();
328 $ilAtomQuery->addTableLock('tree');
329 $ilAtomQuery->addQueryCallable($delete_tree_callable);
330 $ilAtomQuery->run();
331 } else {
332 $delete_tree_callable($this->db);
333 }
334 }
Interface ilDBInterface.
foreach($_POST as $key=> $value) $res

References $ilDB, and $res.

◆ getMaximumPossibleDepth()

ilMaterializedPathTree::getMaximumPossibleDepth ( )
protected

Get maximum possible depth.

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

44 : int
45 {
47 }

References MAXIMUM_POSSIBLE_DEPTH.

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

215 : array
216 {
217 $this->db->setLimit(1, 0);
218 $query = 'SELECT path FROM ' . $this->getTree()->getTreeTable() . ' ' .
219 'WHERE child = ' . $this->db->quote($a_endnode, 'integer') . ' ';
220 $res = $this->db->query($query);
221
222 $path = "";
223 while ($row = $this->db->fetchAssoc($res)) {
224 $path = (string) $row['path'];
225 }
226
227 $pathIds = array_map('intval', explode('.', $path));
228
229 if ($a_startnode != 0) {
230 while (count($pathIds) > 0 && $pathIds[0] != $a_startnode) {
231 array_shift($pathIds);
232 }
233 }
234 return $pathIds;
235 }

References $res.

◆ getRelation()

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

Get relation of two nodes.

Todo:
add test

Implements ilTreeImplementation.

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

88 : int
89 {
90 if ($a_node_a === [] || $a_node_b === []) {
92 }
93 if ($a_node_a['child'] == $a_node_b['child']) {
95 }
96 if (stripos($a_node_a['path'], $a_node_b['path'] . '.') === 0) {
98 }
99 if (stripos($a_node_b['path'], $a_node_a['path'] . '.') === 0) {
101 }
102 $path_a = substr($a_node_a['path'], 0, strrpos($a_node_a['path'], '.'));
103 $path_b = substr($a_node_b['path'], 0, strrpos($a_node_b['path'], '.'));
104 if ($a_node_a['path'] && $path_a === $path_b) {
106 }
108 }
const RELATION_EQUALS
const RELATION_PARENT
const RELATION_NONE
const RELATION_SIBLING
const RELATION_CHILD

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

◆ getSubTreeIds()

ilMaterializedPathTree::getSubTreeIds ( int  $a_node_id)

Get subtree ids.

Parameters
int$a_node_id
Returns
int[]

Implements ilTreeImplementation.

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

62 : array
63 {
64 $node = $this->getTree()->getNodeTreeData($a_node_id);
65 $query = 'SELECT child FROM ' . $this->getTree()->getTreeTable() . ' ' .
66 'WHERE path BETWEEN ' .
67 $this->db->quote($node['path'], 'text') . ' AND ' .
68 $this->db->quote($node['path'] . '.Z', 'text') . ' ' .
69 'AND child != %s ' .
70 'AND ' . $this->getTree()->getTreePk() . ' = %s';
71
72 $res = $this->db->queryF(
73 $query,
74 array('integer', 'integer'),
75 array($a_node_id, $this->getTree()->getTreeId())
76 );
77 $childs = [];
78 while ($row = $this->db->fetchAssoc($res)) {
79 $childs[] = (int) $row['child'];
80 }
81 return $childs;
82 }

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

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

497 : array
498 {
499 if ($this->getTree()->__isMainTree() && $this->getTree()->getTreeId() == 1) {
500 $treeClause1 = '';
501 $treeClause2 = '';
502 } else {
503 $treeClause1 = ' AND t1.' . $this->getTree()->getTreePk() . ' = ' . $this->db->quote(
504 $this->getTree()->getTreeId(),
505 'integer'
506 );
507 $treeClause2 = ' AND t2.' . $this->getTree()->getTreePk() . ' = ' . $this->db->quote(
508 $this->getTree()->getTreeId(),
509 'integer'
510 );
511 }
512
513 // first query for the path of the given node
514 $query = "
515 SELECT t1." . $this->getTree()->getTreePk() . ", t1.path
516 FROM " . $this->getTree()->getTreeTable() . " t1
517 WHERE t1.child = " . $this->db->quote($a_endnode_id, 'integer') .
518 $treeClause1;
519
520 $res = $this->db->query($query);
521 $row = $this->db->fetchAssoc($res);
522 if ($row[$this->getTree()->getTreePk()] ?? null == $this->getTree()->getTreeId()) {
523 $path = (string) $row['path'];
524 } else {
525 return [];
526 }
527
528 // then query for the nodes in that path
529 $query = "SELECT t2." . $this->getTree()->getTreePk() . ", t2.child child, t2.parent parent, type, t2.path path " .
530 "FROM " . $this->getTree()->getTreeTable() . " t2 " .
531 "JOIN " . $this->getTree()->getTableReference() . " obr ON t2.child = obr.ref_id " .
532 "JOIN " . $this->getTree()->getObjectDataTable() . " obd ON obr.obj_id = obd.obj_id " .
533 "WHERE t2.path BETWEEN " . $this->db->quote($path, 'text') . " AND " . $this->db->quote(
534 $path . '.Z',
535 'text'
536 ) .
537 $treeClause2 . ' ' .
538 "ORDER BY t2.path";
539
540 $res = $this->db->query($query);
541 $nodes = [];
542 while ($row = $this->db->fetchAssoc($res)) {
543 // filter out deleted items if tree is repository
544 if ($row[$this->getTree()->getTreePk()] != $this->getTree()->getTreeId()) {
545 continue;
546 }
547
548 $nodes[$row['child']]['child'] = (int) $row['child'];
549 $nodes[$row['child']]['parent'] = (int) $row['parent'];
550 $nodes[$row['child']]['type'] = (string) $row['type'];
551 $nodes[$row['child']]['path'] = (string) $row['path'];
552 }
553
554 $depth_first_compare = static function (array $a, array $b): int {
555 $a_exploded = explode('.', $a['path']);
556 $b_exploded = explode('.', $b['path']);
557
558 $a_padded = '';
559 foreach ($a_exploded as $num) {
560 $a_padded .= (str_pad((string) $num, 14, '0', STR_PAD_LEFT));
561 }
562 $b_padded = '';
563 foreach ($b_exploded as $num) {
564 $b_padded .= (str_pad((string) $num, 14, '0', STR_PAD_LEFT));
565 }
566
567 return strcasecmp($a_padded, $b_padded);
568 };
569
570 uasort($nodes, $depth_first_compare);
571
572 return $nodes;
573 }
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples

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

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

170 : string {
171 $type_str = '';
172 if (count($a_types)) {
173 if ($a_types) {
174 $type_str = "AND " . $this->db->in(
175 $this->getTree()->getObjectDataTable() . ".type",
176 $a_types,
177 false,
178 "text"
179 );
180 }
181 }
182
183 $join = '';
184 if ($type_str || $a_force_join_reference) {
185 $join = $this->getTree()->buildJoin();
186 }
187
188 $fields = '* ';
189 if (count($a_fields)) {
190 $fields = implode(',', $a_fields);
191 }
192
193 // @todo order by
194 $query = 'SELECT ' .
195 $fields . ' ' .
196 'FROM ' . $this->getTree()->getTreeTable() . ' ' .
197 $join . ' ' .
198 'WHERE ' . $this->getTree()->getTreeTable() . '.path ' .
199 'BETWEEN ' .
200 $this->db->quote($a_node['path'], 'text') . ' AND ' .
201 $this->db->quote($a_node['path'] . '.Z', 'text') . ' ' .
202 'AND ' . $this->getTree()->getTreeTable() . '.' . $this->getTree()->getTreePk() . ' = ' . $this->db->quote(
203 $this->getTree()->getTreeId(),
204 'integer'
205 ) . ' ' .
206 $type_str . ' ' .
207 'ORDER BY ' . $this->getTree()->getTreeTable() . '.path';
208
209 return $query;
210 }

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

118 : string {
119 $type_str = '';
120 if (is_array($a_types)) {
121 if ($a_types) {
122 $type_str = "AND " . $this->db->in(
123 $this->getTree()->getObjectDataTable() . ".type",
124 $a_types,
125 false,
126 "text"
127 );
128 }
129 }
130
131 $join = '';
132 if ($type_str || $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 $this->db->quote($a_node['path'], 'text') . ' AND ' .
149 $this->db->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 }

References getTree().

+ Here is the call graph for this function:

◆ getTree()

ilMaterializedPathTree::getTree ( )
protected

Get tree object.

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

52 : \ilTree
53 {
54 return $this->tree;
55 }
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...

Referenced by getSubTreeIds(), and getTrashSubTreeQuery().

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

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

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

+ Here is the call graph for this function:

◆ moveToTrash()

ilMaterializedPathTree::moveToTrash ( int  $a_node_id)

Move subtree to trash.

Implements ilTreeImplementation.

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

339 : void
340 {
341 $move_to_trash_callable = function (ilDBInterface $ilDB) use ($a_node_id): void {
342 $node = $this->getTree()->getNodeTreeData($a_node_id);
343
344 // Set the nodes deleted (negative tree id)
345 $this->db->manipulateF(
346 '
347 UPDATE ' . $this->getTree()->getTreeTable() . ' ' .
348 'SET tree = %s' . ' ' .
349 'WHERE ' . $this->getTree()->getTreePk() . ' = %s ' .
350 'AND path BETWEEN %s AND %s',
351 array('integer', 'integer', 'text', 'text'),
352 array(-$a_node_id, $this->getTree()->getTreeId(), $node['path'], $node['path'] . '.Z')
353 );
354 };
355
356 // use ilAtomQuery to lock tables if tree is main tree
357 // otherwise just call this closure without locking
358 if ($this->getTree()->__isMainTree()) {
359 $ilAtomQuery = $this->db->buildAtomQuery();
360 $ilAtomQuery->addTableLock("tree");
361
362 $ilAtomQuery->addQueryCallable($move_to_trash_callable);
363
364 $ilAtomQuery->run();
365 } else {
366 $move_to_trash_callable($this->db);
367 }
368 }

References $ilDB.

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

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

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

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

578 : array
579 {
580 $query = 'select ' . $this->getTree()->getTreePk() . ', child from ' . $this->getTree()->getTreeTable() . ' child where not exists ' .
581 '( ' .
582 'select child from ' . $this->getTree()->getTreeTable() . ' parent where child.parent = parent.child and ' .
583 '(child.path BETWEEN parent.path AND CONCAT(parent.path,' . $this->db->quote('Z', 'text') . ') )' . ')' .
584 'and ' . $this->getTree()->getTreePk() . ' = ' . $this->getTree()->getTreeId() . ' and child <> 1';
585 $res = $this->db->query($query);
586 $failures = array();
587 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
588 $failures[] = $row[$this->getTree()->getTreePk()];
589 }
590 return $failures;
591 }
const FETCHMODE_ASSOC

References $res, and ilDBConstants\FETCHMODE_ASSOC.

Field Documentation

◆ MAXIMUM_POSSIBLE_DEPTH

const ilMaterializedPathTree::MAXIMUM_POSSIBLE_DEPTH = 100
private

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

Referenced by getMaximumPossibleDepth().


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