ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
class.ilChangeEvent.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=0);
20 
45 {
46  private static array $has_accessed = [];
47 
62  public static function _recordWriteEvent(
63  int $obj_id,
64  int $usr_id,
65  string $action,
66  ?int $parent_obj_id = null
67  ): void {
68  global $DIC;
69 
70  $ilDB = $DIC['ilDB'];
71 
72  /* see _recordReadEvent
73  if (!ilChangeEvent::_isActive())
74  {
75  return;
76  }
77  */
78 
79  if ($parent_obj_id == null) {
80  $pset = $ilDB->query(
81  'SELECT r2.obj_id par_obj_id FROM object_reference r1 ' .
82  'JOIN tree t ON t.child = r1.ref_id ' .
83  'JOIN object_reference r2 ON r2.ref_id = t.parent ' .
84  'WHERE r1.obj_id = ' . $ilDB->quote($obj_id, 'integer')
85  );
86 
87  while ($prec = $ilDB->fetchAssoc($pset)) {
88  $nid = $ilDB->nextId("write_event");
89  $query = sprintf(
90  'INSERT INTO write_event ' .
91  '(write_id, obj_id, parent_obj_id, usr_id, action, ts) VALUES ' .
92  '(%s, %s, %s, %s, %s, ' . $ilDB->now() . ')',
93  $ilDB->quote($nid, 'integer'),
94  $ilDB->quote($obj_id, 'integer'),
95  $ilDB->quote($prec["par_obj_id"], 'integer'),
96  $ilDB->quote($usr_id, 'integer'),
97  $ilDB->quote($action, 'text')
98  );
99 
100  $aff = $ilDB->manipulate($query);
101  }
102  } else {
103  $nid = $ilDB->nextId("write_event");
104  $query = sprintf(
105  'INSERT INTO write_event ' .
106  '(write_id, obj_id, parent_obj_id, usr_id, action, ts) ' .
107  'VALUES (%s,%s,%s,%s,%s,' . $ilDB->now() . ')',
108  $ilDB->quote($nid, 'integer'),
109  $ilDB->quote($obj_id, 'integer'),
110  $ilDB->quote($parent_obj_id, 'integer'),
111  $ilDB->quote($usr_id, 'integer'),
112  $ilDB->quote($action, 'text')
113  );
114  $aff = $ilDB->manipulate($query);
115  }
116  }
117 
118  public static function _recordReadEvent(
119  string $a_type,
120  int $a_ref_id,
121  int $obj_id,
122  int $usr_id,
123  bool $isCatchupWriteEvents = true,
124  $a_ext_rc = null,
125  $a_ext_time = null
126  ): void {
127  global $DIC;
128 
129  $ilDB = $DIC['ilDB'];
130  $tree = $DIC['tree'];
131 
132  $validTimeSpan = ilObjUserTracking::_getValidTimeSpan();
133 
134  $query = sprintf(
135  'SELECT * FROM read_event ' .
136  'WHERE obj_id = %s ' .
137  'AND usr_id = %s ',
138  $ilDB->quote($obj_id, 'integer'),
139  $ilDB->quote($usr_id, 'integer')
140  );
141  $res = $ilDB->query($query);
142  $row = $ilDB->fetchObject($res);
143 
144  // read counter
145  if ($a_ext_rc !== null) {
146  $read_count = 'read_count = ' . $ilDB->quote(
147  $a_ext_rc,
148  "integer"
149  ) . ", ";
150  $read_count_init = max(1, (int) $a_ext_rc);
151  $read_count_diff = max(1, (int) $a_ext_rc) - (int) ($row?->read_count ?? 0);
152  } else {
153  $read_count = 'read_count = read_count + 1, ';
154  $read_count_init = 1;
155  $read_count_diff = 1;
156  }
157 
158  if ($row) {
159  if ($a_ext_time !== null) {
160  $time = (int) $a_ext_time;
161  } else {
162  $time = $ilDB->quote(
163  (time() - $row->last_access) <= $validTimeSpan
164  ? $row->spent_seconds + time() - $row->last_access
165  : $row->spent_seconds,
166  'integer'
167  );
168 
169  // if we are in the valid interval, we do not
170  // add anything to the read_count, since this is the
171  // same access for us
172  if ((time() - $row->last_access) <= $validTimeSpan) {
173  $read_count = '';
174  $read_count_init = 1;
175  $read_count_diff = 0;
176  }
177  }
178  $time_diff = $time - (int) ($row->spent_seconds ?? 0);
179 
180  // Update
181  $query = sprintf(
182  'UPDATE read_event SET ' .
183  $read_count .
184  'spent_seconds = %s, ' .
185  'last_access = %s ' .
186  'WHERE obj_id = %s ' .
187  'AND usr_id = %s ',
188  $time,
189  $ilDB->quote(time(), 'integer'),
190  $ilDB->quote($obj_id, 'integer'),
191  $ilDB->quote($usr_id, 'integer')
192  );
193  $aff = $ilDB->manipulate($query);
194 
195  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
196  } else {
197  if ($a_ext_time !== false) {
198  $time = (int) $a_ext_time;
199  } else {
200  $time = 0;
201  }
202 
203  $time_diff = $time - (int) ($row->spent_seconds ?? 0);
204 
205  // #10407
206  $ilDB->replace(
207  'read_event',
208  array(
209  'obj_id' => array('integer', $obj_id),
210  'usr_id' => array('integer', $usr_id)
211  ),
212  array(
213  'read_count' => array('integer', $read_count_init),
214  'spent_seconds' => array('integer', $time),
215  'first_access' => array('timestamp', date("Y-m-d H:i:s")),
216  // was $ilDB->now()
217  'last_access' => array('integer', time())
218  )
219  );
220 
221  self::$has_accessed[$obj_id][$usr_id] = true;
222 
223  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
224  }
225 
226  if ($isCatchupWriteEvents) {
227  ilChangeEvent::_catchupWriteEvents($obj_id, $usr_id);
228  }
229 
230  // update parents (no categories or root)
231  if (!in_array($a_type, array("cat", "root", "crs"))) {
232  if ($tree->isInTree($a_ref_id)) {
233  $path = $tree->getPathId($a_ref_id);
234 
235  foreach ($path as $p) {
236  $obj2_id = ilObject::_lookupObjId($p);
237  $obj2_type = ilObject::_lookupType($obj2_id);
238  //echo "<br>1-$obj2_type-$p-$obj2_id-";
239  if (($p != $a_ref_id) && (in_array(
240  $obj2_type,
241  array("crs",
242  "fold",
243  "grp",
244  "lso"
245  )
246  ))) {
247  $query = sprintf(
248  'SELECT * FROM read_event ' .
249  'WHERE obj_id = %s ' .
250  'AND usr_id = %s ',
251  $ilDB->quote($obj2_id, 'integer'),
252  $ilDB->quote($usr_id, 'integer')
253  );
254  $res2 = $ilDB->query($query);
255  if ($row2 = $ilDB->fetchAssoc($res2)) {
256  //echo "<br>2";
257  // update read count and spent seconds
258  $query = sprintf(
259  'UPDATE read_event SET ' .
260  'childs_read_count = childs_read_count + %s ,' .
261  'childs_spent_seconds = childs_spent_seconds + %s ' .
262  'WHERE obj_id = %s ' .
263  'AND usr_id = %s ',
264  $ilDB->quote((int) $read_count_diff, 'integer'),
265  $ilDB->quote((int) $time_diff, 'integer'),
266  $ilDB->quote($obj2_id, 'integer'),
267  $ilDB->quote($usr_id, 'integer')
268  );
269  $aff = $ilDB->manipulate($query);
270 
271  self::_recordObjStats(
272  $obj2_id,
273  null,
274  null,
275  (int) $time_diff,
276  (int) $read_count_diff
277  );
278  } else {
279  // #10407
280  $ilDB->replace(
281  'read_event',
282  array(
283  'obj_id' => array('integer', $obj2_id),
284  'usr_id' => array('integer', $usr_id)
285  ),
286  array(
287  'read_count' => array('integer', 1),
288  'spent_seconds' => array('integer', $time),
289  'first_access' => array('timestamp',
290  date("Y-m-d H:i:s")
291  ), // was $ilDB->now()
292  'last_access' => array('integer', time()),
293  'childs_read_count' => array('integer',
294  (int) $read_count_diff
295  ),
296  'childs_spent_seconds' => array('integer',
297  (int) $time_diff
298  )
299  )
300  );
301 
302  self::$has_accessed[$obj2_id][$usr_id] = true;
303 
304  self::_recordObjStats(
305  $obj2_id,
306  $time,
307  1,
308  (int) $time_diff,
309  (int) $read_count_diff
310  );
311  }
312  }
313  }
314  }
315  }
316 
317  // @todo:
318  // - calculate diff of spent_seconds and read_count
319  // - use ref id to get parents of types grp, crs, fold
320  // - add diffs to childs_spent_seconds and childs_read_count
321  }
322 
323  public static function _recordObjStats(
324  int $a_obj_id,
325  ?int $a_spent_seconds,
326  ?int $a_read_count,
327  ?int $a_childs_spent_seconds = null,
328  ?int $a_child_read_count = null
329  ): void {
330  global $DIC;
331 
332  $ilDB = $DIC['ilDB'];
333 
335  $a_obj_id <= 0) { // #12706
336  return;
337  }
338 
339  $now = time();
340 
341  $fields = array();
342  $fields['log_id'] = array("integer", $ilDB->nextId('obj_stat_log'));
343  $fields["obj_id"] = array("integer", $a_obj_id);
344  $fields["obj_type"] = array("text", ilObject::_lookupType($a_obj_id));
345  $fields["tstamp"] = array("timestamp", $now);
346  $fields["yyyy"] = array("integer", date("Y"));
347  $fields["mm"] = array("integer", date("m"));
348  $fields["dd"] = array("integer", date("d"));
349  $fields["hh"] = array("integer", date("H"));
350  if ($a_spent_seconds > 0) {
351  $fields["spent_seconds"] = array("integer", $a_spent_seconds);
352  }
353  if ($a_read_count > 0) {
354  $fields["read_count"] = array("integer", $a_read_count);
355  }
356  if ($a_childs_spent_seconds > 0) {
357  $fields["childs_spent_seconds"] = array("integer",
358  $a_childs_spent_seconds
359  );
360  }
361  if ($a_child_read_count > 0) {
362  $fields["childs_read_count"] = array("integer",
363  $a_child_read_count
364  );
365  }
366  $ilDB->insert("obj_stat_log", $fields);
367 
368  // 0.01% probability
369  if (mt_rand(1, 100) == 1) {
370  self::_syncObjectStats($now);
371  }
372  }
373 
374  public static function _syncObjectStats(
375  ?int $a_now = null,
376  int $a_minimum = 20000
377  ) {
378  global $DIC;
379 
380  $ilDB = $DIC['ilDB'];
381 
382  if (!$a_now) {
383  $a_now = time();
384  }
385 
386  set_time_limit(0);
387 
388  // has source table enough entries?
389  $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
390  $row = $ilDB->fetchAssoc($set);
391  if ($row["counter"] >= $a_minimum) {
392  $ilAtomQuery = $ilDB->buildAtomQuery();
393  $ilAtomQuery->addTableLock('obj_stat_log');
394  $ilAtomQuery->addTableLock('obj_stat_tmp');
395 
396  $ilAtomQuery->addQueryCallable(
397  function (ilDBInterface $ilDB) use ($a_now, $a_minimum, &$ret) {
398  // if other process was transferring, we had to wait for the lock and
399  // the source table should now have less than minimum/needed entries
400  $set = $ilDB->query(
401  "SELECT COUNT(*) AS counter FROM obj_stat_log"
402  );
403  $row = $ilDB->fetchAssoc($set);
404  if ($row["counter"] >= $a_minimum) {
405  // use only "full" seconds to have a clear cut
406  $ilDB->query(
407  "INSERT INTO obj_stat_tmp" .
408  " SELECT * FROM obj_stat_log" .
409  " WHERE tstamp < " . $ilDB->quote(
410  $a_now,
411  "timestamp"
412  )
413  );
414 
415  // remove transferred entries from source table
416  $ilDB->query(
417  "DELETE FROM obj_stat_log" .
418  " WHERE tstamp < " . $ilDB->quote(
419  $a_now,
420  "timestamp"
421  )
422  );
423 
424  $ret = true;
425  } else {
426  $ret = false;
427  }
428  }
429  );
430 
431  $ilAtomQuery->run();
432 
433  //continue only if obj_stat_log counter >= $a_minimum
434  if ($ret) {
435  $ilAtomQuery = $ilDB->buildAtomQuery();
436  $ilAtomQuery->addTableLock('obj_stat_tmp');
437  $ilAtomQuery->addTableLock('obj_stat');
438 
439  $ilAtomQuery->addQueryCallable(
440  function (ilDBInterface $ilDB) use ($a_now, $a_minimum) {
441  // process log data (timestamp is not needed anymore)
442  $sql = "SELECT obj_id, obj_type, yyyy, mm, dd, hh, SUM(read_count) AS read_count," .
443  " SUM(childs_read_count) AS childs_read_count, SUM(spent_seconds) AS spent_seconds," .
444  " SUM(childs_spent_seconds) AS childs_spent_seconds" .
445  " FROM obj_stat_tmp" .
446  " GROUP BY obj_id, obj_type, yyyy, mm, dd, hh";
447  $set = $ilDB->query($sql);
448  while ($row = $ilDB->fetchAssoc($set)) {
449  // "primary key"
450  $where = array("obj_id" => array("integer",
451  $row["obj_id"]
452  ),
453  "obj_type" => array("text",
454  $row["obj_type"]
455  ),
456  "yyyy" => array("integer",
457  $row["yyyy"]
458  ),
459  "mm" => array("integer", $row["mm"]),
460  "dd" => array("integer", $row["dd"]),
461  "hh" => array("integer", $row["hh"])
462  );
463 
464  $where_sql = array();
465  foreach ($where as $field => $def) {
466  $where_sql[] = $field . " = " . $ilDB->quote(
467  $def[1],
468  $def[0]
469  );
470  }
471  $where_sql = implode(" AND ", $where_sql);
472 
473  // existing entry?
474  $check = $ilDB->query(
475  "SELECT read_count, childs_read_count, spent_seconds," .
476  "childs_spent_seconds" .
477  " FROM obj_stat" .
478  " WHERE " . $where_sql
479  );
480  if ($ilDB->numRows($check)) {
481  $old = $ilDB->fetchAssoc($check);
482 
483  // add existing values
484  $fields = array("read_count" => array("integer",
485  $old["read_count"] + $row["read_count"]
486  ),
487  "childs_read_count" => array("integer",
488  $old["childs_read_count"] + $row["childs_read_count"]
489  ),
490  "spent_seconds" => array("integer",
491  $old["spent_seconds"] + $row["spent_seconds"]
492  ),
493  "childs_spent_seconds" => array("integer",
494  $old["childs_spent_seconds"] + $row["childs_spent_seconds"]
495  )
496  );
497 
498  $ilDB->update("obj_stat", $fields, $where);
499  } else {
500  // new entry
501  $fields = $where;
502  $fields["read_count"] = array("integer",
503  $row["read_count"]
504  );
505  $fields["childs_read_count"] = array("integer",
506  $row["childs_read_count"]
507  );
508  $fields["spent_seconds"] = array("integer",
509  $row["spent_seconds"]
510  );
511  $fields["childs_spent_seconds"] = array("integer",
512  $row["childs_spent_seconds"]
513  );
514 
515  $ilDB->insert("obj_stat", $fields);
516  }
517  }
518 
519  // clean up transfer table
520  $ilDB->query("DELETE FROM obj_stat_tmp");
521  }
522  );
523 
524  $ilAtomQuery->run();
525  }
526  }
527  }
528 
541  public static function _catchupWriteEvents(
542  int $obj_id,
543  int $usr_id,
544  ?string $timestamp = null
545  ): void {
546  }
547 
559  public static function _lookupUncaughtWriteEvents(
560  int $obj_id,
561  int $usr_id
562  ): array {
563  return [];
564  }
565 
579  public static function _lookupChangeState(int $obj_id, int $usr_id): int
580  {
581  return 0;
582  }
583 
589  public static function _lookupReadEvents($obj_id, $usr_id = null)
590  {
591  global $DIC;
592 
593  $ilDB = $DIC['ilDB'];
594 
595  if ($usr_id == null) {
596  $query = sprintf(
597  'SELECT * FROM read_event ' .
598  'WHERE obj_id = %s ' .
599  'ORDER BY last_access DESC',
600  $ilDB->quote($obj_id, 'integer')
601  );
602  $res = $ilDB->query($query);
603  } else {
604  $query = sprintf(
605  'SELECT * FROM read_event ' .
606  'WHERE obj_id = %s ' .
607  'AND usr_id = %s ' .
608  'ORDER BY last_access DESC',
609  $ilDB->quote($obj_id, 'integer'),
610  $ilDB->quote($usr_id, 'integer')
611  );
612  $res = $ilDB->query($query);
613  }
614 
615  $counter = 0;
616  $events = [];
617  while ($row = $ilDB->fetchAssoc($res)) {
618  $events[$counter]['obj_id'] = $row['obj_id'];
619  $events[$counter]['usr_id'] = $row['usr_id'];
620  $events[$counter]['last_access'] = $row['last_access'];
621  $events[$counter]['read_count'] = $row['read_count'];
622  $events[$counter]['spent_seconds'] = $row['spent_seconds'];
623  $events[$counter]['first_access'] = $row['first_access'];
624 
625  $counter++;
626  }
627  return $events;
628  }
629 
630  public static function lookupUsersInProgress(int $a_obj_id): array
631  {
632  global $DIC;
633 
634  $ilDB = $DIC['ilDB'];
635 
636  $query = sprintf(
637  'SELECT DISTINCT(usr_id) usr FROM read_event ' .
638  'WHERE obj_id = %s ',
639  $ilDB->quote($a_obj_id, 'integer')
640  );
641  $res = $ilDB->query($query);
642  $users = [];
643  while ($row = $ilDB->fetchObject($res)) {
644  $users[] = (int) $row->usr;
645  }
646  return $users;
647  }
648 
652  public static function hasAccessed(int $a_obj_id, int $a_usr_id): bool
653  {
654  global $DIC;
655 
656  $ilDB = $DIC['ilDB'];
657 
658  if (isset(self::$has_accessed[$a_obj_id][$a_usr_id])) {
659  return self::$has_accessed[$a_obj_id][$a_usr_id];
660  }
661 
662  $set = $ilDB->query(
663  "SELECT usr_id FROM read_event WHERE " .
664  "obj_id = " . $ilDB->quote($a_obj_id, "integer") . " AND " .
665  "usr_id = " . $ilDB->quote($a_usr_id, "integer")
666  );
667  if ($rec = $ilDB->fetchAssoc($set)) {
668  return self::$has_accessed[$a_obj_id][$a_usr_id] = true;
669  }
670  return self::$has_accessed[$a_obj_id][$a_usr_id] = false;
671  }
672 
676  public static function _activate(): bool
677  {
678  if (ilChangeEvent::_isActive()) {
679  return false;
680  } else {
681  global $DIC;
682 
683  $ilDB = $DIC['ilDB'];
684 
685  // Insert initial data into table write_event
686  // We need to do this here, because we need
687  // to catch up write events that occured while the change event tracking was
688  // deactivated.
689 
690  // IGNORE isn't supported in oracle
691  $set = $ilDB->query(
692  sprintf(
693  'SELECT r1.obj_id,r2.obj_id p,d.owner,%s,d.create_date ' .
694  'FROM object_data d ' .
695  'LEFT JOIN write_event w ON d.obj_id = w.obj_id ' .
696  'JOIN object_reference r1 ON d.obj_id=r1.obj_id ' .
697  'JOIN tree t ON t.child=r1.ref_id ' .
698  'JOIN object_reference r2 on r2.ref_id=t.parent ' .
699  'WHERE w.obj_id IS NULL',
700  $ilDB->quote('create', 'text')
701  )
702  );
703  $res = null;
704  while ($rec = $ilDB->fetchAssoc($set)) {
705  $nid = $ilDB->nextId("write_event");
706  $query = 'INSERT INTO write_event ' .
707  '(write_id, obj_id,parent_obj_id,usr_id,action,ts) VALUES (' .
708  $ilDB->quote($nid, "integer") . "," .
709  $ilDB->quote($rec["obj_id"], "integer") . "," .
710  $ilDB->quote($rec["p"], "integer") . "," .
711  $ilDB->quote($rec["owner"], "integer") . "," .
712  $ilDB->quote("create", "text") . "," .
713  $ilDB->quote($rec["create_date"], "timestamp") .
714  ')';
715  $res = $ilDB->query($query);
716  }
717 
718  global $DIC;
719 
720  $ilSetting = $DIC['ilSetting'];
721  $ilSetting->set('enable_change_event_tracking', '1');
722 
723  return $res !== null;
724  }
725  }
726 
730  public static function _deactivate(): bool
731  {
732  global $DIC;
733 
734  $ilSetting = $DIC['ilSetting'];
735  $ilSetting->set('enable_change_event_tracking', '0');
736  return true;
737  }
738 
742  public static function _isActive(): bool
743  {
744  global $DIC;
745 
746  $ilSetting = $DIC['ilSetting'];
747  return $ilSetting->get('enable_change_event_tracking', '0') == '1';
748  }
749 
753  public static function _delete(int $a_obj_id): bool
754  {
755  global $DIC;
756 
757  $ilDB = $DIC['ilDB'];
758  $query = sprintf(
759  'DELETE FROM write_event WHERE obj_id = %s ',
760  $ilDB->quote($a_obj_id, 'integer')
761  );
762  $aff = $ilDB->manipulate($query);
763 
764  $query = sprintf(
765  'DELETE FROM read_event WHERE obj_id = %s ',
766  $ilDB->quote($a_obj_id, 'integer')
767  );
768  $aff = $ilDB->manipulate($query);
769  return true;
770  }
771 
772  public static function _deleteReadEvents(int $a_obj_id): void
773  {
774  global $DIC;
775 
776  $ilDB = $DIC['ilDB'];
777 
778  $ilDB->manipulate(
779  "DELETE FROM read_event" .
780  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer")
781  );
782  }
783 
784  public static function _deleteReadEventsForUsers(
785  int $a_obj_id,
786  array $a_user_ids
787  ): void {
788  global $DIC;
789 
790  $ilDB = $DIC['ilDB'];
791 
792  $ilDB->manipulate(
793  "DELETE FROM read_event" .
794  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer") .
795  " AND " . $ilDB->in("usr_id", $a_user_ids, "", "integer")
796  );
797  }
798 
799  public static function _getAllUserIds(int $a_obj_id): array
800  {
801  global $DIC;
802 
803  $ilDB = $DIC['ilDB'];
804  $res = array();
805  $set = $ilDB->query(
806  "SELECT usr_id FROM read_event" .
807  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer")
808  );
809  while ($row = $ilDB->fetchAssoc($set)) {
810  $res[] = (int) $row["usr_id"];
811  }
812  return $res;
813  }
814 
820  public static function _updateAccessForScormOfflinePlayer(
821  int $obj_id,
822  int $usr_id,
823  int $i_last_access,
824  string $t_first_access
825  ): bool {
826  global $DIC;
827 
828  $ilDB = $DIC->database();
829  $res = $ilDB->queryF(
830  'UPDATE read_event SET first_access=%s, last_access = %s WHERE obj_id=%s AND usr_id=%s',
831  array('timestamp', 'integer', 'integer', 'integer'),
832  array($t_first_access, $i_last_access, $obj_id, $usr_id)
833  );
834  return true;
835  }
836 }
static _delete(int $a_obj_id)
Delete object entries.
$res
Definition: ltiservices.php:69
static _activate()
Activates change event tracking.
numRows(ilDBStatement $statement)
insert(string $table_name, array $values)
static _lookupUncaughtWriteEvents(int $obj_id, int $usr_id)
Reads all write events which occured on the object which happened after the last time the user caught...
fetchAssoc(ilDBStatement $statement)
update(string $table_name, array $values, array $where)
$where MUST contain existing columns only.
static hasAccessed(int $a_obj_id, int $a_usr_id)
Has accessed.
quote($value, string $type)
static _updateAccessForScormOfflinePlayer(int $obj_id, int $usr_id, int $i_last_access, string $t_first_access)
_updateAccessForScormOfflinePlayer needed to synchronize last_access and first_access when learning m...
$path
Definition: ltiservices.php:30
static _syncObjectStats(?int $a_now=null, int $a_minimum=20000)
static _lookupObjId(int $ref_id)
static lookupUsersInProgress(int $a_obj_id)
static _recordReadEvent(string $a_type, int $a_ref_id, int $obj_id, int $usr_id, bool $isCatchupWriteEvents=true, $a_ext_rc=null, $a_ext_time=null)
global $DIC
Definition: shib_login.php:25
static _lookupChangeState(int $obj_id, int $usr_id)
Returns the change state of the object for the specified user.
static _recordWriteEvent(int $obj_id, int $usr_id, string $action, ?int $parent_obj_id=null)
Records a write event.
query(string $query)
Run a (read-only) Query on the database.
static _deleteReadEvents(int $a_obj_id)
static _lookupReadEvents($obj_id, $usr_id=null)
Reads all read events which occured on the object.
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:70
Class ilChangeEvent tracks change events on repository objects.
static _recordObjStats(int $a_obj_id, ?int $a_spent_seconds, ?int $a_read_count, ?int $a_childs_spent_seconds=null, ?int $a_child_read_count=null)
global $ilSetting
Definition: privfeed.php:32
static _isActive()
Returns true, if change event tracking is active.
static _deactivate()
Deactivates change event tracking.
$check
Definition: buildRTE.php:81
static _deleteReadEventsForUsers(int $a_obj_id, array $a_user_ids)
static array $has_accessed
static _lookupType(int $id, bool $reference=false)
static _catchupWriteEvents(int $obj_id, int $usr_id, ?string $timestamp=null)
Catches up with all write events which occured before the specified timestamp.
static _getAllUserIds(int $a_obj_id)