ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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['ilDB'];
17 $this->task = $task;
18 }
19
20
26 public static function findDeepestDuplicate()
27 {
28 global $ilDB;
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 $GLOBALS['ilLog']->write($query);
37
38 $res = $ilDB->query($query);
39 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
40 return $row->child;
41 }
42 return 0;
43 }
44
45 public static function repairPK()
46 {
47 #$GLOBALS['ilDB']->dropPrimaryKey('tree');
48 $GLOBALS['ilDB']->addPrimaryKey('tree', array('child'));
49 }
50
51 public static function getNodeInfo($a_tree_id, $a_child)
52 {
53 global $ilDB;
54
55 $query = 'SELECT * FROM tree WHERE child = ' . $ilDB->quote($a_child, 'integer') . ' AND tree = ' . $ilDB->quote($a_tree_id, 'integer');
56 $res = $ilDB->query($query);
57
58 $node = array();
59 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
60 $node['child'] = $row->child;
61 $node['tree'] = $row->tree;
62 $node['depth'] = $row->depth;
63
64 // read obj_id
65 $query = 'SELECT obj_id FROM object_reference WHERE ref_id = ' . $ilDB->quote($a_child, 'integer');
66 $ref_res = $ilDB->query($query);
67 while ($ref_row = $ref_res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
68 $node['obj_id'] = $ref_row->obj_id;
69
70 // read object info
71 $query = 'SELECT title, description, type FROM object_data ' .
72 'WHERE obj_id = ' . $ilDB->quote($ref_row->obj_id);
73 $obj_res = $ilDB->query($query);
74 while ($obj_row = $obj_res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
75 $node['title'] = $obj_row->title;
76 $node['description'] = $obj_row->description;
77 $node['type'] = $obj_row->type;
78 }
79 }
80 }
81 return $node;
82 }
83
84 public static function getChilds($a_tree_id, $a_childs)
85 {
86 global $ilDB;
87
88 $query = 'SELECT * FROM tree WHERE tree = ' . $ilDB->quote($a_tree_id, 'integer') . ' ' . 'AND child = ' . $ilDB->quote($a_childs, 'integer');
89 $res = $ilDB->query($query);
90
91 $childs = array();
92 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
93 $childs[] = $row->child;
94 }
95 return $childs;
96 }
97
103 public static function findDuplicates($a_duplicate_id)
104 {
105 global $ilDB;
106
107 $query = 'SELECT * FROM tree first ' .
108 'WHERE EXISTS ( ' .
109 'SELECT child FROM tree second WHERE first.child = second.child ' .
110 'GROUP BY child HAVING COUNT(child) > 1 ) ' .
111 'AND child = ' . $ilDB->quote($a_duplicate_id, 'integer') . ' ' .
112 'ORDER BY depth DESC';
113 $res = $ilDB->query($query);
114
115 $GLOBALS['ilLog']->write($query);
116
117 $nodes = array();
118 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
119 $node = array();
120 $node['tree'] = $row->tree;
121 $node['child'] = $row->child;
122 $node['depth'] = $row->depth;
123
124 $nodes[] = $node;
125 }
126
127 return $nodes;
128 }
129
130 public static function hasDuplicate($a_child)
131 {
132 global $ilDB;
133
134 return count(self::findDuplicates($a_child));
135 }
136
137 public static function deleteDuplicateFromTree($a_duplicate_id, $a_delete_trash)
138 {
139 $dups = self::findDuplicates($a_duplicate_id);
140 foreach ($dups as $dup) {
141 if ($a_delete_trash and $dup['tree'] < 1) {
142 self::deleteDuplicate($dup['tree'], $dup['child']);
143 }
144 if (!$a_delete_trash and $dup['tree'] == 1) {
145 self::deleteDuplicate($dup['tree'], $dup['child']);
146 }
147 }
148 return true;
149 }
150
151 protected static function deleteDuplicate($tree_id, $dup_id)
152 {
153 global $ilDB;
154
155 $query = 'SELECT child FROM tree ' .
156 'WHERE parent = ' . $ilDB->quote($dup_id, 'integer') . ' ' .
157 'AND tree = ' . $ilDB->quote($tree_id, 'integer');
158 $res = $ilDB->query($query);
159 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
160 // start recursion
161 self::deleteDuplicate($tree_id, $row->child);
162 }
163 // now delete node
164 if (self::hasDuplicate($dup_id)) {
165 $query = 'DELETE FROM tree ' .
166 'WHERE child = ' . $ilDB->quote($dup_id, 'integer') . ' ' .
167 'AND tree = ' . $ilDB->quote($tree_id, 'integer');
168 $ilDB->manipulate($query);
169 }
170 }
171
172
176 public function getDB()
177 {
178 return $this->db;
179 }
180
185 public function getTask()
186 {
187 return $this->task;
188 }
189
190
191
196 public function validateStructure()
197 {
198 $failures = $this->checkStructure();
199
200 if (count($failures)) {
201 $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
202 } else {
203 $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
204 }
205 $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
206 $this->getTask()->update();
207 return count($failures);
208 }
209
210
211 public function checkStructure()
212 {
213 return $GLOBALS['tree']->validateParentRelations();
214 global $ilDB;
215
216 $query = 'select child from tree child where not exists ' .
217 '( ' .
218 'select child from tree parent where child.parent = parent.child and (parent.lft < child.lft) and (parent.rgt > child.rgt) ' .
219 ')' .
220 'and tree = 1 and child <> 1';
221 $res = $ilDB->query($query);
222
223 $failures = array();
224 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
225 $failures[] = $row->child;
226 }
227 return $failures;
228 }
229
230
231
235 public function validateDuplicates()
236 {
237 $failures = $this->checkDuplicates();
238
239 if (count($failures)) {
240 $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
241 } else {
242 $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
243 }
244 $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
245 $this->getTask()->update();
246 return count($failures);
247 }
248
252 public function checkDuplicates()
253 {
254 $query = 'SELECT child, count(child) num FROM tree ' .
255 'GROUP BY child ' .
256 'HAVING count(child) > 1';
257 $res = $this->getDB()->query($query);
258
259 $GLOBALS['ilLog']->write($query);
260
261 $failures = array();
262 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
263 $failures[] = $row->child;
264 }
265 return $failures;
266 }
267
268 public function findMissingTreeEntries()
269 {
270 global $ilDB;
271
272 $failures = $this->readMissingTreeEntries();
273
274 if (count($failures)) {
275 $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
276 } else {
277 $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
278 }
279
280 $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
281 $this->getTask()->update();
282 return count($failures);
283 }
284
285
289 public function findMissing()
290 {
291 global $ilDB;
292
293 $failures = $this->readMissing();
294
295 if (count($failures)) {
296 $this->getTask()->setStatus(ilSCTask::STATUS_FAILED);
297 } else {
298 $this->getTask()->setStatus(ilSCTask::STATUS_COMPLETED);
299 }
300
301 $this->getTask()->setLastUpdate(new ilDateTime(time(), IL_CAL_UNIX));
302 $this->getTask()->update();
303 return count($failures);
304 }
305
309 public function repairMissing()
310 {
311 $failures = $this->readMissing();
312 $recf_ref_id = $this->createRecoveryContainer();
313 foreach ($failures as $ref_id) {
314 $this->repairMissingObject($recf_ref_id, $ref_id);
315 }
316 }
317
322 protected function repairMissingObject($a_parent_ref, $a_ref_id)
323 {
324 global $ilDB;
325
326 // check if object entry exist
327 $query = 'SELECT obj_id FROM object_reference ' .
328 'WHERE ref_id = ' . $ilDB->quote($a_ref_id, 'integer');
329
330 $res = $ilDB->query($query);
331 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
332 $query = 'SELECT type, title FROM object_data ' .
333 'WHERE obj_id = ' . $ilDB->quote($row->obj_id, 'integer');
334 $ores = $ilDB->query($query);
335
336 $done = false;
337 while ($orow = $ores->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
338 $GLOBALS['ilLog']->write(__METHOD__ . ': Moving to recovery folder: ' . $orow->type . ': ' . $orow->title);
339 $done = true;
340
341 include_once './Services/Object/classes/class.ilObjectFactory.php';
343 $ref_obj = $factory->getInstanceByRefId($a_ref_id, false);
344
345 if ($ref_obj instanceof ilObjRoleFolder) {
346 $ref_obj->delete();
347 } elseif ($ref_obj instanceof ilObject) {
348 $ref_obj->putInTree($a_parent_ref);
349 $ref_obj->setPermissions($a_parent_ref);
350 $GLOBALS['ilLog']->write(__METHOD__ . ': Moving finished');
351 break;
352 }
353 }
354 if (!$done) {
355 // delete reference value
356 $query = 'DELETE FROM object_reference WHERE ref_id = ' . $ilDB->quote($a_ref_id, 'integer');
357 $ilDB->manipulate($query);
358 $GLOBALS['ilLog']->write(__METHOD__ . ': Delete reference for "object" without tree and object_data entry: ref_id= ' . $a_ref_id);
359 }
360 }
361 }
362
369 protected function readMissing()
370 {
371 global $ilDB;
372
373 $query = 'SELECT ref_id FROM object_reference ' .
374 'LEFT JOIN tree ON ref_id = child ' .
375 'WHERE child IS NULL';
376 $res = $ilDB->query($query);
377
378 $failures = array();
379 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
380 $failures[] = $row->ref_id;
381 }
382 return $failures;
383 }
384
389 public function repairMissingTreeEntries()
390 {
391 global $ilDB;
392
393 $missing = $this->readMissingTreeEntries();
394 $GLOBALS['ilLog']->write(__METHOD__ . ': ' . print_r($missing, true));
395
396 foreach ($missing as $ref_id) {
397 // check for duplicates
398 $query = 'SELECT tree, child FROM tree ' .
399 'WHERE child = ' . $ilDB->quote($ref_id);
400 $res = $ilDB->query($query);
401 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
402 $GLOBALS['ilLog']->write(__METHOD__ . ': ' . $row->tree . ': ' . $ref_id);
403
404 $this->deleteMissingTreeEntry($row->tree, $ref_id);
405 }
406 }
407 }
408
412 protected function deleteMissingTreeEntry($a_tree_id, $a_ref_id)
413 {
414 global $ilDB;
415
416 $query = 'SELECT child FROM tree ' .
417 'WHERE parent = ' . $ilDB->quote($a_ref_id, 'integer') . ' ' .
418 'AND tree = ' . $ilDB->quote($a_tree_id, 'integer');
419
420 $res = $ilDB->query($query);
421 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
422 // check for duplicates
423 $query = 'SELECT tree, child FROM tree ' .
424 'WHERE child = ' . $ilDB->quote($row->child);
425 $resd = $ilDB->query($query);
426 while ($rowd = $resd->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
427 $this->deleteMissingTreeEntry($rowd->tree, $rowd->child);
428 }
429 }
430
431 // finally delete
432 include_once './Services/Object/classes/class.ilObjectFactory.php';
434 $ref_obj = $factory->getInstanceByRefId($a_ref_id, false);
435
436 if (($ref_obj instanceof ilObject) and $ref_obj->getType()) {
437 $ref_obj->delete();
438 }
439
440 $query = 'DELETE from tree ' .
441 'WHERE tree = ' . $ilDB->quote($a_tree_id) . ' ' .
442 'AND child = ' . $ilDB->quote($a_ref_id);
443 $ilDB->manipulate($query);
444 }
445
446
453 protected function readMissingTreeEntries()
454 {
455 global $ilDB;
456
457 $query = 'SELECT child FROM tree ' .
458 'LEFT JOIN object_reference ON child = ref_id ' .
459 'WHERE ref_id IS NULL';
460
461 $res = $ilDB->query($query);
462
463 $failures = array();
464 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
465 $failures[] = $row->child;
466 }
467 return $failures;
468 }
469
470
474 protected function createRecoveryContainer()
475 {
476 $now = new ilDateTime(time(), IL_CAL_UNIX);
477
478 include_once './Modules/Folder/classes/class.ilObjFolder.php';
479 $folder = new ilObjFolder();
480 $folder->setTitle('__System check recovery: ' . $now->get(IL_CAL_DATETIME));
481 $folder->create();
482 $folder->createReference();
483 $folder->putInTree(RECOVERY_FOLDER_ID);
484
485 return $folder->getRefId();
486 }
487}
$factory
Definition: metadata.php:47
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.
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.
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
$query
foreach($_POST as $key=> $value) $res
global $ilDB