ILIAS  release_8 Revision v8.23
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 
284  // check if object entry exist
285  $query = 'SELECT obj_id FROM object_reference ' .
286  'WHERE ref_id = ' . $this->db->quote($a_ref_id, ilDBConstants::T_INTEGER);
287 
288  $res = $this->db->query($query);
289  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
290  $query = 'SELECT type, title FROM object_data ' .
291  'WHERE obj_id = ' . $this->db->quote($row->obj_id, ilDBConstants::T_INTEGER);
292  $ores = $this->db->query($query);
293 
294  $done = false;
295  while ($orow = $ores->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
296  $done = true;
297 
298  $factory = new ilObjectFactory();
299  $ref_obj = $factory->getInstanceByRefId($a_ref_id, false);
300 
301  if ($ref_obj instanceof ilObjRoleFolder) {
302  $ref_obj->delete();
303  } elseif ($ref_obj instanceof ilObject) {
304  $ref_obj->putInTree($a_parent_ref);
305  $ref_obj->setPermissions($a_parent_ref);
306 
307  break;
308  }
309  }
310  if (!$done) {
311  // delete reference value
312  $query = 'DELETE FROM object_reference WHERE ref_id = ' . $this->db->quote(
313  $a_ref_id,
315  );
316  $this->db->manipulate($query);
317  }
318  }
319  }
320 
324  protected function readMissing(): array
325  {
326  $query = 'SELECT ref_id FROM object_reference ' .
327  'LEFT JOIN tree ON ref_id = child ' .
328  'WHERE child IS NULL';
329  $res = $this->db->query($query);
330 
331  $failures = array();
332  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
333  $failures[] = (int) $row->ref_id;
334  }
335  return $failures;
336  }
337 
338  public function repairMissingTreeEntries(): void
339  {
340  $missing = $this->readMissingTreeEntries();
341  foreach ($missing as $ref_id) {
342  // check for duplicates
343  $query = 'SELECT tree, child FROM tree ' .
344  'WHERE child = ' . $this->db->quote($ref_id, ilDBConstants::T_INTEGER);
345  $res = $this->db->query($query);
346  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
347  $this->deleteMissingTreeEntry((int) $row->tree, $ref_id);
348  }
349  }
350  }
351 
352  protected function deleteMissingTreeEntry(int $a_tree_id, int $a_ref_id): void
353  {
354  $query = 'SELECT child FROM tree ' .
355  'WHERE parent = ' . $this->db->quote($a_ref_id, ilDBConstants::T_INTEGER) . ' ' .
356  'AND tree = ' . $this->db->quote($a_tree_id, ilDBConstants::T_INTEGER);
357 
358  $res = $this->db->query($query);
359  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
360  // check for duplicates
361  $query = 'SELECT tree, child FROM tree ' .
362  'WHERE child = ' . $this->db->quote($row->child, ilDBConstants::T_INTEGER);
363  $resd = $this->db->query($query);
364  while ($rowd = $resd->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
365  $this->deleteMissingTreeEntry((int) $rowd->tree, (int) $rowd->child);
366  }
367  }
368 
369  // finally delete
370 
371  $factory = new ilObjectFactory();
372  $ref_obj = $factory->getInstanceByRefId($a_ref_id, false);
373 
374  if (($ref_obj instanceof ilObject) && $ref_obj->getType()) {
375  $ref_obj->delete();
376  }
377 
378  $query = 'DELETE from tree ' .
379  'WHERE tree = ' . $this->db->quote($a_tree_id, ilDBConstants::T_INTEGER) . ' ' .
380  'AND child = ' . $this->db->quote($a_ref_id, ilDBConstants::T_INTEGER);
381  $this->db->manipulate($query);
382  }
383 
388  protected function readMissingTreeEntries(): array
389  {
390  $query = 'SELECT child FROM tree ' .
391  'LEFT JOIN object_reference ON child = ref_id ' .
392  'WHERE ref_id IS NULL';
393 
394  $res = $this->db->query($query);
395 
396  $failures = array();
397  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
398  $failures[] = (int) $row->child;
399  }
400  return $failures;
401  }
402 
403  protected function createRecoveryContainer(): int
404  {
405  $now = new ilDateTime(time(), IL_CAL_UNIX);
406 
407  $folder = new ilObjFolder();
408  $folder->setTitle('__System check recovery: ' . $now->get(IL_CAL_DATETIME));
409  $folder->create();
410  $folder->createReference();
411  $folder->putInTree(RECOVERY_FOLDER_ID);
412 
413  return $folder->getRefId();
414  }
415 }
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
$query
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)
$factory
Definition: metadata.php:75