ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
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 
4 include_once("./Services/Object/classes/class.ilObjectFactory.php");
5 
13 class ilRepUtil
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) {
381  $obj_data = ilObjectFactory::getInstanceByRefId($id);
382 
383  if (!$rbacsystem->checkAccess('create', $a_cur_ref_id, $obj_data->getType())) {
384  $no_create[] = ilObject::_lookupTitle(ilObject::_lookupObjId($id));
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';
463  $factory = new ilObjectFactory();
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  {
490  $ilDB = $this->db;
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  {
509  $ilDB = $this->db;
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  {
521  $ilDB = $this->db;
522  $tree = $this->tree;
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 }
Class ilObjRole.
static removeItemFromDesktops($a_id)
removes object from all user&#39;s desktops public
settings()
Definition: settings.php:2
Class ilObjectFactory.
Repository Utilities (application layer, put GUI related stuff into ilRepUtilGUI) ...
getObjectTypeId($a_type)
global $DIC
Definition: saml.php:7
static removeDeletedNodes( $a_node_id, $a_checked, $a_delete_objects, &$a_affected_ids)
Remove already deleted objects within the objects in trash.
static _handleDelete(array $a_subbtree_nodes)
handle delete Objects that are moved to the trash call ECS-Remove
__construct()
Constructor.
static _recordWriteEvent($obj_id, $usr_id, $action, $parent_obj_id=null)
Records a write event.
$factory
Definition: metadata.php:43
if(!array_key_exists('StateId', $_REQUEST)) $id
static _lookupTitle($a_id)
lookup object title
$log
Definition: sabredav.php:21
static restoreObjects($a_cur_ref_id, $a_ref_ids)
Move objects from trash back to repository.
deleteObjectType($a_type)
static _catchupWriteEvents($obj_id, $usr_id, $timestamp=null)
Catches up with all write events which occured before the specified timestamp.
static insertSavedNodes($a_source_id, $a_dest_id, $a_tree_id, &$a_affected_ids)
Recursive method to insert all saved nodes of the clipboard.
$a_type
Definition: workflow.php:92
$r
Definition: example_031.php:79
foreach($_POST as $key=> $value) $res
$lng
static _lookupObjId($a_id)
$ilUser
Definition: imgupload.php:18
static clear($a_var)
Unset a value.
static getInstanceByObjId($a_obj_id, $stop_on_error=true)
get an instance of an Ilias object by object id
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
$row
const IL_LAST_NODE
Definition: class.ilTree.php:4
global $ilSetting
Definition: privfeed.php:17
global $ilDB
static getInstanceByRefId($a_ref_id, $stop_on_error=true)
get an instance of an Ilias object by reference id
static getLogger($a_component_id)
Get component logger.
$key
Definition: croninfo.php:18
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
findTypeInTrash($a_type)
static deleteObjects($a_cur_ref_id, $a_ids)
Delete objects.
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() ...