ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.ilChangeEvent.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 
37 {
38  private static $has_accessed = array();
39 
55  public static function _recordWriteEvent($obj_id, $usr_id, $action, $parent_obj_id = null)
56  {
57  global $ilDB;
58 
59  /* see _recordReadEvent
60  if (!ilChangeEvent::_isActive())
61  {
62  return;
63  }
64  */
65 
66  if ($parent_obj_id == null) {
67  $pset = $ilDB->query('SELECT r2.obj_id par_obj_id FROM object_reference r1 ' .
68  'JOIN tree t ON t.child = r1.ref_id ' .
69  'JOIN object_reference r2 ON r2.ref_id = t.parent ' .
70  'WHERE r1.obj_id = ' . $ilDB->quote($obj_id, 'integer'));
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 
111  public static function _recordReadEvent(
112  $a_type,
113  $a_ref_id,
114  $obj_id,
115  $usr_id,
116  $isCatchupWriteEvents = true,
117  $a_ext_rc = false,
118  $a_ext_time = false
119  ) {
120  global $ilDB, $tree;
121 
122  /* read_event data is now used for several features, so we are always keeping track
123  if (!ilChangeEvent::_isActive())
124  {
125  return;
126  }
127  */
128 
129  include_once('Services/Tracking/classes/class.ilObjUserTracking.php');
130  $validTimeSpan = ilObjUserTracking::_getValidTimeSpan();
131 
132  $query = sprintf(
133  'SELECT * FROM read_event ' .
134  'WHERE obj_id = %s ' .
135  'AND usr_id = %s ',
136  $ilDB->quote($obj_id, 'integer'),
137  $ilDB->quote($usr_id, 'integer')
138  );
139  $res = $ilDB->query($query);
140  $row = $ilDB->fetchObject($res);
141 
142  // read counter
143  if ($a_ext_rc !== false) {
144  $read_count = 'read_count = ' . $ilDB->quote($a_ext_rc, "integer") . ", ";
145  $read_count_init = max(1, (int) $a_ext_rc);
146  $read_count_diff = max(1, (int) $a_ext_rc) - $row->read_count;
147  } else {
148  $read_count = 'read_count = read_count + 1, ';
149  $read_count_init = 1;
150  $read_count_diff = 1;
151  }
152 
153  if ($row) {
154  if ($a_ext_time !== false) {
155  $time = (int) $a_ext_time;
156  } else {
157  $time = $ilDB->quote((time() - $row->last_access) <= $validTimeSpan
158  ? $row->spent_seconds + time() - $row->last_access
159  : $row->spent_seconds, 'integer');
160 
161  // if we are in the valid interval, we do not
162  // add anything to the read_count, since this is the
163  // same access for us
164  if ((time() - $row->last_access) <= $validTimeSpan) {
165  $read_count = '';
166  $read_count_init = 1;
167  $read_count_diff = 0;
168  }
169  }
170  $time_diff = $time - (int) $row->spent_seconds;
171 
172  // Update
173  $query = sprintf(
174  'UPDATE read_event SET ' .
175  $read_count .
176  'spent_seconds = %s, ' .
177  'last_access = %s ' .
178  'WHERE obj_id = %s ' .
179  'AND usr_id = %s ',
180  $time,
181  $ilDB->quote(time(), 'integer'),
182  $ilDB->quote($obj_id, 'integer'),
183  $ilDB->quote($usr_id, 'integer')
184  );
185  $aff = $ilDB->manipulate($query);
186 
187  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
188  } else {
189  if ($a_ext_time !== false) {
190  $time = (int) $a_ext_time;
191  } else {
192  $time = 0;
193  }
194 
195  $time_diff = $time - (int) $row->spent_seconds;
196 
197  /*
198  $query = sprintf('INSERT INTO read_event (obj_id,usr_id,last_access,read_count,spent_seconds,first_access) '.
199  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().') ',
200  $ilDB->quote($obj_id,'integer'),
201  $ilDB->quote($usr_id,'integer'),
202  $ilDB->quote(time(),'integer'),
203  $ilDB->quote($read_count_init,'integer'),
204  $ilDB->quote($time,'integer'));
205  $ilDB->manipulate($query);
206  */
207 
208  // #10407
209  $ilDB->replace(
210  'read_event',
211  array(
212  'obj_id' => array('integer', $obj_id),
213  'usr_id' => array('integer', $usr_id)
214  ),
215  array(
216  'read_count' => array('integer', $read_count_init),
217  'spent_seconds' => array('integer', $time),
218  'first_access' => array('timestamp', date("Y-m-d H:i:s")), // was $ilDB->now()
219  'last_access' => array('integer', time())
220  )
221  );
222 
223  self::$has_accessed[$obj_id][$usr_id] = true;
224 
225  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
226  }
227 
228  if ($isCatchupWriteEvents) {
229  ilChangeEvent::_catchupWriteEvents($obj_id, $usr_id);
230  }
231 
232  // update parents (no categories or root)
233  if (!in_array($a_type, array("cat", "root", "crs"))) {
234  if ($tree->isInTree($a_ref_id)) {
235  $path = $tree->getPathId($a_ref_id);
236 
237  foreach ($path as $p) {
238  $obj2_id = ilObject::_lookupObjId($p);
239  $obj2_type = ilObject::_lookupType($obj2_id);
240  //echo "<br>1-$obj2_type-$p-$obj2_id-";
241  if (($p != $a_ref_id) && (in_array($obj2_type, array("crs", "fold", "grp")))) {
242  $query = sprintf(
243  'SELECT * FROM read_event ' .
244  'WHERE obj_id = %s ' .
245  'AND usr_id = %s ',
246  $ilDB->quote($obj2_id, 'integer'),
247  $ilDB->quote($usr_id, 'integer')
248  );
249  $res2 = $ilDB->query($query);
250  if ($row2 = $ilDB->fetchAssoc($res2)) {
251  //echo "<br>2";
252  // update read count and spent seconds
253  $query = sprintf(
254  'UPDATE read_event SET ' .
255  'childs_read_count = childs_read_count + %s ,' .
256  'childs_spent_seconds = childs_spent_seconds + %s ' .
257  'WHERE obj_id = %s ' .
258  'AND usr_id = %s ',
259  $ilDB->quote((int) $read_count_diff, 'integer'),
260  $ilDB->quote((int) $time_diff, 'integer'),
261  $ilDB->quote($obj2_id, 'integer'),
262  $ilDB->quote($usr_id, 'integer')
263  );
264  $aff = $ilDB->manipulate($query);
265 
266  self::_recordObjStats($obj2_id, null, null, (int) $time_diff, (int) $read_count_diff);
267  } else {
268  //echo "<br>3";
269  //$ilLog->write("insert read event for obj_id -".$obj2_id."-".$usr_id."-");
270  /*
271  $query = sprintf('INSERT INTO read_event (obj_id,usr_id,last_access,read_count,spent_seconds,first_access,'.
272  'childs_read_count, childs_spent_seconds) '.
273  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().', %s, %s) ',
274  $ilDB->quote($obj2_id,'integer'),
275  $ilDB->quote($usr_id,'integer'),
276  $ilDB->quote(time(),'integer'),
277  $ilDB->quote(1,'integer'),
278  $ilDB->quote($time,'integer'),
279  $ilDB->quote((int) $read_count_diff,'integer'),
280  $ilDB->quote((int) $time_diff,'integer')
281  );
282  $aff = $ilDB->manipulate($query);
283  */
284 
285  // #10407
286  $ilDB->replace(
287  'read_event',
288  array(
289  'obj_id' => array('integer', $obj2_id),
290  'usr_id' => array('integer', $usr_id)
291  ),
292  array(
293  'read_count' => array('integer', 1),
294  'spent_seconds' => array('integer', $time),
295  'first_access' => array('timestamp', date("Y-m-d H:i:s")), // was $ilDB->now()
296  'last_access' => array('integer', time()),
297  'childs_read_count' => array('integer', (int) $read_count_diff),
298  'childs_spent_seconds' => array('integer', (int) $time_diff)
299  )
300  );
301 
302  self::$has_accessed[$obj2_id][$usr_id] = true;
303 
304  self::_recordObjStats($obj2_id, $time, 1, (int) $time_diff, (int) $read_count_diff);
305  }
306  }
307  }
308  }
309  }
310 
311  // @todo:
312  // - calculate diff of spent_seconds and read_count
313  // - use ref id to get parents of types grp, crs, fold
314  // - add diffs to childs_spent_seconds and childs_read_count
315  }
316 
317  public static function _recordObjStats($a_obj_id, $a_spent_seconds, $a_read_count, $a_childs_spent_seconds = null, $a_child_read_count = null)
318  {
319  global $ilDB;
320 
322  (int) $a_obj_id <= 0) { // #12706
323  return;
324  }
325 
326  $now = time();
327 
328  $fields = array();
329  $fields['log_id'] = array("integer", $ilDB->nextId('obj_stat_log'));
330  $fields["obj_id"] = array("integer", $a_obj_id);
331  $fields["obj_type"] = array("text", ilObject::_lookupType($a_obj_id));
332  $fields["tstamp"] = array("timestamp", $now);
333  $fields["yyyy"] = array("integer", date("Y"));
334  $fields["mm"] = array("integer", date("m"));
335  $fields["dd"] = array("integer", date("d"));
336  $fields["hh"] = array("integer", date("H"));
337  if ($a_spent_seconds > 0) {
338  $fields["spent_seconds"] = array("integer", $a_spent_seconds);
339  }
340  if ($a_read_count > 0) {
341  $fields["read_count"] = array("integer", $a_read_count);
342  }
343  if ($a_childs_spent_seconds > 0) {
344  $fields["childs_spent_seconds"] = array("integer", $a_childs_spent_seconds);
345  }
346  if ($a_child_read_count > 0) {
347  $fields["childs_read_count"] = array("integer", $a_child_read_count);
348  }
349  $ilDB->insert("obj_stat_log", $fields);
350 
351  // 0.01% probability
352  if (mt_rand(1, 100) == 1) {
353  self::_syncObjectStats($now);
354  }
355  }
356 
363  public static function _syncObjectStats($a_now = null, $a_minimum = 20000)
364  {
365  global $ilDB;
366 
367  if (!$a_now) {
368  $a_now = time();
369  }
370 
371  set_time_limit(0);
372 
373  // has source table enough entries?
374  $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
375  $row = $ilDB->fetchAssoc($set);
376  if ($row["counter"] >= $a_minimum) {
377  $ilAtomQuery = $ilDB->buildAtomQuery();
378  $ilAtomQuery->addTableLock('obj_stat_log');
379  $ilAtomQuery->addTableLock('obj_stat_tmp');
380 
381  $ilAtomQuery->addQueryCallable(function (ilDBInterface $ilDB) use ($a_now, $a_minimum, &$ret) {
382 
383  // if other process was transferring, we had to wait for the lock and
384  // the source table should now have less than minimum/needed entries
385  $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
386  $row = $ilDB->fetchAssoc($set);
387  if ($row["counter"] >= $a_minimum) {
388  // use only "full" seconds to have a clear cut
389  $ilDB->query("INSERT INTO obj_stat_tmp" .
390  " SELECT * FROM obj_stat_log" .
391  " WHERE tstamp < " . $ilDB->quote($a_now, "timestamp"));
392 
393  // remove transferred entries from source table
394  $ilDB->query("DELETE FROM obj_stat_log" .
395  " WHERE tstamp < " . $ilDB->quote($a_now, "timestamp"));
396 
397  $ret = true;
398  } else {
399  $ret = false;
400  }
401  });
402 
403  $ilAtomQuery->run();
404 
405  //continue only if obj_stat_log counter >= $a_minimum
406  if ($ret) {
407  $ilAtomQuery = $ilDB->buildAtomQuery();
408  $ilAtomQuery->addTableLock('obj_stat_tmp');
409  $ilAtomQuery->addTableLock('obj_stat');
410 
411  $ilAtomQuery->addQueryCallable(function (ilDBInterface $ilDB) use ($a_now, $a_minimum) {
412 
413  // process log data (timestamp is not needed anymore)
414  $sql = "SELECT obj_id, obj_type, yyyy, mm, dd, hh, SUM(read_count) AS read_count," .
415  " SUM(childs_read_count) AS childs_read_count, SUM(spent_seconds) AS spent_seconds," .
416  " SUM(childs_spent_seconds) AS childs_spent_seconds" .
417  " FROM obj_stat_tmp" .
418  " GROUP BY obj_id, obj_type, yyyy, mm, dd, hh";
419  $set = $ilDB->query($sql);
420  while ($row = $ilDB->fetchAssoc($set)) {
421  // "primary key"
422  $where = array("obj_id" => array("integer", $row["obj_id"]),
423  "obj_type" => array("text", $row["obj_type"]),
424  "yyyy" => array("integer", $row["yyyy"]),
425  "mm" => array("integer", $row["mm"]),
426  "dd" => array("integer", $row["dd"]),
427  "hh" => array("integer", $row["hh"]));
428 
429  $where_sql = array();
430  foreach ($where as $field => $def) {
431  $where_sql[] = $field . " = " . $ilDB->quote($def[1], $def[0]);
432  }
433  $where_sql = implode(" AND ", $where_sql);
434 
435  // existing entry?
436  $check = $ilDB->query("SELECT read_count, childs_read_count, spent_seconds," .
437  "childs_spent_seconds" .
438  " FROM obj_stat" .
439  " WHERE " . $where_sql);
440  if ($ilDB->numRows($check)) {
441  $old = $ilDB->fetchAssoc($check);
442 
443  // add existing values
444  $fields = array("read_count" => array("integer", $old["read_count"]+$row["read_count"]),
445  "childs_read_count" => array("integer", $old["childs_read_count"]+$row["childs_read_count"]),
446  "spent_seconds" => array("integer", $old["spent_seconds"]+$row["spent_seconds"]),
447  "childs_spent_seconds" => array("integer", $old["childs_spent_seconds"]+$row["childs_spent_seconds"]));
448 
449  $ilDB->update("obj_stat", $fields, $where);
450  } else {
451  // new entry
452  $fields = $where;
453  $fields["read_count"] = array("integer", $row["read_count"]);
454  $fields["childs_read_count"] = array("integer", $row["childs_read_count"]);
455  $fields["spent_seconds"] = array("integer", $row["spent_seconds"]);
456  $fields["childs_spent_seconds"] = array("integer", $row["childs_spent_seconds"]);
457 
458  $ilDB->insert("obj_stat", $fields);
459  }
460  }
461 
462  // clean up transfer table
463  $ilDB->query("DELETE FROM obj_stat_tmp");
464  });
465 
466  $ilAtomQuery->run();
467  }
468  }
469  }
470 
479  public static function _catchupWriteEvents($obj_id, $usr_id, $timestamp = null)
480  {
481  global $ilDB;
482 
483  $query = "SELECT obj_id FROM catch_write_events " .
484  "WHERE obj_id = " . $ilDB->quote($obj_id, 'integer') . " " .
485  "AND usr_id = " . $ilDB->quote($usr_id, 'integer');
486  $res = $ilDB->query($query);
487  if ($res->numRows()) {
488  $ts = ($timestamp == null)
489  ? ilUtil::now()
490  : $timestamp;
491  /* $query = "UPDATE catch_write_events ".
492  "SET ts = ".($timestamp == null ? $ilDB->now() : $ilDB->quote($timestamp, 'timestamp'))." ".
493  "WHERE usr_id = ".$ilDB->quote($usr_id ,'integer')." ".
494  "AND obj_id = ".$ilDB->quote($obj_id ,'integer');
495  $res = $ilDB->manipulate($query);*/
496  } else {
497  $ts = ilUtil::now();
498  /* $query = "INSERT INTO catch_write_events (ts,obj_id,usr_id) ".
499  "VALUES( ".
500  $ilDB->now().", ".
501  $ilDB->quote($obj_id,'integer').", ".
502  $ilDB->quote($usr_id,'integer')." ".
503  ")";
504  $res = $ilDB->manipulate($query);*/
505  }
506 
507  // alex, use replace due to bug #10406
508  $ilDB->replace(
509  "catch_write_events",
510  array(
511  "obj_id" => array("integer", $obj_id),
512  "usr_id" => array("integer", $usr_id)
513  ),
514  array(
515  "ts" => array("timestamp", $ts))
516  );
517  }
518 
566  public static function _lookupUncaughtWriteEvents($obj_id, $usr_id)
567  {
568  global $ilDB;
569 
570  $q = "SELECT ts " .
571  "FROM catch_write_events " .
572  "WHERE obj_id=" . $ilDB->quote($obj_id, 'integer') . " " .
573  "AND usr_id=" . $ilDB->quote($usr_id, 'integer');
574  $r = $ilDB->query($q);
575  $catchup = null;
576  while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
577  $catchup = $row['ts'];
578  }
579 
580  if ($catchup == null) {
581  $query = sprintf(
582  'SELECT * FROM write_event ' .
583  'WHERE obj_id = %s ' .
584  'AND usr_id <> %s ' .
585  'ORDER BY ts DESC',
586  $ilDB->quote($obj_id, 'integer'),
587  $ilDB->quote($usr_id, 'integer')
588  );
589  $res = $ilDB->query($query);
590  } else {
591  $query = sprintf(
592  'SELECT * FROM write_event ' .
593  'WHERE obj_id = %s ' .
594  'AND usr_id <> %s ' .
595  'AND ts >= %s ' .
596  'ORDER BY ts DESC',
597  $ilDB->quote($obj_id, 'integer'),
598  $ilDB->quote($usr_id, 'integer'),
599  $ilDB->quote($catchup, 'timestamp')
600  );
601  $res = $ilDB->query($query);
602  }
603  $events = array();
604  while ($row = $ilDB->fetchAssoc($res)) {
605  $events[] = $row;
606  }
607  return $events;
608  }
619  public static function _lookupChangeState($obj_id, $usr_id)
620  {
621  global $ilDB;
622 
623  $q = "SELECT ts " .
624  "FROM catch_write_events " .
625  "WHERE obj_id=" . $ilDB->quote($obj_id, 'integer') . " " .
626  "AND usr_id=" . $ilDB->quote($usr_id, 'integer');
627  $r = $ilDB->query($q);
628  $catchup = null;
629  while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
630  $catchup = $row['ts'];
631  }
632 
633  if ($catchup == null) {
634  $ilDB->setLimit(1);
635  $query = sprintf(
636  'SELECT * FROM write_event ' .
637  'WHERE obj_id = %s ' .
638  'AND usr_id <> %s ',
639  $ilDB->quote($obj_id, 'integer'),
640  $ilDB->quote($usr_id, 'integer')
641  );
642  $res = $ilDB->query($query);
643  } else {
644  $ilDB->setLimit(1);
645  $query = sprintf(
646  'SELECT * FROM write_event ' .
647  'WHERE obj_id = %s ' .
648  'AND usr_id <> %s ' .
649  'AND ts > %s ',
650  $ilDB->quote($obj_id, 'integer'),
651  $ilDB->quote($usr_id, 'integer'),
652  $ilDB->quote($catchup, 'timestamp')
653  );
654  $res = $ilDB->query($query);
655  }
656 
657  $numRows = $res->numRows();
658  if ($numRows > 0) {
659  $row = $ilDB->fetchAssoc($res);
660  // if we have write events, and user never catched one, report as new (1)
661  // if we have write events, and user catched an old write event, report as changed (2)
662  return ($catchup == null) ? 1 : 2;
663  } else {
664  return 0; // user catched all write events, report as unchanged (0)
665  }
666  }
667 
712  public static function _lookupReadEvents($obj_id, $usr_id = null)
713  {
714  global $ilDB;
715 
716  if ($usr_id == null) {
717  $query = sprintf(
718  'SELECT * FROM read_event ' .
719  'WHERE obj_id = %s ' .
720  'ORDER BY last_access DESC',
721  $ilDB->quote($obj_id, 'integer')
722  );
723  $res = $ilDB->query($query);
724  } else {
725  $query = sprintf(
726  'SELECT * FROM read_event ' .
727  'WHERE obj_id = %s ' .
728  'AND usr_id = %s ' .
729  'ORDER BY last_access DESC',
730  $ilDB->quote($obj_id, 'integer'),
731  $ilDB->quote($usr_id, 'integer')
732  );
733  $res = $ilDB->query($query);
734  }
735 
736  $counter = 0;
737  while ($row = $ilDB->fetchAssoc($res)) {
738  $events[$counter]['obj_id'] = $row['obj_id'];
739  $events[$counter]['usr_id'] = $row['usr_id'];
740  $events[$counter]['last_access'] = $row['last_access'];
741  $events[$counter]['read_count'] = $row['read_count'];
742  $events[$counter]['spent_seconds'] = $row['spent_seconds'];
743  $events[$counter]['first_access'] = $row['first_access'];
744 
745  $counter++;
746  }
747  return $events ? $events : array();
748  }
749 
756  public static function lookupUsersInProgress($a_obj_id)
757  {
758  global $ilDB;
759 
760  $query = sprintf(
761  'SELECT DISTINCT(usr_id) usr FROM read_event ' .
762  'WHERE obj_id = %s ',
763  $ilDB->quote($a_obj_id, 'integer')
764  );
765  $res = $ilDB->query($query);
766  while ($row = $ilDB->fetchObject($res)) {
767  $users[] = $row->usr;
768  }
769  return $users ? $users : array();
770  }
771 
775  public static function hasAccessed($a_obj_id, $a_usr_id)
776  {
777  global $ilDB;
778 
779  if (isset(self::$has_accessed[$a_obj_id][$a_usr_id])) {
780  return self::$has_accessed[$a_obj_id][$a_usr_id];
781  }
782 
783  $set = $ilDB->query(
784  "SELECT usr_id FROM read_event WHERE " .
785  "obj_id = " . $ilDB->quote($a_obj_id, "integer") . " AND " .
786  "usr_id = " . $ilDB->quote($a_usr_id, "integer")
787  );
788  if ($rec = $ilDB->fetchAssoc($set)) {
789  return self::$has_accessed[$a_obj_id][$a_usr_id] = true;
790  }
791  return self::$has_accessed[$a_obj_id][$a_usr_id] = false;
792  }
793 
799  public static function _activate()
800  {
801  if (ilChangeEvent::_isActive()) {
802  return 'change event tracking is already active';
803  } else {
804  global $ilDB;
805 
806  // Insert initial data into table write_event
807  // We need to do this here, because we need
808  // to catch up write events that occured while the change event tracking was
809  // deactivated.
810 
811  // IGNORE isn't supported in oracle
812  $set = $ilDB->query(sprintf(
813  'SELECT r1.obj_id,r2.obj_id p,d.owner,%s,d.create_date ' .
814  'FROM object_data d ' .
815  'LEFT JOIN write_event w ON d.obj_id = w.obj_id ' .
816  'JOIN object_reference r1 ON d.obj_id=r1.obj_id ' .
817  'JOIN tree t ON t.child=r1.ref_id ' .
818  'JOIN object_reference r2 on r2.ref_id=t.parent ' .
819  'WHERE w.obj_id IS NULL',
820  $ilDB->quote('create', 'text')
821  ));
822  while ($rec = $ilDB->fetchAssoc($set)) {
823  $nid = $ilDB->nextId("write_event");
824  $query = 'INSERT INTO write_event ' .
825  '(write_id, obj_id,parent_obj_id,usr_id,action,ts) VALUES (' .
826  $ilDB->quote($nid, "integer") . "," .
827  $ilDB->quote($rec["obj_id"], "integer") . "," .
828  $ilDB->quote($rec["p"], "integer") . "," .
829  $ilDB->quote($rec["owner"], "integer") . "," .
830  $ilDB->quote("create", "text") . "," .
831  $ilDB->quote($rec["create_date"], "timestamp") .
832  ')';
833  $res = $ilDB->query($query);
834  }
835 
836  global $ilSetting;
837  $ilSetting->set('enable_change_event_tracking', '1');
838 
839  return $res;
840  }
841  }
842 
848  public static function _deactivate()
849  {
850  global $ilSetting;
851  $ilSetting->set('enable_change_event_tracking', '0');
852  }
853 
859  public static function _isActive()
860  {
861  global $ilSetting;
862  return $ilSetting->get('enable_change_event_tracking', '0') == '1';
863  }
864 
871  public static function _delete($a_obj_id)
872  {
873  global $ilDB;
874 
875  $query = sprintf(
876  'DELETE FROM write_event WHERE obj_id = %s ',
877  $ilDB->quote($a_obj_id, 'integer')
878  );
879  $aff = $ilDB->manipulate($query);
880 
881  $query = sprintf(
882  'DELETE FROM read_event WHERE obj_id = %s ',
883  $ilDB->quote($a_obj_id, 'integer')
884  );
885  $aff = $ilDB->manipulate($query);
886  return true;
887  }
888 
889  public static function _deleteReadEvents($a_obj_id)
890  {
891  global $ilDB;
892 
893  $ilDB->manipulate("DELETE FROM read_event" .
894  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer"));
895  }
896 
897  public static function _deleteReadEventsForUsers($a_obj_id, array $a_user_ids)
898  {
899  global $ilDB;
900 
901  $ilDB->manipulate("DELETE FROM read_event" .
902  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer") .
903  " AND " . $ilDB->in("usr_id", $a_user_ids, "", "integer"));
904  }
905 
906  public static function _getAllUserIds($a_obj_id)
907  {
908  global $ilDB;
909 
910  $res = array();
911 
912  $set = $ilDB->query("SELECT usr_id FROM read_event" .
913  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer"));
914  while ($row = $ilDB->fetchAssoc($set)) {
915  $res[] = $row["usr_id"];
916  }
917 
918  return $res;
919  }
920 
927  public static function _updateAccessForScormOfflinePlayer($obj_id, $usr_id, $i_last_access, $t_first_access)
928  {
929  global $ilDB;
930  $res = $ilDB->queryF(
931  'UPDATE read_event SET first_access=%s, last_access = %s WHERE obj_id=%s AND usr_id=%s',
932  array('timestamp','integer','integer','integer'),
933  array($t_first_access,$i_last_access,$obj_id,$usr_id)
934  );
935  return $res;
936  }
937 }
static _recordReadEvent( $a_type, $a_ref_id, $obj_id, $usr_id, $isCatchupWriteEvents=true, $a_ext_rc=false, $a_ext_time=false)
Records a read event and catches up with write events.
static hasAccessed($a_obj_id, $a_usr_id)
Has accessed.
static _activate()
Activates change event tracking.
static _enabledObjectStatistics()
check wether object statistics is enabled or not
$action
static _recordWriteEvent($obj_id, $usr_id, $action, $parent_obj_id=null)
Records a write event.
static _deleteReadEvents($a_obj_id)
static _getAllUserIds($a_obj_id)
static now()
Return current timestamp in Y-m-d H:i:s format.
update($table_name, $values, $where)
static _catchupWriteEvents($obj_id, $usr_id, $timestamp=null)
Catches up with all write events which occured before the specified timestamp.
numRows($query_result)
$counter
$time
Definition: cron.php:21
Interface ilDBInterface.
$a_type
Definition: workflow.php:92
quote($value, $type)
static _delete($a_obj_id)
Delete object entries.
$r
Definition: example_031.php:79
static _updateAccessForScormOfflinePlayer($obj_id, $usr_id, $i_last_access, $t_first_access)
_updateAccessForScormOfflinePlayer needed to synchronize last_access and first_access when learning m...
foreach($_POST as $key=> $value) $res
static _lookupObjId($a_id)
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
$query
$old
static _lookupReadEvents($obj_id, $usr_id=null)
Reads all read events which occured on the object which happened after the last time the user caught ...
Create styles array
The data for the language used.
static _lookupType($a_id, $a_reference=false)
lookup object type
$users
Definition: authpage.php:44
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:81
static _lookupUncaughtWriteEvents($obj_id, $usr_id)
Catches up with all write events which occured before the specified timestamp.
Class ilChangeEvent tracks change events on repository objects.
global $ilSetting
Definition: privfeed.php:17
static _deleteReadEventsForUsers($a_obj_id, array $a_user_ids)
static _isActive()
Returns true, if change event tracking is active.
static _deactivate()
Deactivates change event tracking.
global $ilDB
$ret
Definition: parser.php:6
query($query)
Run a (read-only) Query on the database.
static _recordObjStats($a_obj_id, $a_spent_seconds, $a_read_count, $a_childs_spent_seconds=null, $a_child_read_count=null)
insert($table_name, $values)
fetchAssoc($query_result)
$def
Definition: croninfo.php:21
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
static _syncObjectStats($a_now=null, $a_minimum=20000)
Process object statistics log data.
static _lookupChangeState($obj_id, $usr_id)
Returns the change state of the object for the specified user.
static lookupUsersInProgress($a_obj_id)
Lookup users in progress.