ILIAS  release_8 Revision v8.24
class.ilObjectLP.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
27{
28 protected static ?array $type_defaults = null;
29
30 protected ilTree $tree;
31 protected ilDBInterface $db;
33
34 protected int $obj_id;
35
37 protected ?int $mode = null;
38
39 protected function __construct(int $obj_id)
40 {
41 global $DIC;
42
43 $this->tree = $DIC->repositoryTree();
44 $this->db = $DIC->database();
45 $this->objectDefinition = $DIC['objDefinition'];
46
47 $this->obj_id = $obj_id;
48 }
49
54 public static function getInstance(int $obj_id)
55 {
56 static $instances = array();
57
58 if (!isset($instances[$obj_id])) {
60 $class = self::getTypeClass($type);
61 if ($class) {
62 $instance = new $class($obj_id);
63 } else {
64 // :TODO: should we return anything?
65 $instance = new self($obj_id);
66 }
67 $instances[$obj_id] = $instance;
68 }
69 return $instances[$obj_id];
70 }
71
72 public static function getTypeClass(string $type): string
73 {
74 global $DIC;
75 $objDefinition = $DIC["objDefinition"];
76 if (self::isSupportedObjectType($type)) {
77 switch ($type) {
78 // container
79 case "crs":
80 return "ilCourseLP";
81 case 'crsr':
82 return 'ilCourseReferenceLP';
83 case "grp":
84 return "ilGroupLP";
85 case "fold":
86 return "ilFolderLP";
87 case "lso":
88 return "ilLSLP";
89
90 // learning resources
91 case "lm":
92 return "ilLearningModuleLP";
93 case "htlm":
94 return "ilHTMLLearningModuleLP";
95 case "sahs":
96 return "ilScormLP";
97
98 // misc
99 case "tst":
100 return "ilTestLP";
101 case "exc":
102 return "ilExerciseLP";
103 case 'file':
104 return 'ilFileLP';
105 case "mcst":
106 return "ilMediaCastLP";
107 case "sess":
108 return "ilSessionLP";
109 case "svy":
110 return "ilSurveyLP";
111 case "prg":
112 return "ilStudyProgrammeLP";
113 case "iass":
114 return "ilIndividualAssessmentLP";
115 case "copa":
116 return "ilContentPageLP";
117 case 'cmix':
118 return ilCmiXapiLP::class;
119 case 'lti':
120 return ilLTIConsumerLP::class;
121 case 'frm':
122 return ilForumLP::class;
123 }
124 if ($objDefinition->isPluginTypeName($type)) {
125 return "ilPluginLP";
126 }
127 }
128 return "";
129 }
130
131 public static function getSupportedObjectTypes(): array
132 {
133 global $DIC;
134 $component_repository = $DIC["component.repository"];
135
136 $valid = [
137 "crs",
138 "grp",
139 "fold",
140 "lm",
141 "htlm",
142 "sahs",
143 "tst",
144 "exc",
145 "sess",
146 "svy",
147 "file",
148 "mcst",
149 "prg",
150 "iass",
151 "copa",
152 "lso",
153 'cmix',
154 'lti',
155 'crsr',
156 'frm'
157 ];
158
159 $plugins = $component_repository->getPluginSlotById("robj")->getActivePlugins();
160 foreach ($plugins as $plugin) {
161 $type = $plugin->getId();
163 $valid[] = $type;
164 }
165 }
166
167
168 return $valid;
169 }
170
171 public static function isSupportedObjectType(string $type): bool
172 {
174
175 if (in_array($type, $valid)) {
176 return true;
177 }
178
179 return false;
180 }
181
182 public function resetCaches(): void
183 {
184 $this->mode = null;
185 $this->collection_instance = null;
186 }
187
188 public function isAnonymized(): bool
189 {
190 // see ilLPCollectionOfRepositoryObjects::validateEntry()
191 return false;
192 }
193
194 public function getDefaultMode(): int
195 {
197 }
198
202 public function getValidModes(): array
203 {
204 return [];
205 }
206
207 public function getCurrentMode(): int
208 {
209 if ($this->mode === null) {
210 // using global type default if LP is inactive
213 if ($mode === null) {
214 // fallback: inactive as type default may not be suitable
216 }
217 }
218 // use object LP setting
219 else {
220 $mode = ilLPObjSettings::_lookupDBMode($this->obj_id);
221 if ($mode === null) {
222 // fallback: object type default
223 $mode = $this->getDefaultMode();
224 }
225 }
226 $this->mode = (int) $mode;
227 }
228
229 return $this->mode;
230 }
231
232 public function isActive(): bool
233 {
234 // :TODO: check LP activation?
235
236 $mode = $this->getCurrentMode();
239 return false;
240 }
241 return true;
242 }
243
244 public function getModeText(int $mode): string
245 {
247 }
248
249 public function getModeInfoText(int $mode): string
250 {
252 }
253
254 public function getSettingsInfo(): string
255 {
256 // type-specific
257 return "";
258 }
259
260
262 {
263 if ($this->collection_instance === null) {
264 $this->collection_instance = ilLPCollection::getInstanceByMode($this->obj_id, $this->getCurrentMode());
265 }
267 }
268
269 public function getMembers(bool $search = true): array
270 {
271 if (!$search) {
272 return [];
273 }
274
275 $ref_ids = ilObject::_getAllReferences($this->obj_id);
276 $ref_id = current($ref_ids);
277
278 // walk path to find parent with specific members
279 $path = $this->tree->getPathId($ref_id);
280 array_pop($path);
281 foreach (array_reverse($path) as $path_ref_id) {
282 $olp = self::getInstance(ilObject::_lookupObjId($path_ref_id));
283 $all = $olp->getMembers(false);
284 if (is_array($all)) {
285 return $all;
286 }
287 }
288 return [];
289 }
290
291 final public function resetLPDataForCompleteObject(bool $recursive = true): void
292 {
293 $user_ids = $this->gatherLPUsers();
294 if (sizeof($user_ids)) {
295 $this->resetLPDataForUserIds(array_unique($user_ids), $recursive);
296 }
297 }
298
299 final public function resetLPDataForUserIds(array $user_ids, bool $recursive = true): void
300 {
301 if ($recursive && method_exists($this, "getPossibleCollectionItems")) { // #15203
302 $subitems = $this->getPossibleCollectionItems();
303 if (is_array($subitems)) {
304 foreach ($subitems as $sub_ref_id) {
305 $olp = self::getInstance(ilObject::_lookupObjId($sub_ref_id));
306 $olp->resetLPDataForUserIds($user_ids, false);
307 }
308 }
309 }
310
311 $this->resetCustomLPDataForUserIds($user_ids, $recursive);
312
313 ilLPMarks::_deleteForUsers($this->obj_id, $user_ids);
314
315 ilChangeEvent::_deleteReadEventsForUsers($this->obj_id, $user_ids);
316
317 // update LP status to get collections up-to-date
318 foreach ($user_ids as $user_id) {
319 ilLPStatusWrapper::_updateStatus($this->obj_id, $user_id);
320 }
321 }
322
323 protected function resetCustomLPDataForUserIds(array $user_ids, bool $recursive = true): void
324 {
325 // this should delete all data that is relevant for the supported LP modes
326 }
327
328 protected function gatherLPUsers(): array
329 {
330 $user_ids = ilLPMarks::_getAllUserIds($this->obj_id);
331 return array_merge($user_ids, ilChangeEvent::_getAllUserIds($this->obj_id));
332 }
333
334 final public static function handleMove(int $source_ref_id): void
335 {
336 global $DIC;
337
338 $tree = $DIC->repositoryTree();
339 $ilDB = $DIC->database();
340
341 $ref_ids = $tree->getSubTreeIds($source_ref_id);
342 $ref_ids[] = $source_ref_id;
343
344 // get "parent" path to source node (not including source node)
345 $new_path = $tree->getPathId($source_ref_id);
346 array_pop($new_path);
347 $new_path = implode("/", $new_path);
348
349 // find collections with ref_ids
350 $sql =
351 "SELECT DISTINCT(ut_lp_collections.obj_id) obj_id" . PHP_EOL
352 . "FROM object_reference" . PHP_EOL
353 . "JOIN ut_lp_collections ON" . PHP_EOL
354 . "(" . $ilDB->in("object_reference.ref_id", $ref_ids, false, "integer") . PHP_EOL
355 . "AND object_reference.ref_id = ut_lp_collections.item_id)" . PHP_EOL
356 ;
357 $result = $ilDB->query($sql);
358 while ($row = $ilDB->fetchAssoc($result)) {
359 if (in_array(ilObject::_lookupType((int) $row["obj_id"]), ["crs", "grp", "fold"])) {
360 $coll_ref_id = ilObject::_getAllReferences((int) $row["obj_id"]);
361 $coll_ref_id = array_pop($coll_ref_id);
362
363 // #13402
364 if ($coll_ref_id == $source_ref_id) {
365 continue;
366 }
367
368 // #17703 - collection has also been moved - nothing todo
369 if ($tree->isGrandChild($source_ref_id, $coll_ref_id)) {
370 continue;
371 }
372
373 // get path to collection (including collection "parent")
374 $coll_path = $tree->getPathId($coll_ref_id);
375 $coll_path = implode("/", $coll_path);
376
377 // collection path is not inside new path
378 if (!stristr($new_path, $coll_path)) {
379 // delete all items of moved (sub-)tree
380 $sql =
381 "DELETE FROM ut_lp_collections" . PHP_EOL
382 . "WHERE obj_id = " . $ilDB->quote($row["obj_id"], "integer") . PHP_EOL
383 . "AND " . $ilDB->in("item_id", $ref_ids, false, "integer") . PHP_EOL
384 ;
385 $ilDB->manipulate($sql);
386
387 ilLPStatusWrapper::_refreshStatus((int) $row["obj_id"]);
388 }
389 }
390 }
391 }
392
393 final public function handleToTrash(): void
394 {
396 }
397
398 final public function handleDelete(): void
399 {
400 ilLPMarks::deleteObject($this->obj_id);
401
402 ilChangeEvent::_delete($this->obj_id);
403
404 $collection = $this->getCollectionInstance();
405 if ($collection) {
406 $collection->delete();
407 }
408
410 }
411
412 final protected function updateParentCollections(): void
413 {
414 // update parent collections?
415 $sql =
416 "SELECT ut_lp_collections.obj_id obj_id" . PHP_EOL
417 . "FROM object_reference" . PHP_EOL
418 . "JOIN ut_lp_collections ON" . PHP_EOL
419 . "(object_reference.obj_id = " . $this->db->quote($this->obj_id, "integer") . PHP_EOL
420 . "AND object_reference.ref_id = ut_lp_collections.item_id)" . PHP_EOL
421 ;
422 $result = $this->db->query($sql);
423 while ($row = $this->db->fetchAssoc($result)) {
424 if (in_array(ilObject::_lookupType((int) $row["obj_id"]), array("crs", "grp", "fold"))) {
425 // remove from parent collection
426 $sql =
427 "DELETE FROM ut_lp_collections" . PHP_EOL
428 . "WHERE obj_id = " . $this->db->quote($row["obj_id"], "integer") . PHP_EOL
429 . "AND item_id = " . $this->db->quote($this->obj_id, "integer") . PHP_EOL
430 ;
431 $this->db->manipulate($sql);
432
433 ilLPStatusWrapper::_refreshStatus((int) $row["obj_id"]);
434 }
435 }
436 }
437
441 protected static function isLPMember(array &$res, int $usr_id, array $obj_ids): bool
442 {
443 // should be overwritten by object-type-specific class
444 return false;
445 }
446
450 protected static function findMembershipsByPath(
451 array &$res,
452 int $usr_id,
453 int $parent_ref_id,
454 array $obj_ids,
455 bool $mapped_ref_ids = false
456 ): array {
457 global $DIC;
458
459 $tree = $DIC->repositoryTree();
460
461 $found = array();
462
463 // walk path to find course or group object and check members of that object
464 $path = $tree->getPathId($parent_ref_id);
465 foreach (array_reverse($path) as $path_ref_id) {
466 $type = ilObject::_lookupType($path_ref_id, true);
467 if ($type == "crs" || $type == "grp") {
468 $class = self::getTypeClass($type);
469 $path_ob_id = ilObject::_lookupObjId($path_ref_id);
470 $chk = array();
471 $class::isLPMember($chk, $usr_id, array($path_ob_id));
472 if (!$mapped_ref_ids) {
473 // we found a grp/crs in path of (single) parent - mark all objects
474 foreach ($obj_ids as $obj_id) {
475 $found[] = $obj_id;
476 if ($chk[$path_ob_id] ?? false) {
477 $res[$obj_id] = true;
478 }
479 }
480 } else {
481 // all children from current node are "lp-valid"
482 foreach ($obj_ids as $obj_id => $ref_ids) {
483 foreach ($ref_ids as $ref_id) {
484 if ($tree->isGrandChild($path_ref_id, $ref_id)) {
485 $found[$obj_id][] = $ref_id;
486 if ($chk[$path_ob_id] ?? false) {
487 $res[$obj_id] = true;
488 }
489 break;
490 }
491 }
492 }
493 }
494 break;
495 }
496 }
497
498 return $found;
499 }
500
504 public static function getLPMemberships(
505 int $usr_id,
506 array $obj_ids,
507 ?int $parent_ref_id = null,
508 bool $mapped_ref_ids = false
509 ): array {
510 global $DIC;
511
512 $ilDB = $DIC->database();
513 $tree = $DIC->repositoryTree();
514
515 // see ilTrQuery::getParticipantsForObject() [single object only]
516 // this is optimized for larger number of objects, e.g. list GUIs
517
518 $ref_map = [];
519 if ($mapped_ref_ids) {
520 $ref_map = $obj_ids;
521 $obj_ids = array_keys($obj_ids);
522 }
523
524 $res = [];
525
526 // get object types
527 $types_map = [];
528 $sql =
529 "SELECT obj_id, type" . PHP_EOL
530 . "FROM object_data" . PHP_EOL
531 . "WHERE " . $ilDB->in("obj_id", $obj_ids, false, "integer") . PHP_EOL
532 ;
533 $result = $ilDB->query($sql);
534 while ($row = $ilDB->fetchAssoc($result)) {
535 $types_map[$row["type"]][] = (int) $row["obj_id"];
536 $res[(int) $row["obj_id"]] = false;
537 }
538
539 $find_by_parent = [];
540 foreach ($types_map as $type => $type_obj_ids) {
541 $class = self::getTypeClass($type);
542 if ($class) {
543 // lp-supported type?
544 if (!$class::isLPMember($res, $usr_id, $type_obj_ids)) {
545 $find_by_parent = array_merge($find_by_parent, $type_obj_ids);
546 }
547 }
548 }
549
550 if (sizeof($find_by_parent)) {
551 // single parent for all objects (repository/ilObjectListGUI)
552 if ($parent_ref_id) {
553 if (self::findMembershipsByPath($res, $usr_id, $parent_ref_id, $find_by_parent)) {
554 // we found a crs/grp in path, so no need to check read_events
555 $find_by_parent = null;
556 }
557 }
558 // different parents (PD > LP)
559 elseif (is_array($ref_map) && count($ref_map) > 0) {
560 foreach ($find_by_parent as $obj_id) {
561 // maybe already found by path search from other object/reference
562 if ($res[$obj_id] === false) {
563 if (isset($ref_map[$obj_id]) && is_array($ref_map[$obj_id])) {
564 // check all references
565 foreach ($ref_map[$obj_id] as $ref_id) {
566 $parent_ref_id = $tree->getParentId($ref_id);
567 if ($parent_ref_id == ROOT_FOLDER_ID) {
568 continue;
569 }
570
571 // we are checking the complete ref_map
572 // to find all relevant objects in subtree of current ref_id
573 $found = self::findMembershipsByPath($res, $usr_id, $parent_ref_id, $ref_map, true);
574 if (is_array($found) && count($found) > 0) {
575 // if any references were found in a crs/grp-subtree
576 // remove from "read-event"-last-resort-pool
577 foreach ($found as $found_obj_id => $found_ref_ids) {
578 $diff = array_diff($ref_map[$found_obj_id], $found_ref_ids);
579 if ($diff) {
580 // 1-n refs are in another subtree
581 // have to be checked separately
582 $ref_map[$found_obj_id] = $diff;
583 } else {
584 // all references found in subtree
585 // no need to check again
586 unset($ref_map[$found_obj_id]);
587 }
588 }
589 break;
590 }
591 }
592 }
593 }
594 }
595
596 $find_by_parent = array_keys($ref_map);
597 }
598
599 // last resort: use read_event?
600 if (is_array($find_by_parent) && count($find_by_parent) > 0) {
601 $sql =
602 "SELECT obj_id" . PHP_EOL
603 . "FROM read_event" . PHP_EOL
604 . "WHERE " . $ilDB->in("obj_id", $find_by_parent, false, "integer") . PHP_EOL
605 . "AND usr_id = " . $ilDB->quote($usr_id, "integer") . PHP_EOL
606 ;
607 $result = $ilDB->query($sql);
608 while ($row = $ilDB->fetchAssoc($result)) {
609 $res[(int) $row["obj_id"]] = true;
610 }
611 }
612 }
613
614 return $res;
615 }
616
617 public function getMailTemplateId(): string
618 {
619 return '';
620 }
621
622
623 //
624 // type-specific support of features (should be enhanced)
625 //
626
627 public static function supportsSpentSeconds(string $obj_type): bool
628 {
629 return !in_array($obj_type, ["exc", "file", "mcst", "mob", "htlm", "copa", 'cmix', 'lti', 'frm']);
630 }
631
632 public static function supportsMark(string $obj_type): bool
633 {
634 return !in_array($obj_type, ["lm", "dbk"]);
635 }
636
637 public static function supportsMatrixView(string $obj_type): bool
638 {
639 $types = ['svy', 'tst', 'htlm', 'exc', 'sess', 'file', 'frm', 'prg', 'copa', 'cmix', 'lti','crsr'];
640 return !in_array($obj_type, $types);
641 }
642
647 public static function getDefaultModes(bool $lp_active): array
648 {
650 }
651
652 protected static function getTypeDefaultFromDB(string $type): ?int
653 {
654 global $DIC;
655 $ilDB = $DIC->database();
656
657 if (is_null(self::$type_defaults)) {
658 self::$type_defaults = [];
659 $result = $ilDB->query("SELECT type_id, lp_mode FROM ut_lp_defaults");
660 while ($row = $ilDB->fetchAssoc($result)) {
661 self::$type_defaults[(string) $row["type_id"]] = (int) $row["lp_mode"];
662 }
663 }
664 return self::$type_defaults[$type] ?? null;
665 }
666
667 public static function saveTypeDefaults(array $data): void
668 {
669 global $DIC;
670 $ilDB = $DIC->database();
671
672 $ilDB->manipulate("DELETE FROM ut_lp_defaults");
673 foreach ($data as $type => $mode) {
674 $ilDB->insert("ut_lp_defaults", [
675 "type_id" => ["text", $type],
676 "lp_mode" => ["integer", $mode]
677 ]);
678 }
679 }
680
681 public static function getTypeDefault(string $type): int
682 {
683 $db = self::getTypeDefaultFromDB($type);
684 if ($db !== null) {
685 return $db;
686 }
687
688 $class = self::getTypeClass($type);
689 $olp = new $class(0);
690 return $olp->getDefaultMode();
691 }
692
693 public function hasIndividualModeOptions(): bool
694 {
695 return false;
696 }
697
698 public function initInvidualModeOptions(ilRadioGroupInputGUI $modeRadio): void
699 {
700 }
701
703 {
704 return false;
705 }
706
708 {
709 return 0;
710 }
711
712 public function appendModeConfiguration(int $mode, ilRadioOption $modeElement): void
713 {
714 }
715
716 public function saveModeConfiguration(ilPropertyFormGUI $form, bool &$modeChanged): void
717 {
718 }
719}
static _deleteReadEventsForUsers(int $a_obj_id, array $a_user_ids)
static _delete(int $a_obj_id)
Delete object entries.
static _getAllUserIds(int $a_obj_id)
LP collection base class.
static getInstanceByMode(int $a_obj_id, int $a_mode)
static deleteObject(int $a_obj_id)
static _getAllUserIds(int $a_obj_id)
static _deleteForUsers(int $a_obj_id, array $a_user_ids)
static _lookupDBMode(int $a_obj_id)
static _mode2InfoText(int $a_mode)
static _mode2Text(int $a_mode)
static _refreshStatus(int $a_obj_id, ?array $a_users=null)
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
parses the objects.xml it handles the xml-description of all ilias objects
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static supportsSpentSeconds(string $obj_type)
static getDefaultModes(bool $lp_active)
Get available type-specific default modes (no administration needed)
static saveTypeDefaults(array $data)
static supportsMark(string $obj_type)
getMembers(bool $search=true)
appendModeConfiguration(int $mode, ilRadioOption $modeElement)
resetCustomLPDataForUserIds(array $user_ids, bool $recursive=true)
static array $type_defaults
getModeText(int $mode)
ilDBInterface $db
__construct(int $obj_id)
static getTypeDefaultFromDB(string $type)
saveModeConfiguration(ilPropertyFormGUI $form, bool &$modeChanged)
static supportsMatrixView(string $obj_type)
static getLPMemberships(int $usr_id, array $obj_ids, ?int $parent_ref_id=null, bool $mapped_ref_ids=false)
Get all objects where given user is member (from LP POV)
static getSupportedObjectTypes()
getModeInfoText(int $mode)
shouldFetchIndividualModeFromFormSubmission()
fetchIndividualModeFromFormSubmission(ilPropertyFormGUI $form)
static getTypeDefault(string $type)
resetLPDataForUserIds(array $user_ids, bool $recursive=true)
initInvidualModeOptions(ilRadioGroupInputGUI $modeRadio)
static isSupportedObjectType(string $type)
static handleMove(int $source_ref_id)
static findMembershipsByPath(array &$res, int $usr_id, int $parent_ref_id, array $obj_ids, bool $mapped_ref_ids=false)
Find (lp-relevant) memberships by path.
ilLPCollection $collection_instance
static isLPMember(array &$res, int $usr_id, array $obj_ids)
Find (lp-relevant) members for given object ids.
ilObjectDefinition $objectDefinition
resetLPDataForCompleteObject(bool $recursive=true)
static getTypeClass(string $type)
static getInstance(int $obj_id)
static _lookupType(int $id, bool $reference=false)
static _getAllReferences(int $id)
get all reference ids for object ID
static _lookupObjId(int $ref_id)
This class represents a property form user interface.
This class represents a property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static isTypePluginWithLP(string $a_type, bool $a_active_status=true)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
isGrandChild(int $a_startnode_id, int $a_querynode_id)
checks if a node is in the path of an other node
getSubTreeIds(int $a_ref_id)
Get all ids of subnodes.
getPathId(int $a_endnode_id, int $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
getParentId(int $a_node_id)
get parent id of given node
const ROOT_FOLDER_ID
Definition: constants.php:32
$valid
global $DIC
Definition: feed.php:28
Interface ilDBInterface.
$ref_id
Definition: ltiauth.php:67
$path
Definition: ltiservices.php:32
$res
Definition: ltiservices.php:69
$type