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