ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
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...
 
 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...
 

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.

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 }
static getType()
Get context type.
global $DIC
Definition: shib_login.php:26

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

+ 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.

475 : void
476 {
477 $result = $db->queryF('SELECT DISTINCT * FROM tree WHERE parent = %s', ['integer'], [0]);
478
479 while ($row = $db->fetchAssoc($result)) {
481 }
482 }
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 484 of file class.ilMaterializedPathTree.php.

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)) {
496 $db,
497 (int) $row['child'],
498 $parentPath . $row['child'] . '.'
499 );
500 }
501 }
cast(string $a_field_name, string $a_dest_type)
quote($value, string $type)
manipulateF(string $query, array $types, array $values)
$q
Definition: shib_logout.php:23

References $q, 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 309 of file class.ilMaterializedPathTree.php.

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 }
Interface ilDBInterface.
$res
Definition: ltiservices.php:69

References $ilDB, and $res.

◆ getMaximumPossibleDepth()

ilMaterializedPathTree::getMaximumPossibleDepth ( )
protected

Get maximum possible depth.

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

54 : int
55 {
57 }

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

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 }
$path
Definition: ltiservices.php:30

References $path, and $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 98 of file class.ilMaterializedPathTree.php.

98 : int
99 {
100 if ($a_node_a === [] || $a_node_b === []) {
102 }
103 if ($a_node_a['child'] == $a_node_b['child']) {
105 }
106 if (stripos($a_node_a['path'], $a_node_b['path'] . '.') === 0) {
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 }
118 }
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 72 of file class.ilMaterializedPathTree.php.

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 }

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

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 }
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples

References Vendor\Package\$a, Vendor\Package\$b, $path, $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 175 of file class.ilMaterializedPathTree.php.

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 }

◆ 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.

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 }

References getTree().

+ Here is the call graph for this function:

◆ getTree()

ilMaterializedPathTree::getTree ( )
protected

Get tree object.

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

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...

References $tree.

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

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.

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

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 }

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

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 }

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

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 }

References $res, and ilDBConstants\FETCHMODE_ASSOC.

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.

Referenced by getMaximumPossibleDepth().


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