ILIAS  release_8 Revision v8.24
class.ilRepUtil.php
Go to the documentation of this file.
1<?php
2
25{
26 protected ilDBInterface $db;
27 protected ilTree $tree;
29
30 public function __construct()
31 {
32 global $DIC;
33
34 $this->db = $DIC->database();
35 $this->tree = $DIC->repositoryTree();
36 $this->settings = $DIC->settings();
37 }
38
45 public static function deleteObjects(
46 int $a_cur_ref_id,
47 array $a_ids,
48 bool $throw_error_on_already_deleted = true
49 ): void {
50 global $DIC;
51
52 $ilAppEventHandler = $DIC["ilAppEventHandler"];
53 $rbacsystem = $DIC->rbac()->system();
54 $rbacadmin = $DIC->rbac()->admin();
55 $ilLog = $DIC["ilLog"];
56 $tree = $DIC->repositoryTree();
57 $lng = $DIC->language();
58 $ilSetting = $DIC->settings();
59 $user = $DIC->user();
60
61 // deactivating the cache to make functions like
62 // _hasUntrashedReference work properly (e.g. when event listener react)
63 $tree->useCache(false);
64
65 $log = $ilLog;
66
67 // Remove duplicate ids from array
68 $a_ids = array_unique($a_ids);
69
70 // FOR ALL SELECTED OBJECTS
71 $not_deletable = [];
72 $all_node_data = [];
73 foreach ($a_ids as $id) {
74 if ($tree->isDeleted($id)) {
75 if (!$throw_error_on_already_deleted) {
76 continue;
77 }
78 $log->write(__METHOD__ . ': Object with ref_id: ' . $id . ' already deleted.');
79 throw new ilRepositoryException($lng->txt("msg_obj_already_deleted"));
80 }
81
82 // GET COMPLETE NODE_DATA OF ALL SUBTREE NODES
83 $node_data = $tree->getNodeData($id);
84 $subtree_nodes = $tree->getSubTree($node_data);
85
86 $all_node_data[] = $node_data;
87 $all_subtree_nodes[] = $subtree_nodes;
88
89 // CHECK DELETE PERMISSION OF ALL OBJECTS
90 foreach ($subtree_nodes as $node) {
91 if ($node['type'] === 'rolf') {
92 continue;
93 }
94 if (!$rbacsystem->checkAccess('delete', $node["child"])) {
95 $not_deletable[] = $node["child"];
96 $perform_delete = false;
97 }
98 }
99 }
100
101 // IF THERE IS ANY OBJECT WITH NO PERMISSION TO DELETE
102 if (is_array($not_deletable) && count($not_deletable) > 0) {
103 $not_deletable_titles = [];
104 foreach ($not_deletable as $key => $ref_id) {
106 $not_deletable_titles[] = ilObject::_lookupTitle($obj_id);
107 }
108
109 ilSession::clear("saved_post");
110 throw new ilRepositoryException(
111 $lng->txt("msg_no_perm_delete") . " " . implode(', ', $not_deletable_titles) . "<br/>" . $lng->txt("msg_cancel")
112 );
113 }
114
115 // DELETE THEM
116 if (!$all_node_data[0]["type"]) {
117 // alex: this branch looks suspicious to me... I deactivate it for
118 // now. Objects that aren't in the tree should overwrite this method.
119 throw new ilRepositoryException($lng->txt("ilRepUtil::deleteObjects: Type information missing."));
120 }
121
122 // SAVE SUBTREE AND DELETE SUBTREE FROM TREE
123 $affected_ids = [];
124 $affected_parents = [];
125 foreach ($a_ids as $id) {
126 if ($tree->isDeleted($id)) {
127 if (!$throw_error_on_already_deleted) {
128 continue;
129 }
130 $log->write(__METHOD__ . ': Object with ref_id: ' . $id . ' already deleted.');
131 throw new ilRepositoryException($lng->txt("msg_obj_already_deleted"));
132 }
133
134 // DELETE OLD PERMISSION ENTRIES
135 $subnodes = $tree->getSubtree($tree->getNodeData($id));
136
137 foreach ($subnodes as $subnode) {
138 $rbacadmin->revokePermission((int) $subnode["child"]);
139
140 $affected_ids[$subnode["child"]] = $subnode["child"];
141 $affected_parents[$subnode["child"]] = $subnode["parent"];
142 }
143
144 // TODO: needs other handling
145 // This class shouldn't have to know anything about ECS
147 if (!$tree->moveToTrash($id, true, $user->getId())) {
148 $log->write(__METHOD__ . ': Object with ref_id: ' . $id . ' already deleted.');
149 throw new ilRepositoryException($lng->txt("msg_obj_already_deleted"));
150 }
151
152 // write log entry
153 $log->write("ilObjectGUI::confirmedDeleteObject(), moved ref_id " . $id .
154 " to trash");
155
156 $affected_ids[$id] = $id;
157 }
158
159 // send global events
160 foreach ($affected_ids as $aid) {
161 $ilAppEventHandler->raise(
162 "Services/Object",
163 "toTrash",
164 [
165 "obj_id" => ilObject::_lookupObjId($aid),
166 "ref_id" => $aid,
167 "old_parent_ref_id" => $affected_parents[$aid]
168 ]
169 );
170 }
171
172 if (!$ilSetting->get('enable_trash')) {
174 }
175 }
176
186 public static function removeObjectsFromSystem(
187 array $a_ref_ids,
188 bool $a_from_recovery_folder = false
189 ): void {
190 global $DIC;
191
192 $ilLog = $DIC["ilLog"];
193 $ilAppEventHandler = $DIC["ilAppEventHandler"];
194 $tree = $DIC->repositoryTree();
195 $logger = $DIC->logger()->rep();
196
197 $log = $ilLog;
198
199 $affected_ids = [];
200
201 // DELETE THEM
202 $a_ref_ids = array_map('intval', $a_ref_ids);
203 foreach ($a_ref_ids as $id) {
204 $saved_tree = null;
205 // GET COMPLETE NODE_DATA OF ALL SUBTREE NODES
206 if (!$a_from_recovery_folder) {
208 $tree_id = end($trees);
209
210 if ($tree_id) {
211 $saved_tree = new ilTree($tree_id);
212 $node_data = $saved_tree->getNodeData($id);
213 $subtree_nodes = $saved_tree->getSubTree($node_data);
214 } else {
215 throw new ilRepositoryException('No valid tree id found for node id: ' . $id);
216 }
217 } else {
218 $node_data = $tree->getNodeData($id);
219 $subtree_nodes = $tree->getSubTree($node_data);
220 }
221
222 global $DIC;
223
224 $ilUser = $DIC->user();
225 $tree = $DIC->repositoryTree();
226
228 $node_data['obj_id'],
229 $ilUser->getId(),
230 'purge',
231 null
232 );
233 // END ChangeEvent: Record remove from system.
234
235 // remember already checked deleted node_ids
236 if (!$a_from_recovery_folder) {
237 $checked[] = -$id;
238 } else {
239 $checked[] = $id;
240 }
241
242 // dive in recursive manner in each already deleted subtrees and remove these objects too
243 self::removeDeletedNodes($id, $checked, true, $affected_ids);
244
245 foreach ($subtree_nodes as $node) {
246 if (!$node_obj = ilObjectFactory::getInstanceByRefId($node["ref_id"], false)) {
247 continue;
248 }
249
250 $logger->info(
251 'delete obj_id: ' . $node_obj->getId() .
252 ', ref_id: ' . $node_obj->getRefId() .
253 ', type: ' . $node_obj->getType() .
254 ', title: ' . $node_obj->getTitle()
255 );
256 $affected_ids[$node["ref_id"]] = [
257 "ref_id" => $node["ref_id"],
258 "obj_id" => $node_obj->getId(),
259 "type" => $node_obj->getType(),
260 "old_parent_ref_id" => $node["parent"]
261 ];
262
263 // this is due to bug #1860 (even if this will not completely fix it)
264 // and the fact, that media pool folders may find their way into
265 // the recovery folder (what results in broken pools, if the are deleted)
266 // Alex, 2006-07-21
267 if (!$a_from_recovery_folder || $node_obj->getType() !== "fold") {
268 $node_obj->delete();
269 }
270 }
271
272 // Use the saved tree object here (negative tree_id)
273 if (!$a_from_recovery_folder) {
274 if ($saved_tree) {
275 $saved_tree->deleteTree($node_data);
276 }
277 } else {
278 $tree->deleteTree($node_data);
279 }
280
281 $logger->info(
282 'deleted tree, tree_id: ' . $node_data['tree'] .
283 ', child: ' . $node_data['child']
284 );
285 }
286
287 // send global events
288 foreach ($affected_ids as $aid) {
289 $ilAppEventHandler->raise(
290 "Services/Object",
291 "delete",
292 [
293 "obj_id" => $aid["obj_id"],
294 "ref_id" => $aid["ref_id"],
295 "type" => $aid["type"],
296 "old_parent_ref_id" => $aid["old_parent_ref_id"]
297 ]
298 );
299 }
300 }
301
305 private static function removeDeletedNodes(
306 int $a_node_id,
307 array $a_checked,
308 bool $a_delete_objects,
309 array &$a_affected_ids
310 ): void {
311 global $DIC;
312
313 $ilLog = $DIC["ilLog"];
314 $ilDB = $DIC->database();
315 $tree = $DIC->repositoryTree();
316 $logger = $DIC->logger()->rep();
317
318 $log = $ilLog;
319
320 // this queries for trash items in the trash of deleted nodes
321 $q = 'SELECT tree FROM tree WHERE parent = ' . $ilDB->quote($a_node_id, ilDBConstants::T_INTEGER) .
322 ' AND tree < 0 ' .
323 ' AND tree = -1 * child' ;
324
325 $r = $ilDB->query($q);
326
327 while ($row = $ilDB->fetchObject($r)) {
328 // only continue recursion if fetched node wasn't touched already!
329 if (!in_array($row->tree, $a_checked)) {
330 $deleted_tree = new ilTree($row->tree);
331 $a_checked[] = $row->tree;
332
333 $row->tree *= (-1);
334 $del_node_data = $deleted_tree->getNodeData($row->tree);
335 $del_subtree_nodes = $deleted_tree->getSubTree($del_node_data);
336 // delete trash in the trash of trash...
337 self::removeDeletedNodes($row->tree, $a_checked, $a_delete_objects, $a_affected_ids);
338
339 if ($a_delete_objects) {
340 foreach ($del_subtree_nodes as $node) {
341 $node_obj = ilObjectFactory::getInstanceByRefId($node["ref_id"]);
342 $logger->info(
343 'removeDeletedNodes: delete obj_id: ' . $node_obj->getId() .
344 ', ref_id: ' . $node_obj->getRefId() .
345 ', type: ' . $node_obj->getType() .
346 ', title: ' . $node_obj->getTitle()
347 );
348 $a_affected_ids[$node["ref_id"]] = [
349 "ref_id" => $node["ref_id"],
350 "obj_id" => $node_obj->getId(),
351 "type" => $node_obj->getType(),
352 "old_parent_ref_id" => $node["parent"]
353 ];
354 $node_obj->delete();
355 }
356 }
357 // tree instance with -child tree id
358 $trash_tree = new ilTree($del_node_data['tree']);
359 $trash_tree->deleteTree($del_node_data);
360 $logger->info(
361 'removeDeltedNodes: deleted tree, tree_id: ' . $del_node_data['tree'] .
362 ', child: ' . $del_node_data['child']
363 );
364 }
365 }
366 }
367
376 public static function restoreObjects(
377 int $a_cur_ref_id,
378 array $a_ref_ids
379 ): void {
380 global $DIC;
381
382 $rbacsystem = $DIC->rbac()->system();
383 $ilAppEventHandler = $DIC["ilAppEventHandler"];
384 $lng = $DIC->language();
385 $tree = $DIC->repositoryTree();
386
387 $cur_obj_id = ilObject::_lookupObjId($a_cur_ref_id);
388
389 $no_create = [];
390
391 foreach ($a_ref_ids as $id) {
393
394 if (!$rbacsystem->checkAccess('create', $a_cur_ref_id, $obj_data->getType())) {
396 }
397 }
398
399 if (count($no_create)) {
400 throw new ilRepositoryException($lng->txt("msg_no_perm_paste") . " " . implode(',', $no_create));
401 }
402
403 $affected_ids = [];
404
405 foreach ($a_ref_ids as $id) {
406 $affected_ids[$id] = $id;
407
408 // INSERT AND SET PERMISSIONS
409 try {
410 $tree_ids = ilTree::lookupTreesForNode($id);
411 $tree_id = $tree_ids[0];
412 self::insertSavedNodes($id, $a_cur_ref_id, $tree_id, $affected_ids);
413 } catch (Exception $e) {
414 throw new ilRepositoryException('Restore from trash failed with message: ' . $e->getMessage());
415 }
416
417
418 // BEGIN ChangeEvent: Record undelete.
419 global $DIC;
420
421 $ilUser = $DIC->user();
422
423
426 $ilUser->getId(),
427 'undelete',
429 );
431 $cur_obj_id,
432 $ilUser->getId()
433 );
434 // END PATCH ChangeEvent: Record undelete.
435 }
436
437 // send events
438 foreach ($affected_ids as $id) {
439 // send global event
440 $ilAppEventHandler->raise(
441 "Services/Object",
442 "undelete",
443 ["obj_id" => ilObject::_lookupObjId($id), "ref_id" => $id]
444 );
445 }
446 }
447
451 private static function insertSavedNodes(
452 int $a_source_id,
453 int $a_dest_id,
454 int $a_tree_id,
455 array &$a_affected_ids
456 ): void {
457 global $DIC;
458
459 $tree = $DIC->repositoryTree();
460
461 ilLoggerFactory::getLogger('rep')->debug('Restoring from trash: source_id: ' . $a_source_id . ', dest_id: ' . $a_dest_id . ', tree_id:' . $a_tree_id);
462 ilLoggerFactory::getLogger('rep')->info('Restoring ref_id ' . $a_source_id . ' from trash.');
463
464 // read child of node
465 $saved_tree = new ilTree($a_tree_id);
466 $childs = $saved_tree->getChilds($a_source_id);
467
468 // then delete node and put in tree
469 try {
470 $tree->insertNodeFromTrash($a_source_id, $a_dest_id, $a_tree_id, ilTree::POS_LAST_NODE, true);
471 } catch (Exception $e) {
472 ilLoggerFactory::getLogger('rep')->error('Restore from trash failed with message: ' . $e->getMessage());
473 throw $e;
474 }
475
476 $ref_obj = ilObjectFactory::getInstanceByRefId($a_source_id, false);
477 if ($ref_obj instanceof ilObject) {
478 $lroles = $GLOBALS['rbacreview']->getRolesOfRoleFolder($a_source_id, true);
479 foreach ($lroles as $role_id) {
480 $role = new ilObjRole($role_id);
481 $role->setParent($a_source_id);
482 $role->delete();
483 }
484 if ($a_dest_id) {
485 $ref_obj->setPermissions($a_dest_id);
486 }
487 }
488 foreach ($childs as $child) {
489 self::insertSavedNodes($child["child"], $a_source_id, $a_tree_id, $a_affected_ids);
490 }
491 }
492
493
494
495 //
496 // OBJECT TYPE HANDLING / REMOVAL
497 //
498
499 protected function findTypeInTrash(
500 string $a_type
501 ): array {
502 $ilDB = $this->db;
503
504 $res = [];
505
506 $set = $ilDB->query("SELECT child" .
507 " FROM tree" .
508 " JOIN object_reference ref ON (tree.child = ref.ref_id)" .
509 " JOIN object_data od ON (od.obj_id = ref.obj_id)" .
510 " WHERE tree.tree < " . $ilDB->quote(0, "integer") .
511 " AND od.type = " . $ilDB->quote($a_type, "text"));
512 while ($row = $ilDB->fetchAssoc($set)) {
513 $res[] = $row["child"];
514 }
515
516 return $res;
517 }
518
519 protected function getObjectTypeId(
520 string $a_type
521 ): int {
522 $ilDB = $this->db;
523
524 $set = $ilDB->query("SELECT obj_id" .
525 " FROM object_data " .
526 " WHERE type = " . $ilDB->quote("typ", "text") .
527 " AND title = " . $ilDB->quote($a_type, "text"));
528 $row = $ilDB->fetchAssoc($set);
529 return (int) $row["obj_id"];
530 }
531
532 public function deleteObjectType(
533 string $a_type
534 ): void {
535 $ilDB = $this->db;
536 $tree = $this->tree;
538
539 // delete object instances (repository/trash)
540
541 $ref_ids_in_tree = $tree->getSubTree($tree->getNodeData(ROOT_FOLDER_ID), false, [$a_type]);
542 if ($ref_ids_in_tree) {
543 self::deleteObjects(0, $ref_ids_in_tree);
544 }
545
546 if ($ilSetting->get('enable_trash')) {
547 $ref_ids_in_trash = $this->findTypeInTrash($a_type);
548 if ($ref_ids_in_trash) {
549 self::removeObjectsFromSystem($ref_ids_in_trash);
550 }
551 }
552
553 // delete "component"
554 $type_id = $this->getObjectTypeId($a_type);
555 if ($type_id) {
556 // see ilRepositoryObjectPlugin::beforeActivation()
557
558 $ilDB->manipulate("DELETE FROM object_data" .
559 " WHERE obj_id = " . $ilDB->quote($type_id, "integer"));
560
561 // RBAC
562
563 // basic operations
564 $ilDB->manipulate("DELETE FROM rbac_ta" .
565 " WHERE typ_id = " . $ilDB->quote($type_id, "integer") /*.
566 " AND ".$ilDB->in("ops_id", array(1, 2, 3, 4, 6), "", "integer") */);
567
568 // creation operation
569 $set = $ilDB->query("SELECT ops_id" .
570 " FROM rbac_operations " .
571 " WHERE class = " . $ilDB->quote("create", "text") .
572 " AND operation = " . $ilDB->quote("create_" . $a_type, "text"));
573 $row = $ilDB->fetchAssoc($set);
574 $create_ops_id = $row["ops_id"];
575 if ($create_ops_id) {
576 $ilDB->manipulate("DELETE FROM rbac_operations" .
577 " WHERE ops_id = " . $ilDB->quote($create_ops_id, "integer"));
578
579 $ilDB->manipulate("DELETE FROM rbac_templates" .
580 " WHERE ops_id = " . $ilDB->quote($create_ops_id, "integer"));
581
582 // container create
583 foreach (["root", "cat", "crs", "grp", "fold"] as $parent_type) {
584 $parent_type_id = $this->getObjectTypeId($parent_type);
585 if ($parent_type_id) {
586 $ilDB->manipulate("DELETE FROM rbac_ta" .
587 " WHERE typ_id = " . $ilDB->quote($parent_type_id, "integer") .
588 " AND ops_id = " . $ilDB->quote($create_ops_id, "integer"));
589 }
590 }
591 }
592 }
593
594 // delete new item settings
596 }
597}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
if(!defined('PATH_SEPARATOR')) $GLOBALS['_PEAR_default_error_mode']
Definition: PEAR.php:64
static _catchupWriteEvents(int $obj_id, int $usr_id, ?string $timestamp=null)
Catches up with all write events which occured before the specified timestamp.
static _recordWriteEvent(int $obj_id, int $usr_id, string $action, ?int $parent_obj_id=null)
Records a write event.
static _handleDelete(array $a_subbtree_nodes)
handle delete Objects that are moved to the trash call ECS-Remove
static getLogger(string $a_component_id)
Get component logger.
Class ilObjRole.
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _lookupObjId(int $ref_id)
static _lookupTitle(int $obj_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static insertSavedNodes(int $a_source_id, int $a_dest_id, int $a_tree_id, array &$a_affected_ids)
Recursive method to insert all saved nodes of the clipboard.
ilSetting $settings
ilDBInterface $db
static removeDeletedNodes(int $a_node_id, array $a_checked, bool $a_delete_objects, array &$a_affected_ids)
Remove already deleted objects within the objects in trash.
static restoreObjects(int $a_cur_ref_id, array $a_ref_ids)
Move objects from trash back to repository.
static removeObjectsFromSystem(array $a_ref_ids, bool $a_from_recovery_folder=false)
remove objects from trash bin and all entries therefore every object needs a specific deleteObject() ...
static deleteObjects(int $a_cur_ref_id, array $a_ids, bool $throw_error_on_already_deleted=true)
Delete objects.
findTypeInTrash(string $a_type)
getObjectTypeId(string $a_type)
deleteObjectType(string $a_type)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static clear(string $a_var)
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...
insertNodeFromTrash(int $a_source_id, int $a_target_id, int $a_tree_id, int $a_pos=self::POS_LAST_NODE, bool $a_reset_deleted_date=false)
Insert node from trash deletes trash entry.
isDeleted(int $a_node_id)
This is a wrapper for isSaved() with a more useful name.
getNodeData(int $a_node_id, ?int $a_tree_pk=null)
get all information of a node.
useCache(bool $a_use=true)
Use Cache (usually activated)
const POS_LAST_NODE
static lookupTreesForNode(int $node_id)
getSubTree(array $a_node, bool $a_with_data=true, array $a_type=[])
get all nodes in the subtree under specified node
deleteTree(array $a_node)
delete node and the whole subtree under this node
moveToTrash(int $a_node_id, bool $a_set_deleted=false, int $a_deleted_by=0)
Move node to trash bin.
getParentId(int $a_node_id)
get parent id of given node
const ROOT_FOLDER_ID
Definition: constants.php:32
global $DIC
Definition: feed.php:28
$ilUser
Definition: imgupload.php:34
Interface ilDBInterface.
$ref_id
Definition: ltiauth.php:67
$res
Definition: ltiservices.php:69
string $key
Consumer key/client ID value.
Definition: System.php:193
array $settings
Setting values (LTI parameters, custom parameters and local parameters).
Definition: System.php:200
global $ilSetting
Definition: privfeed.php:17
$log
Definition: result.php:33
$lng