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