ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilLPStatus.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
16 {
17  var $obj_id = null;
18 
19  var $db = null;
20 
22 
23  const LP_STATUS_NOT_ATTEMPTED = 'trac_no_attempted';
24  const LP_STATUS_IN_PROGRESS = 'trac_in_progress';
25  const LP_STATUS_COMPLETED = 'trac_completed';
26  const LP_STATUS_FAILED = 'trac_failed';
27 
32 
33  const LP_STATUS_REGISTERED = 'trac_registered';
34  const LP_STATUS_NOT_REGISTERED = 'trac_not_registered';
35  const LP_STATUS_PARTICIPATED = 'trac_participated';
36  const LP_STATUS_NOT_PARTICIPATED = 'trac_not_participated';
37 
38  function ilLPStatus($a_obj_id)
39  {
40  global $ilDB;
41 
42  $this->obj_id = $a_obj_id;
43  $this->db =& $ilDB;
44  }
45 
46  function _getCountNotAttempted($a_obj_id)
47  {
48  return 0;
49  }
50 
51  function _getNotAttempted($a_obj_id)
52  {
53  return array();
54  }
55 
56  function _getCountInProgress($a_obj_id)
57  {
58  return 0;
59  }
60  function _getInProgress($a_obj_id)
61  {
62  return array();
63  }
64 
65  function _getCountCompleted($a_obj_id)
66  {
67  return 0;
68  }
69  function _getCompleted($a_obj_id)
70  {
71  return array();
72  }
73  function _getFailed($a_obj_id)
74  {
75  return array();
76  }
77  function _getCountFailed()
78  {
79  return 0;
80  }
81  function _getStatusInfo($a_obj_id)
82  {
83  return array();
84  }
85  function _getTypicalLearningTime($a_obj_id)
86  {
87  include_once 'Services/MetaData/classes/class.ilMDEducational.php';
89  }
90 
91 
195  function _updateStatus($a_obj_id, $a_usr_id, $a_obj = null, $a_percentage = false, $a_no_raise = false, $a_force_raise = false)
196  {
197 //global $ilLog;
198 //$ilLog->write("ilLPStatus-_updateStatus-");
199 
200  $status = $this->determineStatus($a_obj_id, $a_usr_id, $a_obj);
201  $percentage = $this->determinePercentage($a_obj_id, $a_usr_id, $a_obj);
202  $changed = self::writeStatus($a_obj_id, $a_usr_id, $status, $percentage);
203 
204  if(!$a_no_raise &&
205  ($changed || $a_force_raise)) // #15529
206  {
207  self::raiseEvent($a_obj_id, $a_usr_id, $status, $percentage);
208  }
209  }
210 
217  function determinePercentage($a_obj_id, $a_usr_id, $a_obj = null)
218  {
219  return false;
220  }
221 
228  function determineStatus($a_obj_id, $a_usr_id, $a_obj = null)
229  {
230  return false;
231  }
232 
233 
241  static function checkStatusForObject($a_obj_id, $a_users = false)
242  {
243  global $ilDB;
244 
245 //@todo: there maybe the need to add extra handling for sessions here, since the
246 // "in progress" status is time dependent here. On the other hand, if they registered
247 // to the session, they already accessed the course and should have a "in progress"
248 // anyway. But the status on the session itself may not be correct.
249 
250  $sql = "SELECT usr_id FROM ut_lp_marks WHERE ".
251  " obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
252  " status_dirty = ".$ilDB->quote(1, "integer");
253  if(is_array($a_users) && count($a_users) > 0)
254  {
255  $sql .= " AND ".$ilDB->in("usr_id", $a_users, false, "integer");
256  }
257  $set = $ilDB->query($sql);
258  $dirty = false;
259  if ($rec = $ilDB->fetchAssoc($set))
260  {
261  $dirty = true;
262  }
263 
264  // check if any records are missing
265  $missing = false;
266  if (!$dirty && is_array($a_users) && count($a_users) > 0)
267  {
268  $set = $ilDB->query("SELECT count(usr_id) cnt FROM ut_lp_marks WHERE ".
269  " obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
270  $ilDB->in("usr_id", $a_users, false, "integer"));
271  $r = $ilDB->fetchAssoc($set);
272  if ($r["cnt"] < count($a_users))
273  {
274  $missing = true;
275  }
276  }
277 
278  // refresh status, if records are dirty or missing
279  if ($dirty || $missing)
280  {
281  require_once "Services/Tracking/classes/class.ilLPStatusFactory.php"; // #13330
282  $trac_obj = ilLPStatusFactory::_getInstance($a_obj_id);
283  $trac_obj->refreshStatus($a_obj_id, $a_users);
284  }
285  }
286 
287  protected function raiseEvent($a_obj_id, $a_usr_id, $a_status, $a_percentage)
288  {
289  global $ilAppEventHandler;
290 
291  $ilAppEventHandler->raise("Services/Tracking", "updateStatus", array(
292  "obj_id" => $a_obj_id,
293  "usr_id" => $a_usr_id,
294  "status" => $a_status,
295  "percentage" => $a_percentage
296  ));
297  }
298 
305  function refreshStatus($a_obj_id, $a_users = null)
306  {
307  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
308  $not_attempted = ilLPStatusWrapper::_getNotAttempted($a_obj_id);
309  foreach ($not_attempted as $user_id)
310  {
311  $percentage = $this->determinePercentage($a_obj_id, $user_id);
312  if(self::writeStatus($a_obj_id, $user_id, self::LP_STATUS_NOT_ATTEMPTED_NUM, $percentage, true))
313  {
314  self::raiseEvent($a_obj_id, $user_id, self::LP_STATUS_NOT_ATTEMPTED_NUM, $percentage);
315  }
316  }
317  $in_progress = ilLPStatusWrapper::_getInProgress($a_obj_id);
318  foreach ($in_progress as $user_id)
319  {
320  $percentage = $this->determinePercentage($a_obj_id, $user_id);
321  if(self::writeStatus($a_obj_id, $user_id, self::LP_STATUS_IN_PROGRESS_NUM, $percentage, true))
322  {
323  self::raiseEvent($a_obj_id, $user_id, self::LP_STATUS_IN_PROGRESS_NUM, $percentage);
324  }
325  }
326  $completed = ilLPStatusWrapper::_getCompleted($a_obj_id);
327  foreach ($completed as $user_id)
328  {
329  $percentage = $this->determinePercentage($a_obj_id, $user_id);
330  if(self::writeStatus($a_obj_id, $user_id, self::LP_STATUS_COMPLETED_NUM, $percentage, true))
331  {
332  self::raiseEvent($a_obj_id, $user_id, self::LP_STATUS_COMPLETED_NUM, $percentage);
333  }
334  }
336  foreach ($failed as $user_id)
337  {
338  $percentage = $this->determinePercentage($a_obj_id, $user_id);
339  if(self::writeStatus($a_obj_id, $user_id, self::LP_STATUS_FAILED_NUM, $percentage, true))
340  {
341  self::raiseEvent($a_obj_id, $user_id, self::LP_STATUS_FAILED_NUM, $percentage);
342  }
343  }
344  if($a_users)
345  {
346  $missing_users = array_diff($a_users, $not_attempted+$in_progress+$completed+$failed);
347  if($missing_users)
348  {
349  foreach ($missing_users as $user_id)
350  {
351  ilLPStatusWrapper::_updateStatus($a_obj_id, $user_id);
352  }
353  }
354  }
355  }
356 
363  static function writeStatus($a_obj_id, $a_user_id, $a_status, $a_percentage = false, $a_force_per = false)
364  {
365  global $ilDB;
366 
367  $update_collections = false;
368 
369  // get status in DB
370  $set = $ilDB->query("SELECT usr_id,status,status_dirty FROM ut_lp_marks WHERE ".
371  " obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
372  " usr_id = ".$ilDB->quote($a_user_id, "integer")
373  );
374  $rec = $ilDB->fetchAssoc($set);
375 
376  // update
377  if ($rec)
378  {
379  // status has changed: update
380  if ($rec["status"] != $a_status)
381  {
382  $ret = $ilDB->manipulate("UPDATE ut_lp_marks SET ".
383  " status = ".$ilDB->quote($a_status, "integer").",".
384  " status_changed = ".$ilDB->now().",".
385  " status_dirty = ".$ilDB->quote(0, "integer").
386  " WHERE usr_id = ".$ilDB->quote($a_user_id, "integer").
387  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
388  );
389  if ($ret != 0)
390  {
391  $update_collections = true;
392  }
393  }
394  // status has not changed: reset dirty flag
395  else if ($rec["status_dirty"])
396  {
397  $ilDB->manipulate("UPDATE ut_lp_marks SET ".
398  " status_dirty = ".$ilDB->quote(0, "integer").
399  " WHERE usr_id = ".$ilDB->quote($a_user_id, "integer").
400  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
401  );
402  }
403  }
404  // insert
405  else
406  {
407  /*
408  $ilDB->manipulate("INSERT INTO ut_lp_marks ".
409  "(status, status_changed, usr_id, obj_id, status_dirty) VALUES (".
410  $ilDB->quote($a_status, "integer").",".
411  $ilDB->now().",".
412  $ilDB->quote($a_user_id, "integer").",".
413  $ilDB->quote($a_obj_id, "integer").",".
414  $ilDB->quote(0, "integer").
415  ")");
416  */
417 
418  // #13783
419  $ilDB->replace("ut_lp_marks",
420  array(
421  "obj_id" => array("integer", $a_obj_id),
422  "usr_id" => array("integer", $a_user_id)
423  ),
424  array(
425  "status" => array("integer", $a_status),
426  "status_changed" => array("timestamp", date("Y-m-d H:i:s")), // was $ilDB->now()
427  "status_dirty" => array("integer", 0)
428  )
429  );
430 
431  $update_collections = true;
432  }
433 
434  // update percentage
435  if ($a_percentage !== false || $a_force_per)
436  {
437  $a_percentage = max(0, (int) $a_percentage);
438  $a_percentage = min(100, $a_percentage);
439  $ret = $ilDB->manipulate("UPDATE ut_lp_marks SET ".
440  " percentage = ".$ilDB->quote($a_percentage, "integer").
441  " WHERE usr_id = ".$ilDB->quote($a_user_id, "integer").
442  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
443  );
444  }
445 
446  // update collections
447  if ($update_collections)
448  {
449  // a change occured - remove existing cache entry
450  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
451  ilLPStatusWrapper::_removeStatusCache($a_obj_id, $a_user_id);
452 
453  $set = $ilDB->query("SELECT ut_lp_collections.obj_id obj_id FROM ".
454  "object_reference JOIN ut_lp_collections ON ".
455  "(object_reference.obj_id = ".$ilDB->quote($a_obj_id, "integer").
456  " AND object_reference.ref_id = ut_lp_collections.item_id)");
457  while ($rec = $ilDB->fetchAssoc($set))
458  {
459  if (in_array(ilObject::_lookupType($rec["obj_id"]), array("crs", "grp", "fold")))
460  {
461  // just to make sure - remove existing cache entry
462  ilLPStatusWrapper::_removeStatusCache($rec["obj_id"], $a_user_id);
463 
464  ilLPStatusWrapper::_updateStatus($rec["obj_id"], $a_user_id);
465  }
466  }
467  }
468 
469  return $update_collections;
470  }
471 
477  static function setInProgressIfNotAttempted($a_obj_id, $a_user_id)
478  {
479  global $ilDB;
480 
481  // #11513
482 
483  $needs_update = false;
484 
485  $set = $ilDB->query("SELECT usr_id, status FROM ut_lp_marks WHERE ".
486  " obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
487  " usr_id = ".$ilDB->quote($a_user_id, "integer")
488  );
489  if ($rec = $ilDB->fetchAssoc($set))
490  {
491  // current status is not attempted, so we need to update
492  if($rec["status"] == self::LP_STATUS_NOT_ATTEMPTED_NUM)
493  {
494  $needs_update = true;
495  }
496  }
497  else
498  {
499  // no ut_lp_marks yet, we should update
500  $needs_update = true;
501  }
502 
503  if($needs_update)
504  {
505  require_once "Services/Tracking/classes/class.ilLPStatusWrapper.php";
506  ilLPStatusWrapper::_updateStatus($a_obj_id, $a_user_id);
507  }
508  }
509 
516  static function setAllDirty()
517  {
518  global $ilDB;
519 
520  $ilDB->manipulate("UPDATE ut_lp_marks SET ".
521  " status_dirty = ".$ilDB->quote(1, "integer")
522  );
523 
524  }
525 
532  static function setDirty($a_obj_id)
533  {
534  global $ilDB;
535 
536  $ilDB->manipulate("UPDATE ut_lp_marks SET ".
537  " status_dirty = ".$ilDB->quote(1, "integer").
538  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer")
539  );
540  }
541 
549  public static function _lookupStatus($a_obj_id, $a_user_id, $a_create = true)
550  {
551  global $ilDB;
552 
553  $set = $ilDB->query("SELECT status FROM ut_lp_marks WHERE ".
554  " status_dirty = ".$ilDB->quote(0, "integer").
555  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
556  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
557  );
558  if ($rec = $ilDB->fetchAssoc($set))
559  {
560  return $rec["status"];
561  }
562  else if((bool)$a_create)
563  {
564  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
565  ilLPStatusWrapper::_updateStatus($a_obj_id, $a_user_id);
566  $set = $ilDB->query("SELECT status FROM ut_lp_marks WHERE ".
567  " status_dirty = ".$ilDB->quote(0, "integer").
568  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
569  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
570  );
571  if ($rec = $ilDB->fetchAssoc($set))
572  {
573  return $rec["status"];
574  }
575  }
576  }
577 
584  public static function _lookupPercentage($a_obj_id, $a_user_id)
585  {
586  global $ilDB;
587 
588  $set = $ilDB->query("SELECT percentage FROM ut_lp_marks WHERE ".
589  " status_dirty = ".$ilDB->quote(0, "integer").
590  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
591  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
592  );
593  if ($rec = $ilDB->fetchAssoc($set))
594  {
595  return $rec["percentage"];
596  }
597  }
598 
606  public static function _hasUserCompleted($a_obj_id, $a_user_id)
607  {
608  return (self::_lookupStatus($a_obj_id, $a_user_id) == self::LP_STATUS_COMPLETED_NUM);
609  }
610 
617  function _lookupStatusChanged($a_obj_id, $a_user_id)
618  {
619  global $ilDB;
620 
621  $set = $ilDB->query("SELECT status_changed FROM ut_lp_marks WHERE ".
622  " status_dirty = ".$ilDB->quote(0, "integer").
623  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
624  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
625  );
626  if ($rec = $ilDB->fetchAssoc($set))
627  {
628  return $rec["status_changed"];
629  }
630  else
631  {
632  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
633  ilLPStatusWrapper::_updateStatus($a_obj_id, $a_user_id);
634  $set = $ilDB->query("SELECT status_changed FROM ut_lp_marks WHERE ".
635  " status_dirty = ".$ilDB->quote(0, "integer").
636  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
637  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
638  );
639  if ($rec = $ilDB->fetchAssoc($set))
640  {
641  return $rec["status_changed"];
642  }
643  }
644  }
645 
654  protected static function _lookupStatusForObject($a_obj_id, $a_status, $a_user_ids = null)
655  {
656  global $ilDB;
657 
658  $sql = "SELECT usr_id, status, status_dirty FROM ut_lp_marks".
659  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer").
660  " AND status = ".$ilDB->quote($a_status, "integer");
661  if($a_user_ids)
662  {
663  $sql .= " AND ".$ilDB->in("usr_id", $a_user_ids, "", "integer");
664  }
665 
666  $set = $ilDB->query($sql);
667  $res = array();
668  while($rec = $ilDB->fetchAssoc($set))
669  {
670  if($res["status_dirty"])
671  {
672  // update status and check again
673  if(self::_lookupStatus($a_obj_id, $rec["usr_id"]) != $a_status)
674  {
675  continue;
676  }
677  }
678  $res[] = $rec["usr_id"];
679  }
680 
681  return $res;
682  }
683 
691  public static function _lookupCompletedForObject($a_obj_id, $a_user_ids = null)
692  {
693  return self::_lookupStatusForObject($a_obj_id, self::LP_STATUS_COMPLETED_NUM, $a_user_ids);
694  }
695 
703  public static function _lookupFailedForObject($a_obj_id, $a_user_ids = null)
704  {
705  return self::_lookupStatusForObject($a_obj_id, self::LP_STATUS_FAILED_NUM, $a_user_ids);
706  }
707 
715  public static function _lookupInProgressForObject($a_obj_id, $a_user_ids = null)
716  {
717  return self::_lookupStatusForObject($a_obj_id, self::LP_STATUS_IN_PROGRESS_NUM, $a_user_ids);
718  }
719 
720  public static function preloadListGUIData($a_obj_ids)
721  {
722  global $ilDB, $ilUser, $lng;
723 
724  $res = array();
725 
726  include_once("Services/Tracking/classes/class.ilObjUserTracking.php");
727  if($ilUser->getId() != ANONYMOUS_USER_ID &&
731  {
732  include_once "Services/Object/classes/class.ilObjectLP.php";
733 
734  // validate objects
735  $valid = array();
736  $existing = ilLPObjSettings::_lookupDBModeForObjects($a_obj_ids);
737  foreach($existing as $obj_id => $obj_mode)
738  {
739  if($obj_mode != ilLPObjSettings::LP_MODE_DEACTIVATED)
740  {
742  }
743  }
744 
745  if(sizeof($existing) != sizeof($a_obj_ids))
746  {
747  // missing objects (default mode)
748  foreach(array_diff($a_obj_ids, $existing) as $obj_id)
749  {
750  $olp = ilObjectLP::getInstance($obj_id);
751  $mode = $olp->getCurrentMode();
753  {
754  // #11141
755  unset($valid[$obj_id]);
756  }
757  else if($mode != ilLPObjSettings::LP_MODE_UNDEFINED)
758  {
760  }
761  }
762  unset($existing);
763  }
764 
765  $valid = array_values($valid);
766 
767  // get user lp data
768  $sql = "SELECT status, status_dirty, obj_id FROM ut_lp_marks".
769  " WHERE ".$ilDB->in("obj_id", $valid, "", "integer").
770  " AND usr_id = ".$ilDB->quote($ilUser->getId(), "integer");
771  $set = $ilDB->query($sql);
772  while($row = $ilDB->fetchAssoc($set))
773  {
774  if(!$row["status_dirty"])
775  {
776  $res[$row["obj_id"]] = $row["status"];
777  }
778  else
779  {
780  $res[$row["obj_id"]] = self::_lookupStatus($row["obj_id"], $ilUser->getId());
781  }
782  }
783 
784  // process missing user entries (same as dirty entries, see above)
785  foreach($valid as $obj_id)
786  {
787  if(!isset($res[$obj_id]))
788  {
789  $res[$obj_id] = self::_lookupStatus($obj_id, $ilUser->getId());
790  if($res[$obj_id] === null)
791  {
793  }
794  }
795  }
796 
797  // value to icon
798  $lng->loadLanguageModule("trac");
799  include_once("./Services/Tracking/classes/class.ilLearningProgressBaseGUI.php");
800  foreach($res as $obj_id => $status)
801  {
804  $res[$obj_id] = ilUtil::img($path, $text);
805  }
806  }
807 
808  self::$list_gui_cache = $res;
809  }
810 
811  public static function getListGUIStatus($a_obj_id)
812  {
813  return self::$list_gui_cache[$a_obj_id];
814  }
815 }
816 ?>