ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilLPCollectionOfRepositoryObjects.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=0);
20 
27 {
28  protected static array $possible_items = array();
29 
30  protected ilTree $tree;
32 
33  public function __construct(int $a_obj_id, int $a_mode)
34  {
35  global $DIC;
36 
37  $this->tree = $DIC->repositoryTree();
38  $this->objDefinition = $DIC['objDefinition'];
39 
40  parent::__construct($a_obj_id, $a_mode);
41  }
42 
43  public function getPossibleItems(
44  int $a_ref_id,
45  bool $a_full_data = false
46  ): array {
47  global $DIC;
48 
49  $cache_idx = $a_ref_id . "__" . $a_full_data;
50  if (!isset(self::$possible_items[$cache_idx])) {
51  $all_possible = array();
52 
53  if (!$this->tree->isDeleted($a_ref_id)) {
54  if (!$a_full_data) {
55  $data = $this->tree->getRbacSubtreeInfo($a_ref_id);
56  } else {
57  $node = $this->tree->getNodeData($a_ref_id);
58  $data = $this->tree->getSubTree($node);
59  }
60  foreach ($data as $node) {
61  if (!$a_full_data) {
62  $item_ref_id = (int) $node['child'];
63  } else {
64  $item_ref_id = (int) $node['ref_id'];
65  }
66 
67  // avoid recursion
68  if ($item_ref_id == $a_ref_id || !$this->validateEntry(
69  $item_ref_id
70  )) {
71  continue;
72  }
73 
74  switch ($node['type']) {
75  case 'sess':
76  case 'exc':
77  case 'fold':
78  case 'grp':
79  case 'sahs':
80  case 'lm':
81  case 'tst':
82  case 'file':
83  case 'mcst':
84  case 'htlm':
85  case 'svy':
86  case "prg":
87  case 'iass':
88  case 'copa':
89  case 'frm':
90  case 'cmix':
91  case 'lti':
92  case 'lso':
93  case 'crsr':
94  if (!$a_full_data) {
95  $all_possible[] = $item_ref_id;
96  } else {
97  $all_possible[$item_ref_id] = array(
98  'ref_id' => (int) $item_ref_id,
99  'obj_id' => (int) $node['obj_id'],
100  'title' => (string) $node['title'],
101  'description' => (string) $node['description'],
102  'type' => (string) $node['type']
103  );
104  }
105  break;
106 
107  // repository plugin object?
108  case $this->objDefinition->isPluginTypeName(
109  $node['type']
110  ):
111  $only_active = false;
112  if (!$this->isAssignedEntry($item_ref_id)) {
113  $only_active = true;
114  }
116  $node['type'],
117  $only_active
118  )) {
119  if (!$a_full_data) {
120  $all_possible[] = $item_ref_id;
121  } else {
122  $all_possible[$item_ref_id] = array(
123  'ref_id' => (int) $item_ref_id,
124  'obj_id' => (int) $node['obj_id'],
125  'title' => (string) $node['title'],
126  'description' => (string) $node['description'],
127  'type' => (string) $node['type']
128  );
129  }
130  }
131  break;
132  }
133  }
134  }
135 
136  self::$possible_items[$cache_idx] = $all_possible;
137  }
138 
139  return self::$possible_items[$cache_idx];
140  }
141 
142  protected function validateEntry(int $a_item_id): bool
143  {
144  $a_item_type = ilObject::_lookupType($a_item_id, true);
145  // this is hardcoded so we do not need to call all ObjectLP types
146  if ($a_item_type == 'tst') {
147  // Check anonymized
148  $item_obj_id = ilObject::_lookupObjId($a_item_id);
149  $olp = ilObjectLP::getInstance($item_obj_id);
150  if ($olp->isAnonymized()) {
151  return false;
152  }
153  }
154  return true;
155  }
156 
157  public function cloneCollection(int $a_target_id, int $a_copy_id): void
158  {
159  parent::cloneCollection($a_target_id, $a_copy_id);
160 
161  $cwo = ilCopyWizardOptions::_getInstance($a_copy_id);
162  $mappings = $cwo->getMappings();
163 
164  $target_obj_id = ilObject::_lookupObjId($a_target_id);
165  $target_collection = new static($target_obj_id, $this->mode);
166 
167  // clone (active) groupings
168  foreach ($this->getGroupedItemsForLPStatus(
169  ) as $grouping_id => $group) {
170  $target_item_ids = array();
171  foreach ($group["items"] as $item) {
172  if (!isset($mappings[$item]) or !$mappings[$item]) {
173  continue;
174  }
175 
176  $target_item_ids[] = $mappings[$item];
177  }
178 
179  // grouping - if not only single item left after copy?
180  if ($grouping_id && sizeof($target_item_ids) > 1) {
181  // should not be larger than group
182  $num_obligatory = min(
183  sizeof($target_item_ids),
184  $group["num_obligatory"]
185  );
186 
187  $target_collection->createNewGrouping(
188  $target_item_ids,
189  $num_obligatory
190  );
191  } else {
192  // #15487 - single items
193  foreach ($target_item_ids as $item_id) {
194  $this->addEntry($item_id);
195  }
196  }
197  }
198  }
199 
200  protected function read(int $a_obj_id): void
201  {
202  $items = array();
203 
204  $ref_ids = ilObject::_getAllReferences($a_obj_id);
205  $ref_id = end($ref_ids);
206  $possible = $this->getPossibleItems($ref_id);
207 
208  $res = $this->db->query(
209  "SELECT utc.item_id, obd.type" .
210  " FROM ut_lp_collections utc" .
211  " JOIN object_reference obr ON item_id = ref_id" .
212  " JOIN object_data obd ON obr.obj_id = obd.obj_id" .
213  " WHERE utc.obj_id = " . $this->db->quote($a_obj_id, "integer") .
214  " AND active = " . $this->db->quote(1, "integer") .
215  " ORDER BY title"
216  );
217  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
218  if (in_array($row->item_id, $possible) &&
219  $this->validateEntry((int) $row->item_id)) {
220  $items[] = $row->item_id;
221  } else {
222  $this->deleteEntry((int) $row->item_id);
223  }
224  }
225 
226  $this->items = $items;
227  }
228 
229  protected function addEntry(int $a_item_id): bool
230  {
231  // only active entries are assigned!
232  if (!$this->isAssignedEntry($a_item_id)) {
233  // #13278 - because of grouping inactive items may exist
234  $this->deleteEntry($a_item_id);
235 
236  $query = "INSERT INTO ut_lp_collections" .
237  " (obj_id, lpmode, item_id, grouping_id, num_obligatory, active)" .
238  " VALUES (" . $this->db->quote($this->obj_id, "integer") .
239  ", " . $this->db->quote($this->mode, "integer") .
240  ", " . $this->db->quote($a_item_id, "integer") .
241  ", " . $this->db->quote(0, "integer") .
242  ", " . $this->db->quote(0, "integer") .
243  ", " . $this->db->quote(1, "integer") .
244  ")";
245  $this->db->manipulate($query);
246  $this->items[] = $a_item_id;
247  }
248  return true;
249  }
250 
251  protected function deleteEntry(int $a_item_id): bool
252  {
253  $query = "DELETE FROM ut_lp_collections " .
254  " WHERE obj_id = " . $this->db->quote($this->obj_id, "integer") .
255  " AND item_id = " . $this->db->quote($a_item_id, "integer") .
256  " AND grouping_id = " . $this->db->quote(0, "integer");
257  $this->db->manipulate($query);
258  return true;
259  }
260 
261  public static function hasGroupedItems(int $a_obj_id): bool
262  {
263  global $DIC;
264 
265  $ilDB = $DIC['ilDB'];
266  $query = "SELECT item_id FROM ut_lp_collections" .
267  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer") .
268  " AND grouping_id > " . $ilDB->quote(0, "integer");
269  $res = $ilDB->query($query);
270  return $res->numRows() ? true : false;
271  }
272 
273  protected function getNonGroupedItems(array $a_item_ids): array
274  {
275  $grouped_item_ids = [];
276 
277  $query = "SELECT item_id FROM ut_lp_collections" .
278  " WHERE obj_id = " . $this->db->quote($this->obj_id, ilDBConstants::T_INTEGER) .
279  " AND " . $this->db->in("item_id", $a_item_ids, false, ilDBConstants::T_INTEGER) .
280  " AND grouping_id > " . $this->db->quote(0, ilDBConstants::T_INTEGER);
281  $res = $this->db->query($query);
282  while ($row = $res->fetchObject()) {
283  $grouped_item_ids[] = $row->item_id;
284  }
285 
286  return array_diff($a_item_ids, $grouped_item_ids);
287  }
288 
289  protected function getGroupingIds(array $a_item_ids): array
290  {
291  $grouping_ids = [];
292 
293  $query = "SELECT grouping_id FROM ut_lp_collections" .
294  " WHERE obj_id = " . $this->db->quote($this->obj_id, ilDBConstants::T_INTEGER) .
295  " AND " . $this->db->in("item_id", $a_item_ids, false, ilDBConstants::T_INTEGER) .
296  " AND grouping_id > " . $this->db->quote(0, ilDBConstants::T_INTEGER);
297  $res = $this->db->query($query);
298  while ($row = $res->fetchObject()) {
299  $grouping_ids[] = $row->grouping_id;
300  }
301 
302  return $grouping_ids;
303  }
304 
305  public function deactivateEntries(array $a_item_ids): void
306  {
307  parent::deactivateEntries($a_item_ids);
308 
309  $grouping_ids = $this->getGroupingIds($a_item_ids);
310  if ($grouping_ids) {
311  $query = "UPDATE ut_lp_collections" .
312  " SET active = " . $this->db->quote(0, "integer") .
313  " WHERE " . $this->db->in(
314  "grouping_id",
315  $grouping_ids,
316  false,
317  "integer"
318  ) .
319  " AND obj_id = " . $this->db->quote($this->obj_id, "integer");
320  $this->db->manipulate($query);
321  }
322  }
323 
324  public function activateEntries(array $a_item_ids): void
325  {
326  // 44683: only activate non-grouped items via parent
327  $non_grouped_ids = $this->getNonGroupedItems($a_item_ids);
328  parent::activateEntries($non_grouped_ids);
329 
330  $grouping_ids = $this->getGroupingIds($a_item_ids);
331  if ($grouping_ids) {
332  $query = "UPDATE ut_lp_collections" .
333  " SET active = " . $this->db->quote(1, "integer") .
334  " WHERE " . $this->db->in(
335  "grouping_id",
336  $grouping_ids,
337  false,
338  "integer"
339  ) .
340  " AND obj_id = " . $this->db->quote($this->obj_id, "integer");
341  $this->db->manipulate($query);
342  }
343  }
344 
345  public function createNewGrouping(
346  array $a_item_ids,
347  int $a_num_obligatory = 1
348  ): void {
349  $this->activateEntries($a_item_ids);
350 
351  $all_item_ids = array();
352  $grouping_ids = $this->getGroupingIds($a_item_ids);
353  $query = "SELECT item_id FROM ut_lp_collections" .
354  " WHERE obj_id = " . $this->db->quote($this->obj_id, "integer") .
355  " AND " . $this->db->in(
356  "grouping_id",
357  $grouping_ids,
358  false,
359  "integer"
360  );
361  $res = $this->db->query($query);
362  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
363  $all_item_ids[] = $row->item_id;
364  }
365 
366  $all_item_ids = array_unique(array_merge($all_item_ids, $a_item_ids));
367 
368  $this->releaseGrouping($a_item_ids);
369 
370  // Create new grouping
371  $query = "SELECT MAX(grouping_id) grp FROM ut_lp_collections" .
372  " WHERE obj_id = " . $this->db->quote($this->obj_id, "integer") .
373  " GROUP BY obj_id";
374  $res = $this->db->query($query);
375  $row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT);
376  $grp_id = $row->grp;
377  ++$grp_id;
378 
379  $query = "UPDATE ut_lp_collections SET" .
380  " grouping_id = " . $this->db->quote($grp_id, "integer") .
381  ", num_obligatory = " . $this->db->quote(
382  $a_num_obligatory,
383  "integer"
384  ) .
385  ", active = " . $this->db->quote(1, "integer") .
386  " WHERE obj_id = " . $this->db->quote($this->obj_id, "integer") .
387  " AND " . $this->db->in("item_id", $all_item_ids, false, "integer");
388  $this->db->manipulate($query);
389  }
390 
391  public function releaseGrouping(array $a_item_ids): void
392  {
393  $grouping_ids = $this->getGroupingIds($a_item_ids);
394 
395  $query = "UPDATE ut_lp_collections" .
396  " SET grouping_id = " . $this->db->quote(0, "integer") .
397  ", num_obligatory = " . $this->db->quote(0, "integer") .
398  " WHERE obj_id = " . $this->db->quote($this->obj_id, "integer") .
399  " AND " . $this->db->in(
400  "grouping_id",
401  $grouping_ids,
402  false,
403  "integer"
404  );
405  $this->db->manipulate($query);
406  }
407 
408  public function saveObligatoryMaterials(array $a_obl): void
409  {
410  foreach ($a_obl as $grouping_id => $num) {
411  $query = "SELECT count(obj_id) num FROM ut_lp_collections" .
412  " WHERE obj_id = " . $this->db->quote(
413  $this->obj_id,
414  "integer"
415  ) .
416  " AND grouping_id = " . $this->db->quote(
417  $grouping_id,
418  'integer'
419  ) .
420  " GROUP BY obj_id";
421  $res = $this->db->query($query);
422  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
423  if ($num <= 0 || $num >= $row->num) {
424  throw new UnexpectedValueException();
425  }
426  }
427  }
428  foreach ($a_obl as $grouping_id => $num) {
429  $query = "UPDATE ut_lp_collections" .
430  " SET num_obligatory = " . $this->db->quote($num, "integer") .
431  " WHERE obj_id = " . $this->db->quote(
432  $this->obj_id,
433  "integer"
434  ) .
435  " AND grouping_id = " . $this->db->quote(
436  $grouping_id,
437  "integer"
438  );
439  $this->db->manipulate($query);
440  }
441  }
442 
443  public function getTableGUIData(int $a_parent_ref_id): array
444  {
445  $items = $this->getPossibleItems($a_parent_ref_id, true);
446 
447  $data = array();
448  $done = array();
449  foreach ($items as $item_id => $item) {
450  if (in_array($item_id, $done)) {
451  continue;
452  }
453 
454  $table_item = $this->parseTableGUIItem($item_id, $item);
455 
456  // grouping
457  $table_item['grouped'] = array();
458  $grouped_items = $this->getTableGUItemGroup($item_id);
459  if (count((array) ($grouped_items['items'] ?? [])) > 1) {
460  foreach ($grouped_items['items'] as $grouped_item_id) {
461  if ($grouped_item_id == $item_id ||
462  !is_array($items[$grouped_item_id] ?? false)) { // #15498
463  continue;
464  }
465 
466  $table_item['grouped'][] = $this->parseTableGUIItem(
467  $grouped_item_id,
468  $items[$grouped_item_id]
469  );
470  $table_item['num_obligatory'] = $grouped_items['num_obligatory'];
471  $table_item['grouping_id'] = $grouped_items['grouping_id'];
472 
473  $done[] = $grouped_item_id;
474  }
475  }
476  $data[] = $table_item;
477  }
478  return $data;
479  }
480 
481  protected function parseTableGUIItem(int $a_id, array $a_item): array
482  {
483  $table_item = $a_item;
484  $table_item['id'] = $a_id;
485  $table_item['status'] = $this->isAssignedEntry($a_id);
486 
487  $olp = ilObjectLP::getInstance($a_item['obj_id']);
488  $table_item['mode_id'] = $olp->getCurrentMode();
489  $table_item['mode'] = $olp->getModeText($table_item['mode_id']);
490  $table_item['anonymized'] = $olp->isAnonymized();
491 
492  return $table_item;
493  }
494 
495  protected function getTableGUItemGroup(int $item_id): array
496  {
497  $items = array();
498  $query = "SELECT grouping_id FROM ut_lp_collections" .
499  " WHERE obj_id = " . $this->db->quote($this->obj_id, "integer") .
500  " AND item_id = " . $this->db->quote($item_id, "integer");
501  $res = $this->db->query($query);
502  $grouping_id = 0;
503  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
504  $grouping_id = (int) $row->grouping_id;
505  }
506  if ($grouping_id > 0) {
507  $query = "SELECT item_id, num_obligatory FROM ut_lp_collections" .
508  " WHERE obj_id = " . $this->db->quote(
509  $this->obj_id,
510  "integer"
511  ) .
512  " AND grouping_id = " . $this->db->quote(
513  $grouping_id,
514  "integer"
515  );
516  $res = $this->db->query($query);
517  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
518  $items['items'][] = (int) $row->item_id;
519  $items['num_obligatory'] = (int) $row->num_obligatory;
520  $items['grouping_id'] = (int) $grouping_id;
521  }
522  }
523  return $items;
524  }
525 
526  public function getGroupedItemsForLPStatus(): array
527  {
528  $items = $this->getItems();
529  $query = " SELECT * FROM ut_lp_collections" .
530  " WHERE obj_id = " . $this->db->quote($this->obj_id, "integer") .
531  " AND active = " . $this->db->quote(1, "integer");
532  $res = $this->db->query($query);
533 
534  $grouped = array();
535  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
536  if (in_array($row->item_id, $items)) {
537  $grouped[$row->grouping_id]['items'][] = (int) $row->item_id;
538  $grouped[$row->grouping_id]['num_obligatory'] = (int) $row->num_obligatory;
539  }
540  }
541  return $grouped;
542  }
543 }
$res
Definition: ltiservices.php:66
createNewGrouping(array $a_item_ids, int $a_num_obligatory=1)
static _getAllReferences(int $id)
get all reference ids for object ID
isAssignedEntry(int $a_item_id)
static _lookupObjId(int $ref_id)
$ref_id
Definition: ltiauth.php:65
global $DIC
Definition: shib_login.php:26
LP collection base class.
static isTypePluginWithLP(string $a_type, bool $a_active_status=true)
__construct(Container $dic, ilPlugin $plugin)
static _getInstance(int $a_copy_id)
static _lookupType(int $id, bool $reference=false)
static getInstance(int $obj_id)
getPossibleItems(int $a_ref_id, bool $a_full_data=false)