ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
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 '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  {
200  $valid = self::getSupportedObjectTypes();
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";
242  $mode = self::getTypeDefaultFromDB(ilObject::_lookupType($this->obj_id));
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  {
311  $tree = $this->tree;
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  {
452  $this->updateParentCollections();
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 
468  $this->updateParentCollections();
469  }
470 
471  final protected function updateParentCollections()
472  {
473  $ilDB = $this->db;
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  {
760  $db = self::getTypeDefaultFromDB($a_type);
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 }
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
const ROOT_FOLDER_ID
Definition: constants.php:30
static getSupportedObjectTypes()
resetLPDataForCompleteObject($a_recursive=true)
static _updateStatus($a_obj_id, $a_usr_id, $a_obj=null, $a_percentage=false, $a_force_raise=false)
Update status.
$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)
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)
global $DIC
Definition: goto.php:24
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)
static supportsMark($a_obj_type)
static _mode2InfoText($a_mode)
static supportsSpentSeconds($a_obj_type)
static isSupportedObjectType($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)
const IL_COMP_SERVICE
static _mode2Text($a_mode)