ILIAS  Release_4_4_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  $ilDB->manipulate("INSERT INTO ut_lp_marks ".
408  "(status, status_changed, usr_id, obj_id, status_dirty) VALUES (".
409  $ilDB->quote($a_status, "integer").",".
410  $ilDB->now().",".
411  $ilDB->quote($a_user_id, "integer").",".
412  $ilDB->quote($a_obj_id, "integer").",".
413  $ilDB->quote(0, "integer").
414  ")");
415  $update_collections = true;
416  }
417 
418  // update percentage
419  if ($a_percentage !== false || $a_force_per)
420  {
421  $a_percentage = max(0, (int) $a_percentage);
422  $a_percentage = min(100, $a_percentage);
423  $ret = $ilDB->manipulate("UPDATE ut_lp_marks SET ".
424  " percentage = ".$ilDB->quote($a_percentage, "integer").
425  " WHERE usr_id = ".$ilDB->quote($a_user_id, "integer").
426  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
427  );
428  }
429 
430  // update collections
431  if ($update_collections)
432  {
433  // a change occured - remove existing cache entry
434  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
435  ilLPStatusWrapper::_removeStatusCache($a_obj_id, $a_user_id);
436 
437  $set = $ilDB->query("SELECT ut_lp_collections.obj_id obj_id FROM ".
438  "object_reference JOIN ut_lp_collections ON ".
439  "(object_reference.obj_id = ".$ilDB->quote($a_obj_id, "integer").
440  " AND object_reference.ref_id = ut_lp_collections.item_id)");
441  while ($rec = $ilDB->fetchAssoc($set))
442  {
443  if (in_array(ilObject::_lookupType($rec["obj_id"]), array("crs", "grp", "fold")))
444  {
445  // just to make sure - remove existing cache entry
446  ilLPStatusWrapper::_removeStatusCache($rec["obj_id"], $a_user_id);
447 
448  ilLPStatusWrapper::_updateStatus($rec["obj_id"], $a_user_id);
449  }
450  }
451  }
452 
453  return $update_collections;
454  }
455 
461  static function setInProgressIfNotAttempted($a_obj_id, $a_user_id)
462  {
463  global $ilDB;
464 
465  // #11513
466 
467  $needs_update = false;
468 
469  $set = $ilDB->query("SELECT usr_id, status FROM ut_lp_marks WHERE ".
470  " obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
471  " usr_id = ".$ilDB->quote($a_user_id, "integer")
472  );
473  if ($rec = $ilDB->fetchAssoc($set))
474  {
475  // current status is not attempted, so we need to update
476  if($rec["status"] == self::LP_STATUS_NOT_ATTEMPTED_NUM)
477  {
478  $needs_update = true;
479  }
480  }
481  else
482  {
483  // no ut_lp_marks yet, we should update
484  $needs_update = true;
485  }
486 
487  if($needs_update)
488  {
489  require_once "Services/Tracking/classes/class.ilLPStatusWrapper.php";
490  ilLPStatusWrapper::_updateStatus($a_obj_id, $a_user_id);
491  }
492  }
493 
500  static function setAllDirty()
501  {
502  global $ilDB;
503 
504  $ilDB->manipulate("UPDATE ut_lp_marks SET ".
505  " status_dirty = ".$ilDB->quote(1, "integer")
506  );
507 
508  }
509 
516  static function setDirty($a_obj_id)
517  {
518  global $ilDB;
519 
520  $ilDB->manipulate("UPDATE ut_lp_marks SET ".
521  " status_dirty = ".$ilDB->quote(1, "integer").
522  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer")
523  );
524  }
525 
532  public static function _lookupStatus($a_obj_id, $a_user_id)
533  {
534  global $ilDB;
535 
536  $set = $ilDB->query("SELECT status FROM ut_lp_marks WHERE ".
537  " status_dirty = ".$ilDB->quote(0, "integer").
538  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
539  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
540  );
541  if ($rec = $ilDB->fetchAssoc($set))
542  {
543  return $rec["status"];
544  }
545  else
546  {
547  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
548  ilLPStatusWrapper::_updateStatus($a_obj_id, $a_user_id);
549  $set = $ilDB->query("SELECT status FROM ut_lp_marks WHERE ".
550  " status_dirty = ".$ilDB->quote(0, "integer").
551  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
552  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
553  );
554  if ($rec = $ilDB->fetchAssoc($set))
555  {
556  return $rec["status"];
557  }
558  }
559  }
560 
568  public static function _hasUserCompleted($a_obj_id, $a_user_id)
569  {
570  return (self::_lookupStatus($a_obj_id, $a_user_id) == self::LP_STATUS_COMPLETED_NUM);
571  }
572 
579  function _lookupStatusChanged($a_obj_id, $a_user_id)
580  {
581  global $ilDB;
582 
583  $set = $ilDB->query("SELECT status_changed FROM ut_lp_marks WHERE ".
584  " status_dirty = ".$ilDB->quote(0, "integer").
585  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
586  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
587  );
588  if ($rec = $ilDB->fetchAssoc($set))
589  {
590  return $rec["status_changed"];
591  }
592  else
593  {
594  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
595  ilLPStatusWrapper::_updateStatus($a_obj_id, $a_user_id);
596  $set = $ilDB->query("SELECT status_changed FROM ut_lp_marks WHERE ".
597  " status_dirty = ".$ilDB->quote(0, "integer").
598  " AND usr_id = ".$ilDB->quote($a_user_id, "integer").
599  " AND obj_id = ".$ilDB->quote($a_obj_id, "integer")
600  );
601  if ($rec = $ilDB->fetchAssoc($set))
602  {
603  return $rec["status_changed"];
604  }
605  }
606  }
607 
616  protected static function _lookupStatusForObject($a_obj_id, $a_status, $a_user_ids = null)
617  {
618  global $ilDB;
619 
620  $sql = "SELECT usr_id, status, status_dirty FROM ut_lp_marks".
621  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer").
622  " AND status = ".$ilDB->quote($a_status, "integer");
623  if($a_user_ids)
624  {
625  $sql .= " AND ".$ilDB->in("usr_id", $a_user_ids, "", "integer");
626  }
627 
628  $set = $ilDB->query($sql);
629  $res = array();
630  while($rec = $ilDB->fetchAssoc($set))
631  {
632  if($res["status_dirty"])
633  {
634  // update status and check again
635  if(self::_lookupStatus($a_obj_id, $rec["usr_id"]) != $a_status)
636  {
637  continue;
638  }
639  }
640  $res[] = $rec["usr_id"];
641  }
642 
643  return $res;
644  }
645 
653  public static function _lookupCompletedForObject($a_obj_id, $a_user_ids = null)
654  {
655  return self::_lookupStatusForObject($a_obj_id, self::LP_STATUS_COMPLETED_NUM, $a_user_ids);
656  }
657 
665  public static function _lookupFailedForObject($a_obj_id, $a_user_ids = null)
666  {
667  return self::_lookupStatusForObject($a_obj_id, self::LP_STATUS_FAILED_NUM, $a_user_ids);
668  }
669 
677  public static function _lookupInProgressForObject($a_obj_id, $a_user_ids = null)
678  {
679  return self::_lookupStatusForObject($a_obj_id, self::LP_STATUS_IN_PROGRESS_NUM, $a_user_ids);
680  }
681 
682  public static function preloadListGUIData($a_obj_ids)
683  {
684  global $ilDB, $ilUser, $lng;
685 
686  $res = array();
687 
688  include_once("Services/Tracking/classes/class.ilObjUserTracking.php");
689  if($ilUser->getId() != ANONYMOUS_USER_ID &&
693  {
694  include_once "Services/Object/classes/class.ilObjectLP.php";
695 
696  // validate objects
697  $valid = array();
698  $existing = ilLPObjSettings::_lookupDBModeForObjects($a_obj_ids);
699  foreach($existing as $obj_id => $obj_mode)
700  {
701  if($obj_mode != ilLPObjSettings::LP_MODE_DEACTIVATED)
702  {
704  }
705  }
706 
707  if(sizeof($existing) != sizeof($a_obj_ids))
708  {
709  // missing objects (default mode)
710  foreach(array_diff($a_obj_ids, $existing) as $obj_id)
711  {
712  $olp = ilObjectLP::getInstance($obj_id);
713  $mode = $olp->getCurrentMode();
715  {
716  // #11141
717  unset($valid[$obj_id]);
718  }
719  else if($mode != ilLPObjSettings::LP_MODE_UNDEFINED)
720  {
722  }
723  }
724  unset($existing);
725  }
726 
727  $valid = array_values($valid);
728 
729  // get user lp data
730  $sql = "SELECT status, status_dirty, obj_id FROM ut_lp_marks".
731  " WHERE ".$ilDB->in("obj_id", $valid, "", "integer").
732  " AND usr_id = ".$ilDB->quote($ilUser->getId(), "integer");
733  $set = $ilDB->query($sql);
734  while($row = $ilDB->fetchAssoc($set))
735  {
736  if(!$row["status_dirty"])
737  {
738  $res[$row["obj_id"]] = $row["status"];
739  }
740  else
741  {
742  $res[$row["obj_id"]] = self::_lookupStatus($row["obj_id"], $ilUser->getId());
743  }
744  }
745 
746  // add not attempted for missing user entries
747  foreach($valid as $obj_id)
748  {
749  if(!isset($res[$obj_id]))
750  {
752  }
753  }
754 
755  // value to icon
756  $lng->loadLanguageModule("trac");
757  include_once("./Services/Tracking/classes/class.ilLearningProgressBaseGUI.php");
758  foreach($res as $obj_id => $status)
759  {
762  $res[$obj_id] = ilUtil::img($path, $text);
763  }
764  }
765 
766  self::$list_gui_cache = $res;
767  }
768 
769  public static function getListGUIStatus($a_obj_id)
770  {
771  return self::$list_gui_cache[$a_obj_id];
772  }
773 }
774 ?>