ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
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 public static function isSupportedObjectType($a_type)
159 {
160 global $DIC;
161
162 $objDefinition = $DIC["objDefinition"];
163
164 $valid = array("crs", "grp", "fold", "lm", "htlm", "sahs", "tst", "exc",
165 "sess", "svy", "file", "mcst", "prg", "iass", "copa", "lso", 'cmix', 'lti', 'crsr');
166
167 if (in_array($a_type, $valid)) {
168 return true;
169 }
170
171 if ($objDefinition->isPluginTypeName($a_type)) {
172 include_once 'Services/Repository/classes/class.ilRepositoryObjectPluginSlot.php';
174 }
175
176 return false;
177 }
178
179 public function resetCaches()
180 {
181 $this->mode = null;
182 $this->collection_instance = null;
183 }
184
185 public function isAnonymized()
186 {
187 // see ilLPCollectionOfRepositoryObjects::validateEntry()
188 return false;
189 }
190
191
192 //
193 // MODE
194 //
195
196 public function getDefaultMode()
197 {
199 }
200
201 public function getValidModes()
202 {
203 return array();
204 }
205
206 public function getCurrentMode()
207 {
208 if ($this->mode === null) {
209 // using global type default if LP is inactive
210 include_once "Services/Tracking/classes/class.ilObjUserTracking.php";
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()
233 {
234 // :TODO: check LP activation?
235
236 $mode = $this->getCurrentMode();
239 return false;
240 }
241 return true;
242 }
243
244 public function getModeText($a_mode)
245 {
246 return ilLPObjSettings::_mode2Text($a_mode);
247 }
248
249 public function getModeInfoText($a_mode)
250 {
251 return ilLPObjSettings::_mode2InfoText($a_mode);
252 }
253
254 public function getSettingsInfo()
255 {
256 // type-specific
257 }
258
259
260 //
261 // COLLECTION
262 //
263
264 public function getCollectionInstance()
265 {
266 if ($this->collection_instance === null) {
267 include_once "Services/Tracking/classes/collection/class.ilLPCollection.php";
268 $this->collection_instance = ilLPCollection::getInstanceByMode($this->obj_id, $this->getCurrentMode());
269 }
270
272 }
273
274
275 //
276 // MEMBERS
277 //
278
279 public function getMembers($a_search = true)
280 {
282
283 if (!$a_search) {
284 return;
285 }
286
287 $ref_ids = ilObject::_getAllReferences($this->obj_id);
288 $ref_id = current($ref_ids);
289
290 // walk path to find parent with specific members
291 $path = $tree->getPathId($ref_id);
292 array_pop($path);
293 foreach (array_reverse($path) as $path_ref_id) {
294 $olp = self::getInstance(ilObject::_lookupObjId($path_ref_id));
295 $all = $olp->getMembers(false);
296 if (is_array($all)) {
297 return $all;
298 }
299 }
300 }
301
302
303 //
304 // RESET
305 //
306
307 final public function resetLPDataForCompleteObject($a_recursive = true)
308 {
309 $user_ids = $this->gatherLPUsers();
310 if (sizeof($user_ids)) {
311 $this->resetLPDataForUserIds(array_unique($user_ids), $a_recursive);
312 }
313 }
314
315 final public function resetLPDataForUserIds(array $a_user_ids, $a_recursive = true)
316 {
317 if ((bool) $a_recursive &&
318 method_exists($this, "getPossibleCollectionItems")) { // #15203
319 $subitems = $this->getPossibleCollectionItems();
320 if (is_array($subitems)) {
321 foreach ($subitems as $sub_ref_id) {
322 $olp = self::getInstance(ilObject::_lookupObjId($sub_ref_id));
323 $olp->resetLPDataForUserIds($a_user_ids, false);
324 }
325 }
326 }
327
328 $this->resetCustomLPDataForUserIds($a_user_ids, (bool) $a_recursive);
329
330 include_once "Services/Tracking/classes/class.ilLPMarks.php";
331 ilLPMarks::_deleteForUsers($this->obj_id, $a_user_ids);
332
333 include_once "Services/Tracking/classes/class.ilChangeEvent.php";
334 ilChangeEvent::_deleteReadEventsForUsers($this->obj_id, $a_user_ids);
335
336 // update LP status to get collections up-to-date
337 include_once "Services/Tracking/classes/class.ilLPStatusWrapper.php";
338 foreach ($a_user_ids as $user_id) {
339 ilLPStatusWrapper::_updateStatus($this->obj_id, $user_id);
340 }
341 }
342
343 protected function resetCustomLPDataForUserIds(array $a_user_ids, $a_recursive = true)
344 {
345 // this should delete all data that is relevant for the supported LP modes
346 }
347
348 protected function gatherLPUsers()
349 {
350 include_once "Services/Tracking/classes/class.ilLPMarks.php";
351 $user_ids = ilLPMarks::_getAllUserIds($this->obj_id);
352
353 include_once "Services/Tracking/classes/class.ilChangeEvent.php";
354 $user_ids = array_merge($user_ids, ilChangeEvent::_getAllUserIds($this->obj_id));
355
356 return $user_ids;
357 }
358
359
360 //
361 // EVENTS
362 //
363
364 final public static function handleMove($a_source_ref_id)
365 {
366 global $DIC;
367
368 $tree = $DIC->repositoryTree();
369 $ilDB = $DIC->database();
370
371 $ref_ids = $tree->getSubTreeIds($a_source_ref_id);
372 $ref_ids[] = $a_source_ref_id;
373
374 // get "parent" path to source node (not including source node)
375 $new_path = $tree->getPathId($a_source_ref_id);
376 array_pop($new_path);
377 $new_path = implode("/", $new_path);
378
379 include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
380
381 // find collections with ref_ids
382 $set = $ilDB->query("SELECT DISTINCT(ut_lp_collections.obj_id) obj_id" .
383 " FROM object_reference" .
384 " JOIN ut_lp_collections ON" .
385 " (" . $ilDB->in("object_reference.ref_id", $ref_ids, "", "integer") .
386 " AND object_reference.ref_id = ut_lp_collections.item_id)");
387 while ($rec = $ilDB->fetchAssoc($set)) {
388 if (in_array(ilObject::_lookupType($rec["obj_id"]), array("crs", "grp", "fold"))) {
389 $coll_ref_id = ilObject::_getAllReferences($rec["obj_id"]);
390 $coll_ref_id = array_pop($coll_ref_id);
391
392 // #13402
393 if ($coll_ref_id == $a_source_ref_id) {
394 continue;
395 }
396
397 // #17703 - collection has also been moved - nothing todo
398 if ($tree->isGrandChild($a_source_ref_id, $coll_ref_id)) {
399 continue;
400 }
401
402 // get path to collection (including collection "parent")
403 $coll_path = $tree->getPathId($coll_ref_id);
404 $coll_path = implode("/", $coll_path);
405
406 // collection path is not inside new path
407 if (!stristr($new_path, $coll_path)) {
408 // delete all items of moved (sub-)tree
409 $query = "DELETE FROM ut_lp_collections" .
410 " WHERE obj_id = " . $ilDB->quote($rec["obj_id"], "integer") .
411 " AND " . $ilDB->in("item_id", $ref_ids, "", "integer");
412 $ilDB->manipulate($query);
413
414 ilLPStatusWrapper::_refreshStatus($rec["obj_id"]);
415 }
416 }
417 }
418 }
419
420 final public function handleToTrash()
421 {
423 }
424
425 final public function handleDelete()
426 {
427 include_once "Services/Tracking/classes/class.ilLPMarks.php";
428 ilLPMarks::deleteObject($this->obj_id);
429
430 include_once "Services/Tracking/classes/class.ilChangeEvent.php";
431 ilChangeEvent::_delete($this->obj_id);
432
433 $collection = $this->getCollectionInstance();
434 if ($collection) {
435 $collection->delete();
436 }
437
439 }
440
441 final protected function updateParentCollections()
442 {
444
445 include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
446
447 // update parent collections?
448 $set = $ilDB->query("SELECT ut_lp_collections.obj_id obj_id FROM " .
449 "object_reference JOIN ut_lp_collections ON " .
450 "(object_reference.obj_id = " . $ilDB->quote($this->obj_id, "integer") .
451 " AND object_reference.ref_id = ut_lp_collections.item_id)");
452 while ($rec = $ilDB->fetchAssoc($set)) {
453 if (in_array(ilObject::_lookupType($rec["obj_id"]), array("crs", "grp", "fold"))) {
454 // remove from parent collection
455 $query = "DELETE FROM ut_lp_collections" .
456 " WHERE obj_id = " . $ilDB->quote($rec["obj_id"], "integer") .
457 " AND item_id = " . $ilDB->quote($this->obj_id, "integer");
458 $ilDB->manipulate($query);
459
460 ilLPStatusWrapper::_refreshStatus($rec["obj_id"]);
461 }
462 }
463 }
464
465
466 //
467 // LP-relevant memberships
468 //
469
477 protected static function isLPMember(array &$a_res, $a_usr_id, $a_obj_ids)
478 {
479 // should be overwritten by object-type-specific class
480 return false;
481 }
482
493 protected static function findMembershipsByPath(array &$a_res, $a_usr_id, $a_parent_ref_id, array $a_obj_ids, $a_mapped_ref_ids = false)
494 {
495 global $DIC;
496
497 $tree = $DIC->repositoryTree();
498
499 $found = array();
500
501 // walk path to find course or group object and check members of that object
502 $path = $tree->getPathId($a_parent_ref_id);
503 foreach (array_reverse($path) as $path_ref_id) {
504 $type = ilObject::_lookupType($path_ref_id, true);
505 if ($type == "crs" ||
506 $type == "grp") {
507 $class = self::getTypeClass($type);
508 $path_ob_id = ilObject::_lookupObjId($path_ref_id);
509 $chk = array();
510 $class::isLPMember($chk, $a_usr_id, array($path_ob_id));
511 if (!$a_mapped_ref_ids) {
512 // we found a grp/crs in path of (single) parent - mark all objects
513 foreach ($a_obj_ids as $obj_id) {
514 $found[] = $obj_id;
515 if ($chk[$path_ob_id]) {
516 $a_res[$obj_id] = true;
517 }
518 }
519 } else {
520 // all children from current node are "lp-valid"
521 foreach ($a_obj_ids as $obj_id => $ref_ids) {
522 foreach ($ref_ids as $ref_id) {
523 if ($tree->isGrandChild($path_ref_id, $ref_id)) {
524 $found[$obj_id][] = $ref_id;
525 if ($chk[$path_ob_id]) {
526 $a_res[$obj_id] = true;
527 }
528 break;
529 }
530 }
531 }
532 }
533 break;
534 }
535 }
536
537 return $found;
538 }
539
549 public static function getLPMemberships($a_usr_id, array $a_obj_ids, $a_parent_ref_id = null, $a_mapped_ref_ids = false)
550 {
551 global $DIC;
552
553 $ilDB = $DIC->database();
554 $tree = $DIC->repositoryTree();
555
556 // see ilTrQuery::getParticipantsForObject() [single object only]
557 // this is optimized for larger number of objects, e.g. list GUIs
558
559 $ref_map = [];
560 if ((bool) $a_mapped_ref_ids) {
561 $ref_map = $a_obj_ids;
562 $a_obj_ids = array_keys($a_obj_ids);
563 }
564
565 $res = array();
566
567 // get object types
568 $types_map = array();
569 $query = " SELECT obj_id, type" .
570 " FROM object_data" .
571 " WHERE " . $ilDB->in("obj_id", $a_obj_ids, "", "integer");
572 $set = $ilDB->query($query);
573 while ($row = $ilDB->fetchAssoc($set)) {
574 $types_map[$row["type"]][] = $row["obj_id"];
575 $res[$row["obj_id"]] = false;
576 }
577
578 $find_by_parent = array();
579 foreach ($types_map as $type => $type_obj_ids) {
580 $class = self::getTypeClass($type);
581 if ($class) {
582 // lp-supported type?
583 if (!$class::isLPMember($res, $a_usr_id, $type_obj_ids)) {
584 $find_by_parent = array_merge($find_by_parent, $type_obj_ids);
585 }
586 }
587 }
588
589 if (sizeof($find_by_parent)) {
590 // single parent for all objects (repository/ilObjectListGUI)
591 if ($a_parent_ref_id) {
592 if (self::findMembershipsByPath($res, $a_usr_id, $a_parent_ref_id, $find_by_parent)) {
593 // we found a crs/grp in path, so no need to check read_events
594 $find_by_parent = null;
595 }
596 }
597 // different parents (PD > LP)
598 elseif (is_array($ref_map) && count($ref_map) > 0) {
599 foreach ($find_by_parent as $obj_id) {
600 // maybe already found by path search from other object/reference
601 if ($res[$obj_id] === false) {
602 if (isset($ref_map[$obj_id]) && is_array($ref_map[$obj_id])) {
603 // check all references
604 foreach ($ref_map[$obj_id] as $ref_id) {
605 $parent_ref_id = $tree->getParentId($ref_id);
606 if ($parent_ref_id == ROOT_FOLDER_ID) {
607 continue;
608 }
609
610 // we are checking the complete ref_map
611 // to find all relevant objects in subtree of current ref_id
612 $found = self::findMembershipsByPath($res, $a_usr_id, $parent_ref_id, $ref_map, true);
613 if (is_array($found) && count($found) > 0) {
614 // if any references were found in a crs/grp-subtree
615 // remove from "read-event"-last-resort-pool
616 foreach ($found as $found_obj_id => $found_ref_ids) {
617 $diff = array_diff($ref_map[$found_obj_id], $found_ref_ids);
618 if ($diff) {
619 // 1-n refs are in another subtree
620 // have to be checked separately
621 $ref_map[$found_obj_id] = $diff;
622 } else {
623 // all references found in subtree
624 // no need to check again
625 unset($ref_map[$found_obj_id]);
626 }
627 }
628 break;
629 }
630 }
631 }
632 }
633 }
634
635 $find_by_parent = array_keys($ref_map);
636 }
637
638 // last resort: use read_event?
639 if (is_array($find_by_parent) && count($find_by_parent) > 0) {
640 $set = $ilDB->query("SELECT obj_id" .
641 " FROM read_event" .
642 " WHERE " . $ilDB->in("obj_id", $find_by_parent, "", "integer") .
643 " AND usr_id = " . $ilDB->quote($a_usr_id, "integer"));
644 while ($row = $ilDB->fetchAssoc($set)) {
645 $res[$row["obj_id"]] = true;
646 }
647 }
648 }
649
650 return $res;
651 }
652
653 public function getMailTemplateId()
654 {
655 // type-specific
656 }
657
658
659 //
660 // type-specific support of features (should be enhanced)
661 //
662
663 public static function supportsSpentSeconds($a_obj_type)
664 {
665 return !in_array($a_obj_type, array("exc", "file", "mcst", "mob", "htlm", "copa", 'cmix', 'lti'));
666 }
667
668 public static function supportsMark($a_obj_type)
669 {
670 return !in_array($a_obj_type, array("lm", "dbk"));
671 }
672
673 public static function supportsMatrixView($a_obj_type)
674 {
675 return !in_array($a_obj_type, array('svy', 'tst', 'htlm', 'exc', 'sess', 'file', 'prg', 'copa', 'cmix', 'lti','crsr'));
676 }
677
678
679 // type-wide default
680
686 public static function getDefaultModes($a_lp_active)
687 {
689 }
690
691 protected static function getTypeDefaultFromDB($a_type)
692 {
693 global $DIC;
694
695 $ilDB = $DIC->database();
696
697 if (!is_array(self::$type_defaults)) {
698 self::$type_defaults = array();
699 $set = $ilDB->query("SELECT * FROM ut_lp_defaults");
700 while ($row = $ilDB->fetchAssoc($set)) {
701 self::$type_defaults[$row["type_id"]] = $row["lp_mode"];
702 }
703 }
704 return self::$type_defaults[$a_type];
705 }
706
707 public static function saveTypeDefaults(array $a_data)
708 {
709 global $DIC;
710
711 $ilDB = $DIC->database();
712
713 $ilDB->manipulate("DELETE FROM ut_lp_defaults");
714 foreach ($a_data as $type => $mode) {
715 $ilDB->insert("ut_lp_defaults", array(
716 "type_id" => array("text", $type),
717 "lp_mode" => array("integer", $mode)
718 ));
719 }
720 }
721
728 public static function getTypeDefault($a_type)
729 {
731 if ($db !== null) {
732 return $db;
733 }
734
735 $class = self::getTypeClass($a_type);
736 $olp = new $class(0);
737 return $olp->getDefaultMode();
738 }
739}
An exception for terminatinating execution or to throw for unit testing.
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)
static isSupportedObjectType($a_type)
resetLPDataForUserIds(array $a_user_ids, $a_recursive=true)
static getTypeClass($a_type)
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.
$valid
$query
$type
foreach($_POST as $key=> $value) $res
global $ilDB
$a_type
Definition: workflow.php:92
$DIC
Definition: xapitoken.php:46