ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
Deletion.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
23 class Deletion
24 {
25  public function __construct(
26  protected TreeInterface $tree,
27  protected PermissionInterface $permission,
28  protected EventInterface $event,
29  protected ObjectInterface $object,
30  protected bool $trash_enabled
31  ) {
32 
33  }
34 
40  public function deleteObjectsByRefIds(array $ids): void
41  {
42  // check if objects are already deleted
43  if (count($del_ids = $this->tree->getDeletedTreeNodeIds($ids)) > 0) {
44  throw new AlreadyDeletedException('Deletion: Some tree nodes are already deleted: ' . implode(', ', $del_ids));
45  }
46 
47  // check delelete permissions
48  if (count($miss_ids = $this->permission->getRefIdsWithoutDeletePermission($ids)) > 0) {
49  throw new MissingPermissionException('Deletion: missing permission: ' . implode(', ', $miss_ids));
50  }
51 
52  if ($this->trash_enabled) {
53  $this->moveToTrash($ids);
54  } else {
55  $this->removeObjectsFromSystemByRefIds($ids, true);
56  }
57  }
58 
64  array $ref_ids,
65  bool $direct_from_tree = false
66  ): void {
67 
68  $affected_ids = [];
69  $ref_ids = array_map('intval', $ref_ids);
70  foreach ($ref_ids as $id) {
71  $saved_tree = null;
72 
73  // get subtree nodes
74  if (!$direct_from_tree) {
75  // from trash
76  $saved_tree = $this->tree->getTrashTree($id);
77  $node_data = $saved_tree->getNodeData($id);
78  // subtree nodes from trashed tree will include the $id node itself, too
79  $subtree_nodes = $saved_tree->getSubTree($node_data);
80  } else {
81  // from main tree
82  $node_data = $this->tree->getNodeData($id);
83  // subtree nodes will include the $id node itself, too
84  $subtree_nodes = $this->tree->getSubTree($node_data);
85  }
86 
87  $this->event->beforeSubTreeRemoval(
88  $node_data['obj_id']
89  );
90 
91  // remember already checked deleted node_ids
92  if (!$direct_from_tree) {
93  $checked[] = -$id;
94  } else {
95  $checked[] = $id;
96  }
97 
98  // dive in recursive manner in each already deleted subtrees and remove these objects too
99 
100  foreach ($subtree_nodes as $node) {
101  if (!$node_obj = $this->object->getInstanceByRefId($node["ref_id"])) {
102  continue;
103  }
104 
105  // NOTE: This has been outside of the for loop before
106  $this->removeDeletedNodes($node["ref_id"], $checked, true, $affected_ids);
107 
108  $this->event->beforeObjectRemoval(
109  $node_obj->getId(),
110  $node_obj->getRefId(),
111  $node_obj->getType(),
112  $node_obj->getTitle()
113  );
114  $affected_ids[$node["ref_id"]] = [
115  "ref_id" => $node["ref_id"],
116  "obj_id" => $node_obj->getId(),
117  "type" => $node_obj->getType(),
118  "old_parent_ref_id" => $node["parent"]
119  ];
120 
121  // this is due to bug #1860 (even if this will not completely fix it)
122  // and the fact, that media pool folders may find their way into
123  // the recovery folder (what results in broken pools, if the are deleted)
124  // Alex, 2006-07-21
125  if (!$direct_from_tree || $node_obj->getType() !== "fold") {
126  try {
127  $node_obj->delete();
128  } catch (\Exception $e) {
129  $this->event->failedRemoval(
130  $node_obj->getId(),
131  $node_obj->getRefId(),
132  $node_obj->getType(),
133  $node_obj->getTitle(),
134  $e->getMessage()
135  );
136  }
137 
138  }
139  }
140 
141  // Use the saved tree object here (negative tree_id)
142  if (!$direct_from_tree) {
143  if ($saved_tree) {
144  $saved_tree->deleteTree($node_data);
145  }
146  } else {
147  $this->tree->deleteTree($node_data);
148  }
149 
150  $this->event->afterTreeDeletion(
151  (int) $node_data['tree'],
152  (int) $node_data['child']
153  );
154  }
155 
156  // send global events
157  foreach ($affected_ids as $aid) {
158  $this->event->afterObjectRemoval(
159  $aid["obj_id"],
160  $aid["ref_id"],
161  $aid["type"],
162  $aid["old_parent_ref_id"]
163  );
164  }
165  }
166 
170  protected function removeDeletedNodes(
171  int $a_node_id,
172  array $a_checked,
173  bool $a_delete_objects, // seems to be always true
174  array &$a_affected_ids
175  ): void {
176 
177  foreach ($this->tree->getTrashedSubtrees($a_node_id) as $tree_id) {
178  // $tree_id is negative here
179  // only continue recursion if fetched node wasn't touched already!
180  if (!in_array($tree_id, $a_checked)) {
181  $deleted_tree = $this->tree->getTree($tree_id);
182  $a_checked[] = $tree_id;
183 
184  $tree_id *= (-1);
185  // $tree_id is positive here
186  $del_node_data = $deleted_tree->getNodeData($tree_id);
187  $del_subtree_nodes = $deleted_tree->getSubTree($del_node_data);
188  // delete trash in the trash of trash...
189  $this->removeDeletedNodes($tree_id, $a_checked, $a_delete_objects, $a_affected_ids);
190 
191  if ($a_delete_objects) {
192  foreach ($del_subtree_nodes as $node) {
193  $object = $this->object->getInstanceByRefId($node["ref_id"]);
194  if (!is_null($object)) {
195  $a_affected_ids[$node["ref_id"]] = [
196  "ref_id" => $node["ref_id"],
197  "obj_id" => $object->getId(),
198  "type" => $object->getType(),
199  "old_parent_ref_id" => $node["parent"]
200  ];
201  $this->event->beforeObjectRemoval(
202  $object->getId(),
203  $object->getRefId(),
204  $object->getType(),
205  $object->getTitle()
206  );
207  try {
208  $object->delete();
209  } catch (\Exception $e) {
210  $this->event->failedRemoval(
211  $object->getId(),
212  $object->getRefId(),
213  $object->getType(),
214  $object->getTitle(),
215  $e->getMessage()
216  );
217  }
218  }
219  }
220  }
221  // tree instance with -child tree id
222  $trash_tree = $this->tree->getTree((int) $del_node_data['tree']);
223  $trash_tree->deleteTree($del_node_data);
224  $this->event->afterTreeDeletion(
225  (int) $del_node_data['tree'],
226  (int) $del_node_data['child']
227  );
228  }
229  }
230  }
231 
232 
233  protected function moveToTrash(array $ids): void
234  {
235  // save subtree / delete subtree from tree
236  $affected_ids = [];
237  $affected_parents = [];
238  foreach ($ids as $id) {
239  if ($this->tree->isDeleted($id)) {
240  throw new AlreadyDeletedException("Move To Trash: Object with ref_id: " . $id . " already deleted.");
241  }
242 
243  $subnodes = $this->tree->getSubtree($this->tree->getNodeData($id));
244 
245  foreach ($subnodes as $subnode) {
246  $this->permission->revokePermission((int) $subnode["child"]);
247 
248  $affected_ids[$subnode["child"]] = $subnode["child"];
249  $affected_parents[$subnode["child"]] = $subnode["parent"];
250  }
251 
252  $this->event->beforeMoveToTrash($id, $subnodes);
253 
254  if (!$this->tree->moveToTrash($id)) {
255  throw new AlreadyDeletedException("Move To Trash: Object with ref_id: " . $id . " already deleted.");
256  }
257  $affected_ids[$id] = $id;
258  }
259 
260  // send global events
261  foreach ($affected_ids as $aid) {
262  $this->event->afterMoveToTrash($aid, $affected_parents[$aid]);
263  }
264  }
265 
266 
267 }
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
__construct(protected TreeInterface $tree, protected PermissionInterface $permission, protected EventInterface $event, protected ObjectInterface $object, protected bool $trash_enabled)
Definition: Deletion.php:25
removeObjectsFromSystemByRefIds(array $ref_ids, bool $direct_from_tree=false)
Remove objects from system directly ($direct_from_tree === true) or from trash ($direct_from_tree ===...
Definition: Deletion.php:63
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
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.
Definition: Deletion.php:170
deleteObjectsByRefIds(array $ids)
Delete: If trash is enabled, objects are moved to the trash.
Definition: Deletion.php:40