ILIAS  release_7 Revision v7.30-3-g800a261c036
class.ilObjectLP.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
4
5include_once "Services/Tracking/classes/class.ilLPObjSettings.php";
6
15{
19 protected $tree;
20
24 protected $db;
25
26 protected $obj_id; // [int]
27 protected $collection_instance; // [ilLPCollection]
28 protected $mode; // [int]
29
30 protected static $type_defaults; // [array]
31
32 protected function __construct($a_obj_id)
33 {
34 global $DIC;
35
36 $this->tree = $DIC->repositoryTree();
37 $this->db = $DIC->database();
38 $this->obj_id = (int) $a_obj_id;
39 }
40
45 public static function getInstance($a_obj_id)
46 {
47 static $instances = array();
48
49 if (!isset($instances[$a_obj_id])) {
50 $type = ilObject::_lookupType($a_obj_id);
51 $class = self::getTypeClass($type);
52 if ($class) {
53 $instance = new $class($a_obj_id);
54 } else {
55 // :TODO: should we return anything?
56 $instance = new self($a_obj_id);
57 }
58 $instances[$a_obj_id] = $instance;
59 }
60
61 return $instances[$a_obj_id];
62 }
63
64 public static function getTypeClass($a_type)
65 {
66 global $DIC;
67
68 $objDefinition = $DIC["objDefinition"];
69
70 if (self::isSupportedObjectType($a_type)) {
71 switch ($a_type) {
72 // container
73
74 case "crs":
75 include_once "Modules/Course/classes/class.ilCourseLP.php";
76 return "ilCourseLP";
77
78 case 'crsr':
79 return 'ilCourseReferenceLP';
80
81 case "grp":
82 include_once "Modules/Group/classes/class.ilGroupLP.php";
83 return "ilGroupLP";
84
85 case "fold":
86 include_once "Modules/Folder/classes/class.ilFolderLP.php";
87 return "ilFolderLP";
88
89 case "lso":
90 include_once "Modules/LearningSequence/classes/LearnerProgress/class.ilLSLP.php";
91 return "ilLSLP";
92
93
94 // learning resources
95
96 case "lm":
97 include_once "Modules/LearningModule/classes/class.ilLearningModuleLP.php";
98 return "ilLearningModuleLP";
99
100 case "htlm":
101 include_once "Modules/HTMLLearningModule/classes/class.ilHTMLLearningModuleLP.php";
102 return "ilHTMLLearningModuleLP";
103
104 case "sahs":
105 include_once "Modules/ScormAicc/classes/class.ilScormLP.php";
106 return "ilScormLP";
107
108
109 // misc
110
111 case "tst":
112 include_once "Modules/Test/classes/class.ilTestLP.php";
113 return "ilTestLP";
114
115 case "exc":
116 include_once "Modules/Exercise/classes/class.ilExerciseLP.php";
117 return "ilExerciseLP";
118
119 case 'file':
120 require_once 'Modules/File/classes/class.ilFileLP.php';
121 return 'ilFileLP';
122
123 case "mcst":
124 require_once "Modules/MediaCast/classes/class.ilMediaCastLP.php";
125 return "ilMediaCastLP";
126
127 case "sess":
128 include_once "Modules/Session/classes/class.ilSessionLP.php";
129 return "ilSessionLP";
130
131 case "svy":
132 return "ilSurveyLP";
133
134 case "prg":
135 include_once "Modules/StudyProgramme/classes/class.ilStudyProgrammeLP.php";
136 return "ilStudyProgrammeLP";
137
138 case "iass":
139 include_once "Modules/IndividualAssessment/classes/class.ilIndividualAssessmentLP.php";
140 return "ilIndividualAssessmentLP";
141
142 case "copa":
143 return "ilContentPageLP";
144
145 case 'cmix':
146 return ilCmiXapiLP::class;
147
148 case 'lti':
149 return ilLTIConsumerLP::class;
150
151 // plugin
152 case $objDefinition->isPluginTypeName($a_type):
153 include_once "Services/Component/classes/class.ilPluginLP.php";
154 return "ilPluginLP";
155 }
156 }
157 }
158
159 public static function getSupportedObjectTypes() : array
160 {
161 global $DIC;
162 $ilPluginAdmin = $DIC['ilPluginAdmin'];
163
164 $valid = [
165 "crs",
166 "grp",
167 "fold",
168 "lm",
169 "htlm",
170 "sahs",
171 "tst",
172 "exc",
173 "sess",
174 "svy",
175 "file",
176 "mcst",
177 "prg",
178 "iass",
179 "copa",
180 "lso",
181 'cmix',
182 'lti',
183 'crsr'
184 ];
185
186 $plugins = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_SERVICE, "Repository", "robj");
187 foreach ($plugins as $plugin) {
188 $type = $ilPluginAdmin->getId(IL_COMP_SERVICE, "Repository", "robj", $plugin);
190 $valid[] = $type;
191 }
192 }
193
194
195 return $valid;
196 }
197
198 public static function isSupportedObjectType($type) : bool
199 {
201
202 if (in_array((string) $type, $valid)) {
203 return true;
204 }
205
206 return false;
207 }
208
209 public function resetCaches()
210 {
211 $this->mode = null;
212 $this->collection_instance = null;
213 }
214
215 public function isAnonymized()
216 {
217 // see ilLPCollectionOfRepositoryObjects::validateEntry()
218 return false;
219 }
220
221
222 //
223 // MODE
224 //
225
226 public function getDefaultMode()
227 {
229 }
230
231 public function getValidModes()
232 {
233 return array();
234 }
235
236 public function getCurrentMode()
237 {
238 if ($this->mode === null) {
239 // using global type default if LP is inactive
240 include_once "Services/Tracking/classes/class.ilObjUserTracking.php";
243 if ($mode === null) {
244 // fallback: inactive as type default may not be suitable
246 }
247 }
248 // use object LP setting
249 else {
250 $mode = ilLPObjSettings::_lookupDBMode($this->obj_id);
251 if ($mode === null) {
252 // fallback: object type default
253 $mode = $this->getDefaultMode();
254 }
255 }
256 $this->mode = (int) $mode;
257 }
258
259 return $this->mode;
260 }
261
262 public function isActive()
263 {
264 // :TODO: check LP activation?
265
266 $mode = $this->getCurrentMode();
269 return false;
270 }
271 return true;
272 }
273
274 public function getModeText($a_mode)
275 {
276 return ilLPObjSettings::_mode2Text($a_mode);
277 }
278
279 public function getModeInfoText($a_mode)
280 {
281 return ilLPObjSettings::_mode2InfoText($a_mode);
282 }
283
284 public function getSettingsInfo()
285 {
286 // type-specific
287 }
288
289
290 //
291 // COLLECTION
292 //
293
294 public function getCollectionInstance()
295 {
296 if ($this->collection_instance === null) {
297 include_once "Services/Tracking/classes/collection/class.ilLPCollection.php";
298 $this->collection_instance = ilLPCollection::getInstanceByMode($this->obj_id, $this->getCurrentMode());
299 }
300
302 }
303
304
305 //
306 // MEMBERS
307 //
308
309 public function getMembers($a_search = true)
310 {
312
313 if (!$a_search) {
314 return;
315 }
316
317 $ref_ids = ilObject::_getAllReferences($this->obj_id);
318 $ref_id = current($ref_ids);
319
320 // walk path to find parent with specific members
321 $path = $tree->getPathId($ref_id);
322 array_pop($path);
323 foreach (array_reverse($path) as $path_ref_id) {
324 $olp = self::getInstance(ilObject::_lookupObjId($path_ref_id));
325 $all = $olp->getMembers(false);
326 if (is_array($all)) {
327 return $all;
328 }
329 }
330 }
331
332
333 //
334 // RESET
335 //
336
337 final public function resetLPDataForCompleteObject($a_recursive = true)
338 {
339 $user_ids = $this->gatherLPUsers();
340 if (sizeof($user_ids)) {
341 $this->resetLPDataForUserIds(array_unique($user_ids), $a_recursive);
342 }
343 }
344
345 final public function resetLPDataForUserIds(array $a_user_ids, $a_recursive = true)
346 {
347 if ((bool) $a_recursive &&
348 method_exists($this, "getPossibleCollectionItems")) { // #15203
349 $subitems = $this->getPossibleCollectionItems();
350 if (is_array($subitems)) {
351 foreach ($subitems as $sub_ref_id) {
352 $olp = self::getInstance(ilObject::_lookupObjId($sub_ref_id));
353 $olp->resetLPDataForUserIds($a_user_ids, false);
354 }
355 }
356 }
357
358 $this->resetCustomLPDataForUserIds($a_user_ids, (bool) $a_recursive);
359
360 include_once "Services/Tracking/classes/class.ilLPMarks.php";
361 ilLPMarks::_deleteForUsers($this->obj_id, $a_user_ids);
362
363 include_once "Services/Tracking/classes/class.ilChangeEvent.php";
364 ilChangeEvent::_deleteReadEventsForUsers($this->obj_id, $a_user_ids);
365
366 // update LP status to get collections up-to-date
367 include_once "Services/Tracking/classes/class.ilLPStatusWrapper.php";
368 foreach ($a_user_ids as $user_id) {
369 ilLPStatusWrapper::_updateStatus($this->obj_id, $user_id);
370 }
371 }
372
373 protected function resetCustomLPDataForUserIds(array $a_user_ids, $a_recursive = true)
374 {
375 // this should delete all data that is relevant for the supported LP modes
376 }
377
378 protected function gatherLPUsers()
379 {
380 include_once "Services/Tracking/classes/class.ilLPMarks.php";
381 $user_ids = ilLPMarks::_getAllUserIds($this->obj_id);
382
383 include_once "Services/Tracking/classes/class.ilChangeEvent.php";
384 $user_ids = array_merge($user_ids, ilChangeEvent::_getAllUserIds($this->obj_id));
385
386 return $user_ids;
387 }
388
389
390 //
391 // EVENTS
392 //
393
394 final public static function handleMove($a_source_ref_id)
395 {
396 global $DIC;
397
398 $tree = $DIC->repositoryTree();
399 $ilDB = $DIC->database();
400
401 $ref_ids = $tree->getSubTreeIds($a_source_ref_id);
402 $ref_ids[] = $a_source_ref_id;
403
404 // get "parent" path to source node (not including source node)
405 $new_path = $tree->getPathId($a_source_ref_id);
406 array_pop($new_path);
407 $new_path = implode("/", $new_path);
408
409 include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
410
411 // find collections with ref_ids
412 $set = $ilDB->query("SELECT DISTINCT(ut_lp_collections.obj_id) obj_id" .
413 " FROM object_reference" .
414 " JOIN ut_lp_collections ON" .
415 " (" . $ilDB->in("object_reference.ref_id", $ref_ids, "", "integer") .
416 " AND object_reference.ref_id = ut_lp_collections.item_id)");
417 while ($rec = $ilDB->fetchAssoc($set)) {
418 if (in_array(ilObject::_lookupType($rec["obj_id"]), array("crs", "grp", "fold"))) {
419 $coll_ref_id = ilObject::_getAllReferences($rec["obj_id"]);
420 $coll_ref_id = array_pop($coll_ref_id);
421
422 // #13402
423 if ($coll_ref_id == $a_source_ref_id) {
424 continue;
425 }
426
427 // #17703 - collection has also been moved - nothing todo
428 if ($tree->isGrandChild($a_source_ref_id, $coll_ref_id)) {
429 continue;
430 }
431
432 // get path to collection (including collection "parent")
433 $coll_path = $tree->getPathId($coll_ref_id);
434 $coll_path = implode("/", $coll_path);
435
436 // collection path is not inside new path
437 if (!stristr($new_path, $coll_path)) {
438 // delete all items of moved (sub-)tree
439 $query = "DELETE FROM ut_lp_collections" .
440 " WHERE obj_id = " . $ilDB->quote($rec["obj_id"], "integer") .
441 " AND " . $ilDB->in("item_id", $ref_ids, "", "integer");
442 $ilDB->manipulate($query);
443
444 ilLPStatusWrapper::_refreshStatus($rec["obj_id"]);
445 }
446 }
447 }
448 }
449
450 final public function handleToTrash()
451 {
453 }
454
455 final public function handleDelete()
456 {
457 include_once "Services/Tracking/classes/class.ilLPMarks.php";
458 ilLPMarks::deleteObject($this->obj_id);
459
460 include_once "Services/Tracking/classes/class.ilChangeEvent.php";
461 ilChangeEvent::_delete($this->obj_id);
462
463 $collection = $this->getCollectionInstance();
464 if ($collection) {
465 $collection->delete();
466 }
467
469 }
470
471 final protected function updateParentCollections()
472 {
474
475 include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
476
477 // update parent collections?
478 $set = $ilDB->query("SELECT ut_lp_collections.obj_id obj_id FROM " .
479 "object_reference JOIN ut_lp_collections ON " .
480 "(object_reference.obj_id = " . $ilDB->quote($this->obj_id, "integer") .
481 " AND object_reference.ref_id = ut_lp_collections.item_id)");
482 while ($rec = $ilDB->fetchAssoc($set)) {
483 if (in_array(ilObject::_lookupType($rec["obj_id"]), array("crs", "grp", "fold"))) {
484 // remove from parent collection
485 $query = "DELETE FROM ut_lp_collections" .
486 " WHERE obj_id = " . $ilDB->quote($rec["obj_id"], "integer") .
487 " AND item_id = " . $ilDB->quote($this->obj_id, "integer");
488 $ilDB->manipulate($query);
489
490 ilLPStatusWrapper::_refreshStatus($rec["obj_id"]);
491 }
492 }
493 }
494
495
496 //
497 // LP-relevant memberships
498 //
499
507 protected static function isLPMember(array &$a_res, $a_usr_id, $a_obj_ids)
508 {
509 // should be overwritten by object-type-specific class
510 return false;
511 }
512
523 protected static function findMembershipsByPath(array &$a_res, $a_usr_id, $a_parent_ref_id, array $a_obj_ids, $a_mapped_ref_ids = false)
524 {
525 global $DIC;
526
527 $tree = $DIC->repositoryTree();
528
529 $found = array();
530
531 // walk path to find course or group object and check members of that object
532 $path = $tree->getPathId($a_parent_ref_id);
533 foreach (array_reverse($path) as $path_ref_id) {
534 $type = ilObject::_lookupType($path_ref_id, true);
535 if ($type == "crs" ||
536 $type == "grp") {
537 $class = self::getTypeClass($type);
538 $path_ob_id = ilObject::_lookupObjId($path_ref_id);
539 $chk = array();
540 $class::isLPMember($chk, $a_usr_id, array($path_ob_id));
541 if (!$a_mapped_ref_ids) {
542 // we found a grp/crs in path of (single) parent - mark all objects
543 foreach ($a_obj_ids as $obj_id) {
544 $found[] = $obj_id;
545 if ($chk[$path_ob_id]) {
546 $a_res[$obj_id] = true;
547 }
548 }
549 } else {
550 // all children from current node are "lp-valid"
551 foreach ($a_obj_ids as $obj_id => $ref_ids) {
552 foreach ($ref_ids as $ref_id) {
553 if ($tree->isGrandChild($path_ref_id, $ref_id)) {
554 $found[$obj_id][] = $ref_id;
555 if ($chk[$path_ob_id]) {
556 $a_res[$obj_id] = true;
557 }
558 break;
559 }
560 }
561 }
562 }
563 break;
564 }
565 }
566
567 return $found;
568 }
569
579 public static function getLPMemberships($a_usr_id, array $a_obj_ids, $a_parent_ref_id = null, $a_mapped_ref_ids = false)
580 {
581 global $DIC;
582
583 $ilDB = $DIC->database();
584 $tree = $DIC->repositoryTree();
585
586 // see ilTrQuery::getParticipantsForObject() [single object only]
587 // this is optimized for larger number of objects, e.g. list GUIs
588
589 $ref_map = [];
590 if ((bool) $a_mapped_ref_ids) {
591 $ref_map = $a_obj_ids;
592 $a_obj_ids = array_keys($a_obj_ids);
593 }
594
595 $res = array();
596
597 // get object types
598 $types_map = array();
599 $query = " SELECT obj_id, type" .
600 " FROM object_data" .
601 " WHERE " . $ilDB->in("obj_id", $a_obj_ids, "", "integer");
602 $set = $ilDB->query($query);
603 while ($row = $ilDB->fetchAssoc($set)) {
604 $types_map[$row["type"]][] = $row["obj_id"];
605 $res[$row["obj_id"]] = false;
606 }
607
608 $find_by_parent = array();
609 foreach ($types_map as $type => $type_obj_ids) {
610 $class = self::getTypeClass($type);
611 if ($class) {
612 // lp-supported type?
613 if (!$class::isLPMember($res, $a_usr_id, $type_obj_ids)) {
614 $find_by_parent = array_merge($find_by_parent, $type_obj_ids);
615 }
616 }
617 }
618
619 if (sizeof($find_by_parent)) {
620 // single parent for all objects (repository/ilObjectListGUI)
621 if ($a_parent_ref_id) {
622 if (self::findMembershipsByPath($res, $a_usr_id, $a_parent_ref_id, $find_by_parent)) {
623 // we found a crs/grp in path, so no need to check read_events
624 $find_by_parent = null;
625 }
626 }
627 // different parents (PD > LP)
628 elseif (is_array($ref_map) && count($ref_map) > 0) {
629 foreach ($find_by_parent as $obj_id) {
630 // maybe already found by path search from other object/reference
631 if ($res[$obj_id] === false) {
632 if (isset($ref_map[$obj_id]) && is_array($ref_map[$obj_id])) {
633 // check all references
634 foreach ($ref_map[$obj_id] as $ref_id) {
635 $parent_ref_id = $tree->getParentId($ref_id);
636 if ($parent_ref_id == ROOT_FOLDER_ID) {
637 continue;
638 }
639
640 // we are checking the complete ref_map
641 // to find all relevant objects in subtree of current ref_id
642 $found = self::findMembershipsByPath($res, $a_usr_id, $parent_ref_id, $ref_map, true);
643 if (is_array($found) && count($found) > 0) {
644 // if any references were found in a crs/grp-subtree
645 // remove from "read-event"-last-resort-pool
646 foreach ($found as $found_obj_id => $found_ref_ids) {
647 $diff = array_diff($ref_map[$found_obj_id], $found_ref_ids);
648 if ($diff) {
649 // 1-n refs are in another subtree
650 // have to be checked separately
651 $ref_map[$found_obj_id] = $diff;
652 } else {
653 // all references found in subtree
654 // no need to check again
655 unset($ref_map[$found_obj_id]);
656 }
657 }
658 break;
659 }
660 }
661 }
662 }
663 }
664
665 $find_by_parent = array_keys($ref_map);
666 }
667
668 // last resort: use read_event?
669 if (is_array($find_by_parent) && count($find_by_parent) > 0) {
670 $set = $ilDB->query("SELECT obj_id" .
671 " FROM read_event" .
672 " WHERE " . $ilDB->in("obj_id", $find_by_parent, "", "integer") .
673 " AND usr_id = " . $ilDB->quote($a_usr_id, "integer"));
674 while ($row = $ilDB->fetchAssoc($set)) {
675 $res[$row["obj_id"]] = true;
676 }
677 }
678 }
679
680 return $res;
681 }
682
683 public function getMailTemplateId()
684 {
685 // type-specific
686 }
687
688
689 //
690 // type-specific support of features (should be enhanced)
691 //
692
693 public static function supportsSpentSeconds($a_obj_type)
694 {
695 return !in_array($a_obj_type, array("exc", "file", "mcst", "mob", "htlm", "copa", 'cmix', 'lti'));
696 }
697
698 public static function supportsMark($a_obj_type)
699 {
700 return !in_array($a_obj_type, array("lm", "dbk"));
701 }
702
703 public static function supportsMatrixView($a_obj_type)
704 {
705 return !in_array($a_obj_type, array('svy', 'tst', 'htlm', 'exc', 'sess', 'file', 'prg', 'copa', 'cmix', 'lti','crsr'));
706 }
707
708
709 // type-wide default
710
716 public static function getDefaultModes($a_lp_active)
717 {
719 }
720
721 protected static function getTypeDefaultFromDB($a_type)
722 {
723 global $DIC;
724
725 $ilDB = $DIC->database();
726
727 if (!is_array(self::$type_defaults)) {
728 self::$type_defaults = array();
729 $set = $ilDB->query("SELECT * FROM ut_lp_defaults");
730 while ($row = $ilDB->fetchAssoc($set)) {
731 self::$type_defaults[$row["type_id"]] = $row["lp_mode"];
732 }
733 }
734 return self::$type_defaults[$a_type];
735 }
736
737 public static function saveTypeDefaults(array $a_data)
738 {
739 global $DIC;
740
741 $ilDB = $DIC->database();
742
743 $ilDB->manipulate("DELETE FROM ut_lp_defaults");
744 foreach ($a_data as $type => $mode) {
745 $ilDB->insert("ut_lp_defaults", array(
746 "type_id" => array("text", $type),
747 "lp_mode" => array("integer", $mode)
748 ));
749 }
750 }
751
758 public static function getTypeDefault($a_type)
759 {
761 if ($db !== null) {
762 return $db;
763 }
764
765 $class = self::getTypeClass($a_type);
766 $olp = new $class(0);
767 return $olp->getDefaultMode();
768 }
769}
An exception for terminatinating execution or to throw for unit testing.
const IL_COMP_SERVICE
static _getAllUserIds($a_obj_id)
static _deleteReadEventsForUsers($a_obj_id, array $a_user_ids)
static _delete($a_obj_id)
Delete object entries.
static getInstanceByMode($a_obj_id, $a_mode)
static deleteObject($a_obj_id)
Delete object.
static _getAllUserIds($a_obj_id)
static _deleteForUsers($a_obj_id, array $a_user_ids)
static _mode2Text($a_mode)
static _lookupDBMode($a_obj_id)
static _mode2InfoText($a_mode)
static _updateStatus($a_obj_id, $a_usr_id, $a_obj=null, $a_percentage=false, $a_force_raise=false)
Update status.
static _refreshStatus($a_obj_id, $a_users=null)
Set dirty.
static _enabledLearningProgress()
check wether learing progress is enabled or not
__construct($a_obj_id)
static getLPMemberships($a_usr_id, array $a_obj_ids, $a_parent_ref_id=null, $a_mapped_ref_ids=false)
Get all objects where given user is member (from LP POV)
static supportsMark($a_obj_type)
getModeText($a_mode)
static saveTypeDefaults(array $a_data)
resetLPDataForUserIds(array $a_user_ids, $a_recursive=true)
static isSupportedObjectType($type)
static getTypeClass($a_type)
static getSupportedObjectTypes()
resetCustomLPDataForUserIds(array $a_user_ids, $a_recursive=true)
static $type_defaults
static getTypeDefaultFromDB($a_type)
static supportsSpentSeconds($a_obj_type)
static getInstance($a_obj_id)
resetLPDataForCompleteObject($a_recursive=true)
static handleMove($a_source_ref_id)
getModeInfoText($a_mode)
static getTypeDefault($a_type)
Get current type default.
static getDefaultModes($a_lp_active)
Get available type-specific default modes (no administration needed)
static supportsMatrixView($a_obj_type)
static isLPMember(array &$a_res, $a_usr_id, $a_obj_ids)
Find (lp-relevant) members for given object ids.
getMembers($a_search=true)
static findMembershipsByPath(array &$a_res, $a_usr_id, $a_parent_ref_id, array $a_obj_ids, $a_mapped_ref_ids=false)
Find (lp-relevant) memberships by path.
static _lookupObjId($a_id)
static _getAllReferences($a_id)
get all reference ids of object
static _lookupType($a_id, $a_reference=false)
lookup object type
static isTypePluginWithLP($a_type, $a_active_status=true)
Check whether a repository type is a plugin which has active learning progress.
const ROOT_FOLDER_ID
Definition: constants.php:30
$valid
global $DIC
Definition: goto.php:24
$query
$type
foreach($_POST as $key=> $value) $res
global $ilDB