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