ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.ilRepUtil.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once("./Services/Object/classes/class.ilObjectFactory.php");
5
14{
18 protected $db;
19
23 protected $tree;
24
28 protected $settings;
29
30
34 public function __construct()
35 {
36 global $DIC;
37
38 $this->db = $DIC->database();
39 $this->tree = $DIC->repositoryTree();
40 $this->settings = $DIC->settings();
41 }
42
43
50 public static function deleteObjects($a_cur_ref_id, $a_ids)
51 {
52 global $DIC;
53
54 $ilAppEventHandler = $DIC["ilAppEventHandler"];
55 $rbacsystem = $DIC->rbac()->system();
56 $rbacadmin = $DIC->rbac()->admin();
57 $ilLog = $DIC["ilLog"];
58 $tree = $DIC->repositoryTree();
59 $lng = $DIC->language();
60 $ilSetting = $DIC->settings();
61
62 $log = $ilLog;
63
64 include_once("./Services/Repository/exceptions/class.ilRepositoryException.php");
65
66 // Remove duplicate ids from array
67 $a_ids = array_unique((array) $a_ids);
68
69 // FOR ALL SELECTED OBJECTS
70 $not_deletable = [];
71 foreach ($a_ids as $id) {
72 if ($tree->isDeleted($id)) {
73 $log->write(__METHOD__ . ': Object with ref_id: ' . $id . ' already deleted.');
74 throw new ilRepositoryException($lng->txt("msg_obj_already_deleted"));
75 }
76
77 // GET COMPLETE NODE_DATA OF ALL SUBTREE NODES
78 $node_data = $tree->getNodeData($id);
79 $subtree_nodes = $tree->getSubTree($node_data);
80
81 $all_node_data[] = $node_data;
82 $all_subtree_nodes[] = $subtree_nodes;
83
84 // CHECK DELETE PERMISSION OF ALL OBJECTS
85 foreach ($subtree_nodes as $node) {
86 if ($node['type'] == 'rolf') {
87 continue;
88 }
89 if (!$rbacsystem->checkAccess('delete', $node["child"])) {
90 $not_deletable[] = $node["child"];
91 $perform_delete = false;
92 }
93 }
94 }
95
96 // IF THERE IS ANY OBJECT WITH NO PERMISSION TO DELETE
97 if (is_array($not_deletable) && count($not_deletable) > 0) {
98 $not_deletable_titles = array();
99 foreach ($not_deletable as $key => $ref_id) {
100 $obj_id = ilObject::_lookupObjId($ref_id);
101 $not_deletable_titles[] = ilObject::_lookupTitle($obj_id);
102 }
103
104 ilSession::clear("saved_post");
105 throw new ilRepositoryException(
106 $lng->txt("msg_no_perm_delete") . " " . implode(', ', $not_deletable_titles) . "<br/>" . $lng->txt("msg_cancel")
107 );
108 }
109
110 // DELETE THEM
111 if (!$all_node_data[0]["type"]) {
112 // alex: this branch looks suspicious to me... I deactivate it for
113 // now. Objects that aren't in the tree should overwrite this method.
114 throw new ilRepositoryException($lng->txt("ilRepUtil::deleteObjects: Type information missing."));
115 // OBJECTS ARE NO 'TREE OBJECTS'
116 if ($rbacsystem->checkAccess('delete', $a_cur_ref_id)) {
117 foreach ($a_ids as $id) {
119 $obj->delete();
120
121 // write log entry
122 $log->write("ilObjectGUI::confirmedDeleteObject(), deleted obj_id " . $obj->getId() .
123 ", type: " . $obj->getType() . ", title: " . $obj->getTitle());
124 }
125 } else {
126 throw new ilRepositoryException(
127 $lng->txt("no_perm_delete") . "<br/>" . $lng->txt("msg_cancel")
128 );
129 }
130 } else {
131 // SAVE SUBTREE AND DELETE SUBTREE FROM TREE
132 $affected_ids = array();
133 $affected_parents = array();
134 foreach ($a_ids as $id) {
135 if ($tree->isDeleted($id)) {
136 $log->write(__METHOD__ . ': Object with ref_id: ' . $id . ' already deleted.');
137 throw new ilRepositoryException($lng->txt("msg_obj_already_deleted"));
138 }
139
140 // DELETE OLD PERMISSION ENTRIES
141 $subnodes = $tree->getSubtree($tree->getNodeData($id));
142
143 foreach ($subnodes as $subnode) {
144 $rbacadmin->revokePermission($subnode["child"]);
145 // remove item from all user desktops
146 $affected_users = ilUtil::removeItemFromDesktops($subnode["child"]);
147
148 $affected_ids[$subnode["child"]] = $subnode["child"];
149 $affected_parents[$subnode["child"]] = $subnode["parent"];
150
151 // TODO: inform users by mail that object $id was deleted
152 //$mail->sendMail($id,$msg,$affected_users);
153 // should go to appevents at the end
154 }
155
156 // TODO: needs other handling
157 // This class shouldn't have to know anything about ECS
158 include_once('./Services/WebServices/ECS/classes/class.ilECSObjectSettings.php');
160
161 if (!$tree->saveSubTree($id, true)) {
162 $log->write(__METHOD__ . ': Object with ref_id: ' . $id . ' already deleted.');
163 throw new ilRepositoryException($lng->txt("msg_obj_already_deleted"));
164 }
165
166 // write log entry
167 $log->write("ilObjectGUI::confirmedDeleteObject(), moved ref_id " . $id .
168 " to trash");
169
170 // remove item from all user desktops
171 $affected_users = ilUtil::removeItemFromDesktops($id);
172
173 $affected_ids[$id] = $id;
174
175 // TODO: inform users by mail that object $id was deleted
176 //$mail->sendMail($id,$msg,$affected_users);
177 }
178
179 // send global events
180 foreach ($affected_ids as $aid) {
181 $ilAppEventHandler->raise(
182 "Services/Object",
183 "toTrash",
184 array( "obj_id" => ilObject::_lookupObjId($aid),
185 "ref_id" => $aid,
186 "old_parent_ref_id" => $affected_parents[$aid]
187 )
188 );
189 }
190 }
191
192 if (!$ilSetting->get('enable_trash')) {
194 }
195 }
196
202 public static function removeObjectsFromSystem($a_ref_ids, $a_from_recovery_folder = false)
203 {
204 global $DIC;
205
206 $ilLog = $DIC["ilLog"];
207 $ilAppEventHandler = $DIC["ilAppEventHandler"];
208 $tree = $DIC->repositoryTree();
209
210 $log = $ilLog;
211
212 $affected_ids = array();
213
214 // DELETE THEM
215 foreach ($a_ref_ids as $id) {
216 // GET COMPLETE NODE_DATA OF ALL SUBTREE NODES
217 if (!$a_from_recovery_folder) {
218 $saved_tree = new ilTree(-(int) $id);
219 $node_data = $saved_tree->getNodeData($id);
220 $subtree_nodes = $saved_tree->getSubTree($node_data);
221 } else {
222 $node_data = $tree->getNodeData($id);
223 $subtree_nodes = $tree->getSubTree($node_data);
224 }
225
226 // BEGIN ChangeEvent: Record remove from system.
227 require_once('Services/Tracking/classes/class.ilChangeEvent.php');
228 // Record write event
229 global $DIC;
230
231 $ilUser = $DIC->user();
232 $tree = $DIC->repositoryTree();
233 $parent_data = $tree->getParentNodeData($node_data['ref_id']);
235 $node_data['obj_id'],
236 $ilUser->getId(),
237 'purge',
238 $parent_data['obj_id']
239 );
240 // END ChangeEvent: Record remove from system.
241
242 // remember already checked deleted node_ids
243 if (!$a_from_recovery_folder) {
244 $checked[] = -(int) $id;
245 } else {
246 $checked[] = $id;
247 }
248
249 // dive in recursive manner in each already deleted subtrees and remove these objects too
250 ilRepUtil::removeDeletedNodes($id, $checked, true, $affected_ids);
251
252 foreach ($subtree_nodes as $node) {
253 if (!$node_obj = ilObjectFactory::getInstanceByRefId($node["ref_id"], false)) {
254 continue;
255 }
256
257 // write log entry
258 $log->write("ilObjectGUI::removeFromSystemObject(), delete obj_id: " . $node_obj->getId() .
259 ", ref_id: " . $node_obj->getRefId() . ", type: " . $node_obj->getType() . ", " .
260 "title: " . $node_obj->getTitle());
261 $affected_ids[$node["ref_id"]] = array(
262 "ref_id" => $node["ref_id"],
263 "obj_id" => $node_obj->getId(),
264 "type" => $node_obj->getType(),
265 "old_parent_ref_id" => $node["parent"]);
266
267 // this is due to bug #1860 (even if this will not completely fix it)
268 // and the fact, that media pool folders may find their way into
269 // the recovery folder (what results in broken pools, if the are deleted)
270 // Alex, 2006-07-21
271 if (!$a_from_recovery_folder || $node_obj->getType() != "fold") {
272 $node_obj->delete();
273 }
274 }
275
276 // Use the saved tree object here (negative tree_id)
277 if (!$a_from_recovery_folder) {
278 $saved_tree->deleteTree($node_data);
279 } else {
280 $tree->deleteTree($node_data);
281 }
282
283 // write log entry
284 $log->write("ilObjectGUI::removeFromSystemObject(), deleted tree, tree_id: " . $node_data["tree"] .
285 ", child: " . $node_data["child"]);
286 }
287
288 // send global events
289 foreach ($affected_ids as $aid) {
290 $ilAppEventHandler->raise(
291 "Services/Object",
292 "delete",
293 array("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
304 private static function removeDeletedNodes(
305 $a_node_id,
306 $a_checked,
307 $a_delete_objects,
308 &$a_affected_ids
309 ) {
310 global $DIC;
311
312 $ilLog = $DIC["ilLog"];
313 $ilDB = $DIC->database();
314 $tree = $DIC->repositoryTree();
315
316 $log = $ilLog;
317
318 $q = "SELECT tree FROM tree WHERE parent= " .
319 $ilDB->quote($a_node_id, "integer") . " AND tree < 0";
320
321 $r = $ilDB->query($q);
322
323 while ($row = $ilDB->fetchObject($r)) {
324 // only continue recursion if fetched node wasn't touched already!
325 if (!in_array($row->tree, $a_checked)) {
326 $deleted_tree = new ilTree($row->tree);
327 $a_checked[] = $row->tree;
328
329 $row->tree = $row->tree * (-1);
330 $del_node_data = $deleted_tree->getNodeData($row->tree);
331 $del_subtree_nodes = $deleted_tree->getSubTree($del_node_data);
332
333 ilRepUtil::removeDeletedNodes($row->tree, $a_checked, $a_delete_objects, $a_affected_ids);
334
335 if ($a_delete_objects) {
336 foreach ($del_subtree_nodes as $node) {
337 $node_obj = ilObjectFactory::getInstanceByRefId($node["ref_id"]);
338
339 // write log entry
340 $log->write("ilObjectGUI::removeDeletedNodes(), delete obj_id: " . $node_obj->getId() .
341 ", ref_id: " . $node_obj->getRefId() . ", type: " . $node_obj->getType() . ", " .
342 "title: " . $node_obj->getTitle());
343 $a_affected_ids[$node["ref_id"]] = array(
344 "ref_id" => $node["ref_id"],
345 "obj_id" => $node_obj->getId(),
346 "type" => $node_obj->getType(),
347 "old_parent_ref_id" => $node["parent"]);
348
349 $node_obj->delete();
350 }
351 }
352
353 $tree->deleteTree($del_node_data);
354
355 // write log entry
356 $log->write("ilObjectGUI::removeDeletedNodes(), deleted tree, tree_id: " . $del_node_data["tree"] .
357 ", child: " . $del_node_data["child"]);
358 }
359 }
360
361 return true;
362 }
363
367 public static function restoreObjects($a_cur_ref_id, $a_ref_ids)
368 {
369 global $DIC;
370
371 $rbacsystem = $DIC->rbac()->system();
372 $ilAppEventHandler = $DIC["ilAppEventHandler"];
373 $lng = $DIC->language();
374 $tree = $DIC->repositoryTree();
375
376 $cur_obj_id = ilObject::_lookupObjId($a_cur_ref_id);
377
378 $no_create = [];
379
380 foreach ($a_ref_ids as $id) {
382
383 if (!$rbacsystem->checkAccess('create', $a_cur_ref_id, $obj_data->getType())) {
385 }
386 }
387
388 if (count($no_create)) {
389 include_once("./Services/Repository/exceptions/class.ilRepositoryException.php");
390 throw new ilRepositoryException($lng->txt("msg_no_perm_paste") . " " . implode(',', $no_create));
391 }
392
393 $affected_ids = array();
394
395 foreach ($a_ref_ids as $id) {
396 $affected_ids[$id] = $id;
397
398 // INSERT AND SET PERMISSIONS
399 try {
400 ilRepUtil::insertSavedNodes($id, $a_cur_ref_id, -(int) $id, $affected_ids);
401 } catch (Exception $e) {
402 include_once("./Services/Repository/exceptions/class.ilRepositoryException.php");
403 throw new ilRepositoryException('Restore from trash failed with message: ' . $e->getMessage());
404 }
405
406
407 // BEGIN ChangeEvent: Record undelete.
408 require_once('Services/Tracking/classes/class.ilChangeEvent.php');
409 global $DIC;
410
411 $ilUser = $DIC->user();
412
413
416 $ilUser->getId(),
417 'undelete',
418 ilObject::_lookupObjId($tree->getParentId($id))
419 );
421 $cur_obj_id,
422 $ilUser->getId()
423 );
424 // END PATCH ChangeEvent: Record undelete.
425 }
426
427 // send events
428 foreach ($affected_ids as $id) {
429 // send global event
430 $ilAppEventHandler->raise(
431 "Services/Object",
432 "undelete",
433 array("obj_id" => ilObject::_lookupObjId($id), "ref_id" => $id)
434 );
435 }
436 }
437
441 private static function insertSavedNodes($a_source_id, $a_dest_id, $a_tree_id, &$a_affected_ids)
442 {
443 global $DIC;
444
445 $tree = $DIC->repositoryTree();
446
447 ilLoggerFactory::getLogger('rep')->debug('Restoring from trash: source_id: ' . $a_source_id . ', dest_id: ' . $a_dest_id . ', tree_id:' . $a_tree_id);
448 ilLoggerFactory::getLogger('rep')->info('Restoring ref_id ' . $a_source_id . ' from trash.');
449
450 // read child of node
451 $saved_tree = new ilTree($a_tree_id);
452 $childs = $saved_tree->getChilds($a_source_id);
453
454 // then delete node and put in tree
455 try {
456 $tree->insertNodeFromTrash($a_source_id, $a_dest_id, $a_tree_id, IL_LAST_NODE, true);
457 } catch (Exception $e) {
458 ilLoggerFactory::getLogger('rep')->error('Restore from trash failed with message: ' . $e->getMessage());
459 throw $e;
460 }
461
462 include_once './Services/Object/classes/class.ilObjectFactory.php';
464 $ref_obj = $factory->getInstanceByRefId($a_source_id, false);
465 if ($ref_obj instanceof ilObject) {
466 $lroles = $GLOBALS['rbacreview']->getRolesOfRoleFolder($a_source_id, true);
467 foreach ($lroles as $role_id) {
468 include_once './Services/AccessControl/classes/class.ilObjRole.php';
469 $role = new ilObjRole($role_id);
470 $role->setParent($a_source_id);
471 $role->delete();
472 }
473 if ($a_dest_id) {
474 $ref_obj->setPermissions($a_dest_id);
475 }
476 }
477 foreach ($childs as $child) {
478 ilRepUtil::insertSavedNodes($child["child"], $a_source_id, $a_tree_id, $a_affected_ids);
479 }
480 }
481
482
483
484 //
485 // OBJECT TYPE HANDLING / REMOVAL
486 //
487
488 protected function findTypeInTrash($a_type)
489 {
491
492 $res = array();
493
494 $set = $ilDB->query("SELECT child" .
495 " FROM tree" .
496 " JOIN object_reference ref ON (tree.child = ref.ref_id)" .
497 " JOIN object_data od ON (od.obj_id = ref.obj_id)" .
498 " WHERE tree.tree < " . $ilDB->quote(0, "integer") .
499 " AND od.type = " . $ilDB->quote($a_type, "text"));
500 while ($row = $ilDB->fetchAssoc($set)) {
501 $res[] = $row["child"];
502 }
503
504 return $res;
505 }
506
507 protected function getObjectTypeId($a_type)
508 {
510
511 $set = $ilDB->query("SELECT obj_id" .
512 " FROM object_data " .
513 " WHERE type = " . $ilDB->quote("typ", "text") .
514 " AND title = " . $ilDB->quote($a_type, "text"));
515 $row = $ilDB->fetchAssoc($set);
516 return $row["obj_id"];
517 }
518
519 public function deleteObjectType($a_type)
520 {
524
525 // delete object instances (repository/trash)
526
527 $ref_ids_in_tree = $tree->getSubTree($tree->getNodeData(ROOT_FOLDER_ID), false, $a_type);
528 if ($ref_ids_in_tree) {
529 $this->deleteObjects(null, $ref_ids_in_tree);
530 }
531
532 if ($ilSetting->get('enable_trash')) {
533 $ref_ids_in_trash = $this->findTypeInTrash($a_type);
534 if ($ref_ids_in_trash) {
535 self::removeObjectsFromSystem($ref_ids_in_trash);
536 }
537 }
538
539 // delete "component"
540 $type_id = $this->getObjectTypeId($a_type);
541 if ($type_id) {
542 // see ilRepositoryObjectPlugin::beforeActivation()
543
544 $ilDB->manipulate("DELETE FROM object_data" .
545 " WHERE obj_id = " . $ilDB->quote($type_id, "integer"));
546
547 // RBAC
548
549 // basic operations
550 $ilDB->manipulate("DELETE FROM rbac_ta" .
551 " WHERE typ_id = " . $ilDB->quote($type_id, "integer") /*.
552 " AND ".$ilDB->in("ops_id", array(1, 2, 3, 4, 6), "", "integer") */);
553
554 // creation operation
555 $set = $ilDB->query("SELECT ops_id" .
556 " FROM rbac_operations " .
557 " WHERE class = " . $ilDB->quote("create", "text") .
558 " AND operation = " . $ilDB->quote("create_" . $a_type, "text"));
559 $row = $ilDB->fetchAssoc($set);
560 $create_ops_id = $row["ops_id"];
561 if ($create_ops_id) {
562 $ilDB->manipulate("DELETE FROM rbac_operations" .
563 " WHERE ops_id = " . $ilDB->quote($create_ops_id, "integer"));
564
565 $ilDB->manipulate("DELETE FROM rbac_templates" .
566 " WHERE ops_id = " . $ilDB->quote($create_ops_id, "integer"));
567
568 // container create
569 foreach (array("root", "cat", "crs", "grp", "fold") as $parent_type) {
570 $parent_type_id = $this->getObjectTypeId($parent_type);
571 if ($parent_type_id) {
572 $ilDB->manipulate("DELETE FROM rbac_ta" .
573 " WHERE typ_id = " . $ilDB->quote($parent_type_id, "integer") .
574 " AND ops_id = " . $ilDB->quote($create_ops_id, "integer"));
575 }
576 }
577 }
578 }
579
580 // delete new item settings
581 include_once "Services/Repository/classes/class.ilObjRepositorySettings.php";
583 }
584}
$factory
Definition: metadata.php:47
An exception for terminatinating execution or to throw for unit testing.
const IL_LAST_NODE
Definition: class.ilTree.php:4
static _catchupWriteEvents($obj_id, $usr_id, $timestamp=null)
Catches up with all write events which occured before the specified timestamp.
static _recordWriteEvent($obj_id, $usr_id, $action, $parent_obj_id=null)
Records a write event.
static _handleDelete(array $a_subbtree_nodes)
static getLogger($a_component_id)
Get component logger.
Class ilObjRole.
Class ilObjectFactory.
static getInstanceByObjId($a_obj_id, $stop_on_error=true)
get an instance of an Ilias object by object id
static getInstanceByRefId($a_ref_id, $stop_on_error=true)
get an instance of an Ilias object by reference id
Class ilObject Basic functions for all objects.
static _lookupObjId($a_id)
static _lookupTitle($a_id)
lookup object title
Repository Utilities (application layer, put GUI related stuff into ilRepUtilGUI)
static deleteObjects($a_cur_ref_id, $a_ids)
Delete objects.
findTypeInTrash($a_type)
static removeDeletedNodes( $a_node_id, $a_checked, $a_delete_objects, &$a_affected_ids)
Remove already deleted objects within the objects in trash.
getObjectTypeId($a_type)
static restoreObjects($a_cur_ref_id, $a_ref_ids)
Move objects from trash back to repository.
deleteObjectType($a_type)
static insertSavedNodes($a_source_id, $a_dest_id, $a_tree_id, &$a_affected_ids)
Recursive method to insert all saved nodes of the clipboard.
static removeObjectsFromSystem($a_ref_ids, $a_from_recovery_folder=false)
remove objects from trash bin and all entries therefore every object needs a specific deleteObject() ...
__construct()
Constructor.
static clear($a_var)
Unset a value.
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
static removeItemFromDesktops($a_id)
removes object from all user's desktops @access public
$key
Definition: croninfo.php:18
$r
Definition: example_031.php:79
if(!array_key_exists('StateId', $_REQUEST)) $id
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
global $lng
Definition: privfeed.php:17
global $ilSetting
Definition: privfeed.php:17
global $DIC
Definition: saml.php:7
foreach($_POST as $key=> $value) $res
settings()
Definition: settings.php:2
global $ilDB
$ilUser
Definition: imgupload.php:18
$a_type
Definition: workflow.php:92