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