ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilSCTreeTasks.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
5 
11 {
12  protected ilTree $tree;
13  protected ilDBInterface $db;
14  private ilSCTask $task;
15 
16  public function __construct(ilSCTask $task)
17  {
18  global $DIC;
19  $this->db = $DIC->database();
20  $this->tree = $DIC->repositoryTree();
21  $this->task = $task;
22  }
23 
24  public static function findDeepestDuplicate(): int
25  {
26  global $DIC;
27 
28  $ilDB = $DIC->database();
29 
30  $query = 'SELECT child FROM tree first ' .
31  'WHERE EXISTS ( ' .
32  'SELECT child FROM tree second WHERE first.child = second.child ' .
33  'GROUP BY child HAVING COUNT(child) > 1 ) ' .
34  'ORDER BY depth DESC';
35 
36  $res = $ilDB->query($query);
37  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
38  return (int) $row->child;
39  }
40  return 0;
41  }
42 
43  public static function repairPK(): void
44  {
45  global $DIC;
46 
47  $ilDB = $DIC->database();
48 
49  $ilDB->addPrimaryKey('tree', array('child'));
50  }
51 
52  public static function getNodeInfo(int $a_tree_id, int $a_child): array
53  {
54  global $DIC;
55 
56  $ilDB = $DIC->database();
57 
58  $query = 'SELECT * FROM tree WHERE child = ' . $ilDB->quote(
59  $a_child,
61  ) . ' AND tree = ' . $ilDB->quote($a_tree_id, ilDBConstants::T_INTEGER);
62  $res = $ilDB->query($query);
63 
64  $node = array();
65  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
66  $node['child'] = (int) $row->child;
67  $node['tree'] = (int) $row->tree;
68  $node['depth'] = (int) $row->depth;
69 
70  // read obj_id
71  $query = 'SELECT obj_id FROM object_reference WHERE ref_id = ' . $ilDB->quote(
72  $a_child,
74  );
75  $ref_res = $ilDB->query($query);
76  while ($ref_row = $ref_res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
77  $node['obj_id'] = (int) $ref_row->obj_id;
78 
79  // read object info
80  $query = 'SELECT title, description, type FROM object_data ' .
81  'WHERE obj_id = ' . $ilDB->quote($ref_row->obj_id, ilDBConstants::T_INTEGER);
82  $obj_res = $ilDB->query($query);
83  while ($obj_row = $obj_res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
84  $node['title'] = (string) $obj_row->title;
85  $node['description'] = (string) $obj_row->description;
86  $node['type'] = (string) $obj_row->type;
87  }
88  }
89  }
90  return $node;
91  }
92 
93  public static function getChilds(int $a_tree_id, int $a_childs): array
94  {
95  global $DIC;
96 
97  $ilDB = $DIC->database();
98 
99  $query = 'SELECT * FROM tree WHERE tree = ' . $ilDB->quote(
100  $a_tree_id,
102  ) . ' ' . 'AND child = ' . $ilDB->quote($a_childs, ilDBConstants::T_INTEGER);
103  $res = $ilDB->query($query);
104 
105  $childs = array();
106  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
107  $childs[] = (int) $row->child;
108  }
109  return $childs;
110  }
111 
112  public static function findDuplicates(int $a_duplicate_id): array
113  {
114  global $DIC;
115 
116  $ilDB = $DIC->database();
117 
118  $query = 'SELECT * FROM tree first ' .
119  'WHERE EXISTS ( ' .
120  'SELECT child FROM tree second WHERE first.child = second.child ' .
121  'GROUP BY child HAVING COUNT(child) > 1 ) ' .
122  'AND child = ' . $ilDB->quote($a_duplicate_id, ilDBConstants::T_INTEGER) . ' ' .
123  'ORDER BY depth DESC';
124  $res = $ilDB->query($query);
125 
126  $nodes = array();
127  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
128  $node = array();
129  $node['tree'] = (int) $row->tree;
130  $node['child'] = (int) $row->child;
131  $node['depth'] = (int) $row->depth;
132 
133  $nodes[] = $node;
134  }
135 
136  return $nodes;
137  }
138 
139  public static function hasDuplicate(int $a_child): int
140  {
141  global $DIC;
142 
143  $ilDB = $DIC->database();
144 
145  return count(self::findDuplicates($a_child));
146  }
147 
148  public static function deleteDuplicateFromTree(int $a_duplicate_id, bool $a_delete_trash): bool
149  {
150  $dups = self::findDuplicates($a_duplicate_id);
151  foreach ($dups as $dup) {
152  if ($a_delete_trash && $dup['tree'] < 1) {
153  self::deleteDuplicate($dup['tree'], $dup['child']);
154  }
155  if (!$a_delete_trash && $dup['tree'] == 1) {
156  self::deleteDuplicate($dup['tree'], $dup['child']);
157  }
158  }
159  return true;
160  }
161 
162  protected static function deleteDuplicate(int $tree_id, int $dup_id): void
163  {
164  global $DIC;
165 
166  $ilDB = $DIC->database();
167 
168  $query = 'SELECT child FROM tree ' .
169  'WHERE parent = ' . $ilDB->quote($dup_id, ilDBConstants::T_INTEGER) . ' ' .
170  'AND tree = ' . $ilDB->quote($tree_id, ilDBConstants::T_INTEGER);
171  $res = $ilDB->query($query);
172  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
173  // start recursion
174  self::deleteDuplicate($tree_id, (int) $row->child);
175  }
176  // now delete node
177  if (self::hasDuplicate($dup_id)) {
178  $query = 'DELETE FROM tree ' .
179  'WHERE child = ' . $ilDB->quote($dup_id, ilDBConstants::T_INTEGER) . ' ' .
180  'AND tree = ' . $ilDB->quote($tree_id, ilDBConstants::T_INTEGER);
181  $ilDB->manipulate($query);
182  }
183  }
184 
185  protected function getDB(): ilDBInterface
186  {
187  return $this->db;
188  }
189 
190  public function getTask(): ilSCTask
191  {
192  return $this->task;
193  }
194 
195  public function validateStructure(): int
196  {
197  $failures = $this->checkStructure();
198 
199  if (count($failures)) {
200  $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
201  } else {
202  $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
203  }
204  $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
205  $this->getTask()->update();
206  return count($failures);
207  }
208 
209  public function checkStructure(): array
210  {
211  return $this->tree->validateParentRelations();
212  }
213 
214  public function validateDuplicates(): int
215  {
216  $failures = $this->checkDuplicates();
217 
218  if (count($failures)) {
219  $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
220  } else {
221  $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
222  }
223  $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
224  $this->getTask()->update();
225  return count($failures);
226  }
227 
228  public function checkDuplicates(): array
229  {
230  $query = 'SELECT child, count(child) num FROM tree ' .
231  'GROUP BY child ' .
232  'HAVING count(child) > 1';
233  $res = $this->db->query($query);
234 
235  $failures = array();
236  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
237  $failures[] = (int) $row->child;
238  }
239  return $failures;
240  }
241 
242  public function findMissingTreeEntries(): int
243  {
244  $failures = $this->readMissingTreeEntries();
245 
246  if (count($failures)) {
247  $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
248  } else {
249  $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
250  }
251 
252  $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
253  $this->getTask()->update();
254  return count($failures);
255  }
256 
257  public function findMissing(): int
258  {
259  $failures = $this->readMissing();
260 
261  if (count($failures)) {
262  $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
263  } else {
264  $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
265  }
266 
267  $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
268  $this->getTask()->update();
269  return count($failures);
270  }
271 
272  public function repairMissing(): void
273  {
274  $failures = $this->readMissing();
275  $recf_ref_id = $this->createRecoveryContainer();
276  foreach ($failures as $ref_id) {
277  $this->repairMissingObject($recf_ref_id, $ref_id);
278  }
279  }
280 
281  protected function repairMissingObject(int $a_parent_ref, int $a_ref_id): void
282  {
283  // check if object entry exist
284  $query = 'SELECT obj_id FROM object_reference ' .
285  'WHERE ref_id = ' . $this->db->quote($a_ref_id, ilDBConstants::T_INTEGER);
286 
287  $res = $this->db->query($query);
288  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
289  $query = 'SELECT type, title FROM object_data ' .
290  'WHERE obj_id = ' . $this->db->quote($row->obj_id, ilDBConstants::T_INTEGER);
291  $ores = $this->db->query($query);
292 
293  $done = false;
294  while ($orow = $ores->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
295  $done = true;
296 
297  $factory = new ilObjectFactory();
298  $ref_obj = $factory->getInstanceByRefId($a_ref_id, false);
299 
300  if ($ref_obj instanceof ilObjRoleFolder) {
301  $ref_obj->delete();
302  } elseif ($ref_obj instanceof ilObject) {
303  $ref_obj->putInTree($a_parent_ref);
304  $ref_obj->setPermissions($a_parent_ref);
305 
306  break;
307  }
308  }
309  if (!$done) {
310  // delete reference value
311  $query = 'DELETE FROM object_reference WHERE ref_id = ' . $this->db->quote(
312  $a_ref_id,
314  );
315  $this->db->manipulate($query);
316  }
317  }
318  }
319 
323  protected function readMissing(): array
324  {
325  $query = 'SELECT ref_id FROM object_reference ' .
326  'LEFT JOIN tree ON ref_id = child ' .
327  'WHERE child IS NULL';
328  $res = $this->db->query($query);
329 
330  $failures = array();
331  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
332  $failures[] = (int) $row->ref_id;
333  }
334  return $failures;
335  }
336 
337  public function repairMissingTreeEntries(): void
338  {
339  $missing = $this->readMissingTreeEntries();
340  foreach ($missing as $ref_id) {
341  // check for duplicates
342  $query = 'SELECT tree, child FROM tree ' .
343  'WHERE child = ' . $this->db->quote($ref_id, ilDBConstants::T_INTEGER);
344  $res = $this->db->query($query);
345  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
346  $this->deleteMissingTreeEntry((int) $row->tree, $ref_id);
347  }
348  }
349  }
350 
351  protected function deleteMissingTreeEntry(int $a_tree_id, int $a_ref_id): void
352  {
353  $query = 'SELECT child FROM tree ' .
354  'WHERE parent = ' . $this->db->quote($a_ref_id, ilDBConstants::T_INTEGER) . ' ' .
355  'AND tree = ' . $this->db->quote($a_tree_id, ilDBConstants::T_INTEGER);
356 
357  $res = $this->db->query($query);
358  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
359  // check for duplicates
360  $query = 'SELECT tree, child FROM tree ' .
361  'WHERE child = ' . $this->db->quote($row->child, ilDBConstants::T_INTEGER);
362  $resd = $this->db->query($query);
363  while ($rowd = $resd->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
364  $this->deleteMissingTreeEntry((int) $rowd->tree, (int) $rowd->child);
365  }
366  }
367 
368  // finally delete
369 
370  $factory = new ilObjectFactory();
371  $ref_obj = $factory->getInstanceByRefId($a_ref_id, false);
372 
373  if (($ref_obj instanceof ilObject) && $ref_obj->getType()) {
374  $ref_obj->delete();
375  }
376 
377  $query = 'DELETE from tree ' .
378  'WHERE tree = ' . $this->db->quote($a_tree_id, ilDBConstants::T_INTEGER) . ' ' .
379  'AND child = ' . $this->db->quote($a_ref_id, ilDBConstants::T_INTEGER);
380  $this->db->manipulate($query);
381  }
382 
387  protected function readMissingTreeEntries(): array
388  {
389  $query = 'SELECT child FROM tree ' .
390  'LEFT JOIN object_reference ON child = ref_id ' .
391  'WHERE ref_id IS NULL';
392 
393  $res = $this->db->query($query);
394 
395  $failures = array();
396  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
397  $failures[] = (int) $row->child;
398  }
399  return $failures;
400  }
401 
402  protected function createRecoveryContainer(): int
403  {
404  $now = new ilDateTime(time(), IL_CAL_UNIX);
405 
406  $folder = new ilObjFolder();
407  $folder->setTitle('__System check recovery: ' . $now->get(IL_CAL_DATETIME));
408  $folder->create();
409  $folder->createReference();
410  $folder->putInTree(RECOVERY_FOLDER_ID);
411 
412  return $folder->getRefId();
413  }
414 }
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$res
Definition: ltiservices.php:69
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const IL_CAL_DATETIME
__construct(ilSCTask $task)
static deleteDuplicateFromTree(int $a_duplicate_id, bool $a_delete_trash)
readMissingTreeEntries()
Read missing tree entries for referenced objects Entry in tree but no entry in object reference...
const STATUS_FAILED
static findDeepestDuplicate()
deleteMissingTreeEntry(int $a_tree_id, int $a_ref_id)
static hasDuplicate(int $a_child)
const IL_CAL_UNIX
static deleteDuplicate(int $tree_id, int $dup_id)
global $DIC
Definition: feed.php:28
repairMissingObject(int $a_parent_ref, int $a_ref_id)
ilDBInterface $db
$ref_id
Definition: ltiauth.php:67
static findDuplicates(int $a_duplicate_id)
static getNodeInfo(int $a_tree_id, int $a_child)
const STATUS_COMPLETED
Defines a system check task.
const RECOVERY_FOLDER_ID
Definition: constants.php:37
static getChilds(int $a_tree_id, int $a_childs)