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