ILIAS  release_7 Revision v7.30-3-g800a261c036
class.ilSCTreeTasks.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
10{
11 private $db = null;
12 private $task = null;
13
14 public function __construct(ilSCTask $task)
15 {
16 $this->db = $GLOBALS['DIC']['ilDB'];
17 $this->task = $task;
18 }
19
20
26 public static function findDeepestDuplicate()
27 {
28 global $DIC;
29
30 $ilDB = $DIC['ilDB'];
31
32 $query = 'SELECT child FROM tree first ' .
33 'WHERE EXISTS ( ' .
34 'SELECT child FROM tree second WHERE first.child = second.child ' .
35 'GROUP BY child HAVING COUNT(child) > 1 ) ' .
36 'ORDER BY depth DESC';
37
38 $GLOBALS['DIC']['ilLog']->write($query);
39
40 $res = $ilDB->query($query);
41 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
42 return $row->child;
43 }
44 return 0;
45 }
46
47 public static function repairPK()
48 {
49 #$GLOBALS['DIC']['ilDB']->dropPrimaryKey('tree');
50 $GLOBALS['DIC']['ilDB']->addPrimaryKey('tree', array('child'));
51 }
52
53 public static function getNodeInfo($a_tree_id, $a_child)
54 {
55 global $DIC;
56
57 $ilDB = $DIC['ilDB'];
58
59 $query = 'SELECT * FROM tree WHERE child = ' . $ilDB->quote($a_child, 'integer') . ' AND tree = ' . $ilDB->quote($a_tree_id, 'integer');
60 $res = $ilDB->query($query);
61
62 $node = array();
63 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
64 $node['child'] = $row->child;
65 $node['tree'] = $row->tree;
66 $node['depth'] = $row->depth;
67
68 // read obj_id
69 $query = 'SELECT obj_id FROM object_reference WHERE ref_id = ' . $ilDB->quote($a_child, 'integer');
70 $ref_res = $ilDB->query($query);
71 while ($ref_row = $ref_res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
72 $node['obj_id'] = $ref_row->obj_id;
73
74 // read object info
75 $query = 'SELECT title, description, type FROM object_data ' .
76 'WHERE obj_id = ' . $ilDB->quote($ref_row->obj_id);
77 $obj_res = $ilDB->query($query);
78 while ($obj_row = $obj_res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
79 $node['title'] = $obj_row->title;
80 $node['description'] = $obj_row->description;
81 $node['type'] = $obj_row->type;
82 }
83 }
84 }
85 return $node;
86 }
87
88 public static function getChilds($a_tree_id, $a_childs)
89 {
90 global $DIC;
91
92 $ilDB = $DIC['ilDB'];
93
94 $query = 'SELECT * FROM tree WHERE tree = ' . $ilDB->quote($a_tree_id, 'integer') . ' ' . 'AND child = ' . $ilDB->quote($a_childs, 'integer');
95 $res = $ilDB->query($query);
96
97 $childs = array();
98 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
99 $childs[] = $row->child;
100 }
101 return $childs;
102 }
103
109 public static function findDuplicates($a_duplicate_id)
110 {
111 global $DIC;
112
113 $ilDB = $DIC['ilDB'];
114
115 $query = 'SELECT * FROM tree first ' .
116 'WHERE EXISTS ( ' .
117 'SELECT child FROM tree second WHERE first.child = second.child ' .
118 'GROUP BY child HAVING COUNT(child) > 1 ) ' .
119 'AND child = ' . $ilDB->quote($a_duplicate_id, 'integer') . ' ' .
120 'ORDER BY depth DESC';
121 $res = $ilDB->query($query);
122
123 $GLOBALS['DIC']['ilLog']->write($query);
124
125 $nodes = array();
126 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
127 $node = array();
128 $node['tree'] = $row->tree;
129 $node['child'] = $row->child;
130 $node['depth'] = $row->depth;
131
132 $nodes[] = $node;
133 }
134
135 return $nodes;
136 }
137
138 public static function hasDuplicate($a_child)
139 {
140 global $DIC;
141
142 $ilDB = $DIC['ilDB'];
143
144 return count(self::findDuplicates($a_child));
145 }
146
147 public static function deleteDuplicateFromTree($a_duplicate_id, $a_delete_trash)
148 {
149 $dups = self::findDuplicates($a_duplicate_id);
150 foreach ($dups as $dup) {
151 if ($a_delete_trash and $dup['tree'] < 1) {
152 self::deleteDuplicate($dup['tree'], $dup['child']);
153 }
154 if (!$a_delete_trash and $dup['tree'] == 1) {
155 self::deleteDuplicate($dup['tree'], $dup['child']);
156 }
157 }
158 return true;
159 }
160
161 protected static function deleteDuplicate($tree_id, $dup_id)
162 {
163 global $DIC;
164
165 $ilDB = $DIC['ilDB'];
166
167 $query = 'SELECT child FROM tree ' .
168 'WHERE parent = ' . $ilDB->quote($dup_id, 'integer') . ' ' .
169 'AND tree = ' . $ilDB->quote($tree_id, 'integer');
170 $res = $ilDB->query($query);
171 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
172 // start recursion
173 self::deleteDuplicate($tree_id, $row->child);
174 }
175 // now delete node
176 if (self::hasDuplicate($dup_id)) {
177 $query = 'DELETE FROM tree ' .
178 'WHERE child = ' . $ilDB->quote($dup_id, 'integer') . ' ' .
179 'AND tree = ' . $ilDB->quote($tree_id, 'integer');
180 $ilDB->manipulate($query);
181 }
182 }
183
184
188 public function getDB()
189 {
190 return $this->db;
191 }
192
197 public function getTask()
198 {
199 return $this->task;
200 }
201
202
203
208 public function validateStructure()
209 {
210 $failures = $this->checkStructure();
211
212 if (count($failures)) {
213 $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
214 } else {
215 $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
216 }
217 $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
218 $this->getTask()->update();
219 return count($failures);
220 }
221
222
223 public function checkStructure()
224 {
225 return $GLOBALS['DIC']['tree']->validateParentRelations();
226 global $DIC;
227
228 $ilDB = $DIC['ilDB'];
229
230 $query = 'select child from tree child where not exists ' .
231 '( ' .
232 'select child from tree parent where child.parent = parent.child and (parent.lft < child.lft) and (parent.rgt > child.rgt) ' .
233 ')' .
234 'and tree = 1 and child <> 1';
235 $res = $ilDB->query($query);
236
237 $failures = array();
238 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
239 $failures[] = $row->child;
240 }
241 return $failures;
242 }
243
244
245
249 public function validateDuplicates()
250 {
251 $failures = $this->checkDuplicates();
252
253 if (count($failures)) {
254 $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
255 } else {
256 $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
257 }
258 $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
259 $this->getTask()->update();
260 return count($failures);
261 }
262
266 public function checkDuplicates()
267 {
268 $query = 'SELECT child, count(child) num FROM tree ' .
269 'GROUP BY child ' .
270 'HAVING count(child) > 1';
271 $res = $this->getDB()->query($query);
272
273 $GLOBALS['DIC']['ilLog']->write($query);
274
275 $failures = array();
276 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
277 $failures[] = $row->child;
278 }
279 return $failures;
280 }
281
282 public function findMissingTreeEntries()
283 {
284 global $DIC;
285
286 $ilDB = $DIC['ilDB'];
287
288 $failures = $this->readMissingTreeEntries();
289
290 if (count($failures)) {
291 $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
292 } else {
293 $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
294 }
295
296 $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
297 $this->getTask()->update();
298 return count($failures);
299 }
300
301
305 public function findMissing()
306 {
307 global $DIC;
308
309 $ilDB = $DIC['ilDB'];
310
311 $failures = $this->readMissing();
312
313 if (count($failures)) {
314 $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
315 } else {
316 $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
317 }
318
319 $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
320 $this->getTask()->update();
321 return count($failures);
322 }
323
327 public function repairMissing()
328 {
329 $failures = $this->readMissing();
330 $recf_ref_id = $this->createRecoveryContainer();
331 foreach ($failures as $ref_id) {
332 $this->repairMissingObject($recf_ref_id, $ref_id);
333 }
334 }
335
340 protected function repairMissingObject($a_parent_ref, $a_ref_id)
341 {
342 global $DIC;
343
344 $ilDB = $DIC['ilDB'];
345
346 // check if object entry exist
347 $query = 'SELECT obj_id FROM object_reference ' .
348 'WHERE ref_id = ' . $ilDB->quote($a_ref_id, 'integer');
349
350 $res = $ilDB->query($query);
351 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
352 $query = 'SELECT type, title FROM object_data ' .
353 'WHERE obj_id = ' . $ilDB->quote($row->obj_id, 'integer');
354 $ores = $ilDB->query($query);
355
356 $done = false;
357 while ($orow = $ores->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
358 $GLOBALS['DIC']['ilLog']->write(__METHOD__ . ': Moving to recovery folder: ' . $orow->type . ': ' . $orow->title);
359 $done = true;
360
361 include_once './Services/Object/classes/class.ilObjectFactory.php';
363 $ref_obj = $factory->getInstanceByRefId($a_ref_id, false);
364
365 if ($ref_obj instanceof ilObjRoleFolder) {
366 $ref_obj->delete();
367 } elseif ($ref_obj instanceof ilObject) {
368 $ref_obj->putInTree($a_parent_ref);
369 $ref_obj->setPermissions($a_parent_ref);
370 $GLOBALS['DIC']['ilLog']->write(__METHOD__ . ': Moving finished');
371 break;
372 }
373 }
374 if (!$done) {
375 // delete reference value
376 $query = 'DELETE FROM object_reference WHERE ref_id = ' . $ilDB->quote($a_ref_id, 'integer');
377 $ilDB->manipulate($query);
378 $GLOBALS['DIC']['ilLog']->write(__METHOD__ . ': Delete reference for "object" without tree and object_data entry: ref_id= ' . $a_ref_id);
379 }
380 }
381 }
382
389 protected function readMissing()
390 {
391 global $DIC;
392
393 $ilDB = $DIC['ilDB'];
394
395 $query = 'SELECT ref_id FROM object_reference ' .
396 'LEFT JOIN tree ON ref_id = child ' .
397 'WHERE child IS NULL';
398 $res = $ilDB->query($query);
399
400 $failures = array();
401 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
402 $failures[] = $row->ref_id;
403 }
404 return $failures;
405 }
406
411 public function repairMissingTreeEntries()
412 {
413 global $DIC;
414
415 $ilDB = $DIC['ilDB'];
416
417 $missing = $this->readMissingTreeEntries();
418 $GLOBALS['DIC']['ilLog']->write(__METHOD__ . ': ' . print_r($missing, true));
419
420 foreach ($missing as $ref_id) {
421 // check for duplicates
422 $query = 'SELECT tree, child FROM tree ' .
423 'WHERE child = ' . $ilDB->quote($ref_id);
424 $res = $ilDB->query($query);
425 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
426 $GLOBALS['DIC']['ilLog']->write(__METHOD__ . ': ' . $row->tree . ': ' . $ref_id);
427
428 $this->deleteMissingTreeEntry($row->tree, $ref_id);
429 }
430 }
431 }
432
436 protected function deleteMissingTreeEntry($a_tree_id, $a_ref_id)
437 {
438 global $DIC;
439
440 $ilDB = $DIC['ilDB'];
441
442 $query = 'SELECT child FROM tree ' .
443 'WHERE parent = ' . $ilDB->quote($a_ref_id, 'integer') . ' ' .
444 'AND tree = ' . $ilDB->quote($a_tree_id, 'integer');
445
446 $res = $ilDB->query($query);
447 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
448 // check for duplicates
449 $query = 'SELECT tree, child FROM tree ' .
450 'WHERE child = ' . $ilDB->quote($row->child);
451 $resd = $ilDB->query($query);
452 while ($rowd = $resd->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
453 $this->deleteMissingTreeEntry($rowd->tree, $rowd->child);
454 }
455 }
456
457 // finally delete
458 include_once './Services/Object/classes/class.ilObjectFactory.php';
460 $ref_obj = $factory->getInstanceByRefId($a_ref_id, false);
461
462 if (($ref_obj instanceof ilObject) and $ref_obj->getType()) {
463 $ref_obj->delete();
464 }
465
466 $query = 'DELETE from tree ' .
467 'WHERE tree = ' . $ilDB->quote($a_tree_id) . ' ' .
468 'AND child = ' . $ilDB->quote($a_ref_id);
469 $ilDB->manipulate($query);
470 }
471
472
479 protected function readMissingTreeEntries()
480 {
481 global $DIC;
482
483 $ilDB = $DIC['ilDB'];
484
485 $query = 'SELECT child FROM tree ' .
486 'LEFT JOIN object_reference ON child = ref_id ' .
487 'WHERE ref_id IS NULL';
488
489 $res = $ilDB->query($query);
490
491 $failures = array();
492 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
493 $failures[] = $row->child;
494 }
495 return $failures;
496 }
497
498
502 protected function createRecoveryContainer()
503 {
504 $now = new ilDateTime(time(), IL_CAL_UNIX);
505
506 include_once './Modules/Folder/classes/class.ilObjFolder.php';
507 $folder = new ilObjFolder();
508 $folder->setTitle('__System check recovery: ' . $now->get(IL_CAL_DATETIME));
509 $folder->create();
510 $folder->createReference();
511 $folder->putInTree(RECOVERY_FOLDER_ID);
512
513 return $folder->getRefId();
514 }
515}
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
Definition: PEAR.php:64
An exception for terminatinating execution or to throw for unit testing.
const IL_CAL_UNIX
const IL_CAL_DATETIME
@classDescription Date and time handling
Class ilObjFolder.
Class ilObjRoleFolder.
Class ilObjectFactory This class offers methods to get instances of the type-specific object classes ...
Class ilObject Basic functions for all objects.
Defines a system check task.
const STATUS_COMPLETED
const STATUS_FAILED
Defines a system check task.
static findDeepestDuplicate()
find duplicates @global type $ilDB
static findDuplicates($a_duplicate_id)
find duplicates @global type $ilDB
validateStructure()
validate tree structure base on parent relation
deleteMissingTreeEntry($a_tree_id, $a_ref_id)
Delete missing tree entries from tree table.
static deleteDuplicateFromTree($a_duplicate_id, $a_delete_trash)
findMissing()
Find missing objects.
__construct(ilSCTask $task)
repairMissingTreeEntries()
repair missing tree entries @global type $ilDB
checkDuplicates()
Check for duplicates.
static hasDuplicate($a_child)
static getNodeInfo($a_tree_id, $a_child)
readMissing()
Read missing objects in tree Entry in oject_reference but no entry in tree @global type $ilDB.
createRecoveryContainer()
Create a reccovery folder.
repairMissing()
Repair missing objects.
static getChilds($a_tree_id, $a_childs)
static deleteDuplicate($tree_id, $dup_id)
readMissingTreeEntries()
Read missing tree entries for referenced objects Entry in tree but no entry in object reference @glob...
repairMissingObject($a_parent_ref, $a_ref_id)
Repair missing object.
const RECOVERY_FOLDER_ID
Definition: constants.php:35
global $DIC
Definition: goto.php:24
$factory
Definition: metadata.php:58
$query
foreach($_POST as $key=> $value) $res
global $ilDB