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