ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
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  static private $has_accessed = array();
39 
55  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  {
68  $pset = $ilDB->query('SELECT r2.obj_id par_obj_id FROM object_reference r1 '.
69  'JOIN tree t ON t.child = r1.ref_id '.
70  'JOIN object_reference r2 ON r2.ref_id = t.parent '.
71  'WHERE r1.obj_id = '.$ilDB->quote($obj_id,'integer'));
72 
73  while ($prec = $ilDB->fetchAssoc($pset))
74  {
75  $nid = $ilDB->nextId("write_event");
76  $query = sprintf('INSERT INTO write_event '.
77  '(write_id, obj_id, parent_obj_id, usr_id, action, ts) VALUES '.
78  '(%s, %s, %s, %s, %s, '.$ilDB->now().')',
79  $ilDB->quote($nid,'integer'),
80  $ilDB->quote($obj_id,'integer'),
81  $ilDB->quote($prec["par_obj_id"],'integer'),
82  $ilDB->quote($usr_id,'integer'),
83  $ilDB->quote($action,'text'));
84 
85  $aff = $ilDB->manipulate($query);
86  }
87  }
88  else
89  {
90  $nid = $ilDB->nextId("write_event");
91  $query = sprintf('INSERT INTO write_event '.
92  '(write_id, obj_id, parent_obj_id, usr_id, action, ts) '.
93  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().')',
94  $ilDB->quote($nid,'integer'),
95  $ilDB->quote($obj_id,'integer'),
96  $ilDB->quote($parent_obj_id,'integer'),
97  $ilDB->quote($usr_id,'integer'),
98  $ilDB->quote($action,'text'));
99  $aff = $ilDB->manipulate($query);
100 
101  }
102  //error_log ('ilChangeEvent::_recordWriteEvent '.$q);
103  }
104 
113  function _recordReadEvent($a_type, $a_ref_id, $obj_id, $usr_id,
114  $isCatchupWriteEvents = true, $a_ext_rc = false, $a_ext_time = false)
115  {
116  global $ilDB, $tree;
117 
118  /* read_event data is now used for several features, so we are always keeping track
119  if (!ilChangeEvent::_isActive())
120  {
121  return;
122  }
123  */
124 
125  include_once('Services/Tracking/classes/class.ilObjUserTracking.php');
126  $validTimeSpan = ilObjUserTracking::_getValidTimeSpan();
127 
128  $query = sprintf('SELECT * FROM read_event '.
129  'WHERE obj_id = %s '.
130  'AND usr_id = %s ',
131  $ilDB->quote($obj_id,'integer'),
132  $ilDB->quote($usr_id,'integer'));
133  $res = $ilDB->query($query);
134  $row = $ilDB->fetchObject($res);
135 
136  // read counter
137  if ($a_ext_rc !== false)
138  {
139  $read_count = 'read_count = '.$ilDB->quote($a_ext_rc, "integer").", ";
140  $read_count_init = max(1, (int) $a_ext_rc);
141  $read_count_diff = max(1, (int) $a_ext_rc) - $row->read_count;
142  }
143  else
144  {
145  $read_count = 'read_count = read_count + 1, ';
146  $read_count_init = 1;
147  $read_count_diff = 1;
148  }
149 
150  if ($row)
151  {
152 
153  if ($a_ext_time !== false)
154  {
155  $time = (int) $a_ext_time;
156  }
157  else
158  {
159  $time = $ilDB->quote((time() - $row->last_access) <= $validTimeSpan
160  ? $row->spent_seconds + time() - $row->last_access
161  : $row->spent_seconds,'integer');
162 
163  // if we are in the valid interval, we do not
164  // add anything to the read_count, since this is the
165  // same access for us
166  if ((time() - $row->last_access) <= $validTimeSpan)
167  {
168  $read_count = '';
169  $read_count_init = 1;
170  $read_count_diff = 0;
171  }
172  }
173  $time_diff = $time - (int) $row->spent_seconds;
174 
175  // Update
176  $query = sprintf('UPDATE read_event SET '.
177  $read_count.
178  'spent_seconds = %s, '.
179  'last_access = %s '.
180  'WHERE obj_id = %s '.
181  'AND usr_id = %s ',
182  $time,
183  $ilDB->quote(time(),'integer'),
184  $ilDB->quote($obj_id,'integer'),
185  $ilDB->quote($usr_id,'integer'));
186  $aff = $ilDB->manipulate($query);
187 
188  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
189  }
190  else
191  {
192  if ($a_ext_time !== false)
193  {
194  $time = (int) $a_ext_time;
195  }
196  else
197  {
198  $time = 0;
199  }
200 
201  $time_diff = $time - (int) $row->spent_seconds;
202 
203  /*
204  $query = sprintf('INSERT INTO read_event (obj_id,usr_id,last_access,read_count,spent_seconds,first_access) '.
205  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().') ',
206  $ilDB->quote($obj_id,'integer'),
207  $ilDB->quote($usr_id,'integer'),
208  $ilDB->quote(time(),'integer'),
209  $ilDB->quote($read_count_init,'integer'),
210  $ilDB->quote($time,'integer'));
211  $ilDB->manipulate($query);
212  */
213 
214  // #10407
215  $ilDB->replace('read_event',
216  array(
217  'obj_id' => array('integer', $obj_id),
218  'usr_id' => array('integer', $usr_id)
219  ),
220  array(
221  'read_count' => array('integer', $read_count_init),
222  'spent_seconds' => array('integer', $time),
223  'first_access' => array('timestamp', date("Y-m-d H:i:s")), // was $ilDB->now()
224  'last_access' => array('integer', time())
225  )
226  );
227 
228  self::$has_accessed[$obj_id][$usr_id] = true;
229 
230  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
231  }
232 
233  if ($isCatchupWriteEvents)
234  {
235  ilChangeEvent::_catchupWriteEvents($obj_id, $usr_id);
236  }
237 
238  // update parents (no categories or root)
239  if (!in_array($a_type, array("cat", "root", "crs")))
240  {
241  if ($tree->isInTree($a_ref_id))
242  {
243  $path = $tree->getPathId($a_ref_id);
244 
245  foreach ($path as $p)
246  {
247  $obj2_id = ilObject::_lookupObjId($p);
248  $obj2_type = ilObject::_lookupType($obj2_id);
249 //echo "<br>1-$obj2_type-$p-$obj2_id-";
250  if (($p != $a_ref_id) && (in_array($obj2_type, array("crs", "fold", "grp"))))
251  {
252  $query = sprintf('SELECT * FROM read_event '.
253  'WHERE obj_id = %s '.
254  'AND usr_id = %s ',
255  $ilDB->quote($obj2_id, 'integer'),
256  $ilDB->quote($usr_id, 'integer'));
257  $res2 = $ilDB->query($query);
258  if ($row2 = $ilDB->fetchAssoc($res2))
259  {
260 //echo "<br>2";
261  // update read count and spent seconds
262  $query = sprintf('UPDATE read_event SET '.
263  'childs_read_count = childs_read_count + %s ,'.
264  'childs_spent_seconds = childs_spent_seconds + %s '.
265  'WHERE obj_id = %s '.
266  'AND usr_id = %s ',
267  $ilDB->quote((int) $read_count_diff,'integer'),
268  $ilDB->quote((int) $time_diff,'integer'),
269  $ilDB->quote($obj2_id,'integer'),
270  $ilDB->quote($usr_id,'integer'));
271  $aff = $ilDB->manipulate($query);
272 
273  self::_recordObjStats($obj2_id, null, null, (int)$time_diff, (int)$read_count_diff);
274  }
275  else
276  {
277 //echo "<br>3";
278 //$ilLog->write("insert read event for obj_id -".$obj2_id."-".$usr_id."-");
279  /*
280  $query = sprintf('INSERT INTO read_event (obj_id,usr_id,last_access,read_count,spent_seconds,first_access,'.
281  'childs_read_count, childs_spent_seconds) '.
282  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().', %s, %s) ',
283  $ilDB->quote($obj2_id,'integer'),
284  $ilDB->quote($usr_id,'integer'),
285  $ilDB->quote(time(),'integer'),
286  $ilDB->quote(1,'integer'),
287  $ilDB->quote($time,'integer'),
288  $ilDB->quote((int) $read_count_diff,'integer'),
289  $ilDB->quote((int) $time_diff,'integer')
290  );
291  $aff = $ilDB->manipulate($query);
292  */
293 
294  // #10407
295  $ilDB->replace('read_event',
296  array(
297  'obj_id' => array('integer', $obj2_id),
298  'usr_id' => array('integer', $usr_id)
299  ),
300  array(
301  'read_count' => array('integer', 1),
302  'spent_seconds' => array('integer', $time),
303  'first_access' => array('timestamp', date("Y-m-d H:i:s")), // was $ilDB->now()
304  'last_access' => array('integer', time()),
305  'childs_read_count' => array('integer', (int)$read_count_diff),
306  'childs_spent_seconds' => array('integer', (int)$time_diff)
307  )
308  );
309 
310  self::$has_accessed[$obj2_id][$usr_id] = true;
311 
312  self::_recordObjStats($obj2_id, $time, 1, (int)$time_diff, (int)$read_count_diff);
313  }
314  }
315  }
316  }
317  }
318 
319  // @todo:
320  // - calculate diff of spent_seconds and read_count
321  // - use ref id to get parents of types grp, crs, fold
322  // - add diffs to childs_spent_seconds and childs_read_count
323  }
324 
325  function _recordObjStats($a_obj_id, $a_spent_seconds, $a_read_count, $a_childs_spent_seconds = null, $a_child_read_count = null)
326  {
327  global $ilDB;
328 
330  (int)$a_obj_id <= 0) // #12706
331  {
332  return;
333  }
334 
335  $now = time();
336 
337  $fields = array();
338  $fields["obj_id"] = array("integer", $a_obj_id);
339  $fields["obj_type"] = array("text", ilObject::_lookupType($a_obj_id));
340  $fields["tstamp"] = array("timestamp", $now);
341  $fields["yyyy"] = array("integer", date("Y"));
342  $fields["mm"] = array("integer", date("m"));
343  $fields["dd"] = array("integer", date("d"));
344  $fields["hh"] = array("integer", date("H"));
345  if($a_spent_seconds > 0)
346  {
347  $fields["spent_seconds"] = array("integer", $a_spent_seconds);
348  }
349  if($a_read_count > 0)
350  {
351  $fields["read_count"] = array("integer", $a_read_count);
352  }
353  if($a_childs_spent_seconds > 0)
354  {
355  $fields["childs_spent_seconds"] = array("integer", $a_childs_spent_seconds);
356  }
357  if($a_child_read_count > 0)
358  {
359  $fields["childs_read_count"] = array("integer", $a_child_read_count);
360  }
361  $ilDB->insert("obj_stat_log", $fields);
362 
363  // 0.01% probability
364  if(mt_rand(1, 100) == 1)
365  {
367  }
368  }
369 
376  function _syncObjectStats($a_now = null, $a_minimum = 20000)
377  {
378  global $ilDB;
379 
380  if(!$a_now)
381  {
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  {
392  // lock source and transfer table
393  $ilDB->lockTables(array(array("name"=>"obj_stat_log", "type"=>ilDB::LOCK_WRITE),
394  array("name"=>"obj_stat_tmp", "type"=>ilDB::LOCK_WRITE)));
395 
396  // if other process was transferring, we had to wait for the lock and
397  // the source table should now have less than minimum/needed entries
398  $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
399  $row = $ilDB->fetchAssoc($set);
400  if($row["counter"] >= $a_minimum)
401  {
402  // use only "full" seconds to have a clear cut
403  $ilDB->query("INSERT INTO obj_stat_tmp".
404  " SELECT * FROM obj_stat_log".
405  " WHERE tstamp < ".$ilDB->quote($a_now, "timestamp"));
406 
407  // remove transferred entries from source table
408  $ilDB->query("DELETE FROM obj_stat_log".
409  " WHERE tstamp < ".$ilDB->quote($a_now, "timestamp"));
410 
411  // remove lock from source table
412  $ilDB->unlockTables();
413 
414  // lock transfer and target table (is this needed?)
415  $ilDB->lockTables(array(array("name"=>"obj_stat_tmp", "type"=>ilDB::LOCK_WRITE),
416  array("name"=>"obj_stat", "type"=>ilDB::LOCK_WRITE)));
417 
418  // process log data (timestamp is not needed anymore)
419  $sql = "SELECT obj_id, obj_type, yyyy, mm, dd, hh, SUM(read_count) AS read_count,".
420  " SUM(childs_read_count) AS childs_read_count, SUM(spent_seconds) AS spent_seconds,".
421  " SUM(childs_spent_seconds) AS childs_spent_seconds".
422  " FROM obj_stat_tmp".
423  " GROUP BY obj_id, obj_type, yyyy, mm, dd, hh";
424  $set = $ilDB->query($sql);
425  while($row = $ilDB->fetchAssoc($set))
426  {
427  // "primary key"
428  $where = array("obj_id" => array("integer", $row["obj_id"]),
429  "obj_type" => array("text", $row["obj_type"]),
430  "yyyy" => array("integer", $row["yyyy"]),
431  "mm" => array("integer", $row["mm"]),
432  "dd" => array("integer", $row["dd"]),
433  "hh" => array("integer", $row["hh"]));
434 
435  $where_sql = array();
436  foreach($where as $field => $def)
437  {
438  $where_sql[] = $field." = ".$ilDB->quote($def[1], $def[0]);
439  }
440  $where_sql = implode(" AND ", $where_sql);
441 
442  // existing entry?
443  $check = $ilDB->query("SELECT read_count, childs_read_count, spent_seconds,".
444  "childs_spent_seconds".
445  " FROM obj_stat".
446  " WHERE ".$where_sql);
447  if($ilDB->numRows($check))
448  {
449  $old = $ilDB->fetchAssoc($check);
450 
451  // add existing values
452  $fields = array("read_count" => array("integer", $old["read_count"]+$row["read_count"]),
453  "childs_read_count" => array("integer", $old["childs_read_count"]+$row["childs_read_count"]),
454  "spent_seconds" => array("integer", $old["spent_seconds"]+$row["spent_seconds"]),
455  "childs_spent_seconds" => array("integer", $old["childs_spent_seconds"]+$row["childs_spent_seconds"]));
456 
457  $ilDB->update("obj_stat", $fields, $where);
458  }
459  else
460  {
461  // new entry
462  $fields = $where;
463  $fields["read_count"] = array("integer", $row["read_count"]);
464  $fields["childs_read_count"] = array("integer", $row["childs_read_count"]);
465  $fields["spent_seconds"] = array("integer", $row["spent_seconds"]);
466  $fields["childs_spent_seconds"] = array("integer", $row["childs_spent_seconds"]);
467 
468  $ilDB->insert("obj_stat", $fields);
469  }
470  }
471 
472  // clean up transfer table
473  $ilDB->query("DELETE FROM obj_stat_tmp");
474  }
475 
476  // remove all locks (does not matter if transfer was actually performed)
477  $ilDB->unlockTables();
478  }
479  }
480 
489  function _catchupWriteEvents($obj_id, $usr_id, $timestamp = null)
490  {
491  global $ilDB;
492 
493  $query = "SELECT obj_id FROM catch_write_events ".
494  "WHERE obj_id = ".$ilDB->quote($obj_id ,'integer')." ".
495  "AND usr_id = ".$ilDB->quote($usr_id ,'integer');
496  $res = $ilDB->query($query);
497  if($res->numRows())
498  {
499  $ts = ($timestamp == null)
500  ? ilUtil::now()
501  : $timestamp;
502 /* $query = "UPDATE catch_write_events ".
503  "SET ts = ".($timestamp == null ? $ilDB->now() : $ilDB->quote($timestamp, 'timestamp'))." ".
504  "WHERE usr_id = ".$ilDB->quote($usr_id ,'integer')." ".
505  "AND obj_id = ".$ilDB->quote($obj_id ,'integer');
506  $res = $ilDB->manipulate($query);*/
507  }
508  else
509  {
510  $ts = ilUtil::now();
511 /* $query = "INSERT INTO catch_write_events (ts,obj_id,usr_id) ".
512  "VALUES( ".
513  $ilDB->now().", ".
514  $ilDB->quote($obj_id,'integer').", ".
515  $ilDB->quote($usr_id,'integer')." ".
516  ")";
517  $res = $ilDB->manipulate($query);*/
518  }
519 
520  // alex, use replace due to bug #10406
521  $ilDB->replace("catch_write_events",
522  array(
523  "obj_id" => array("integer", $obj_id),
524  "usr_id" => array("integer", $usr_id)
525  ),
526  array(
527  "ts" => array("timestamp", $ts))
528  );
529  }
530 
578  public static function _lookupUncaughtWriteEvents($obj_id, $usr_id)
579  {
580  global $ilDB;
581 
582  $q = "SELECT ts ".
583  "FROM catch_write_events ".
584  "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
585  "AND usr_id=".$ilDB->quote($usr_id ,'integer');
586  $r = $ilDB->query($q);
587  $catchup = null;
588  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
589  $catchup = $row['ts'];
590  }
591 
592  if($catchup == null)
593  {
594  $query = sprintf('SELECT * FROM write_event '.
595  'WHERE obj_id = %s '.
596  'AND usr_id <> %s '.
597  'ORDER BY ts DESC',
598  $ilDB->quote($obj_id,'integer'),
599  $ilDB->quote($usr_id,'integer'));
600  $res = $ilDB->query($query);
601  }
602  else
603  {
604  $query = sprintf('SELECT * FROM write_event '.
605  'WHERE obj_id = %s '.
606  'AND usr_id <> %s '.
607  'AND ts >= %s '.
608  'ORDER BY ts DESC',
609  $ilDB->quote($obj_id,'integer'),
610  $ilDB->quote($usr_id,'integer'),
611  $ilDB->quote($catchup,'timestamp'));
612  $res = $ilDB->query($query);
613  }
614  $events = array();
615  while($row = $ilDB->fetchAssoc($res))
616  {
617  $events[] = $row;
618  }
619  return $events;
620  }
631  public static function _lookupChangeState($obj_id, $usr_id)
632  {
633  global $ilDB;
634 
635  $q = "SELECT ts ".
636  "FROM catch_write_events ".
637  "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
638  "AND usr_id=".$ilDB->quote($usr_id ,'integer');
639  $r = $ilDB->query($q);
640  $catchup = null;
641  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
642  $catchup = $row['ts'];
643  }
644 
645  if($catchup == null)
646  {
647  $ilDB->setLimit(1);
648  $query = sprintf('SELECT * FROM write_event '.
649  'WHERE obj_id = %s '.
650  'AND usr_id <> %s ',
651  $ilDB->quote($obj_id,'integer'),
652  $ilDB->quote($usr_id,'integer'));
653  $res = $ilDB->query($query);
654  }
655  else
656  {
657  $ilDB->setLimit(1);
658  $query = sprintf('SELECT * FROM write_event '.
659  'WHERE obj_id = %s '.
660  'AND usr_id <> %s '.
661  'AND ts > %s ',
662  $ilDB->quote($obj_id,'integer'),
663  $ilDB->quote($usr_id,'integer'),
664  $ilDB->quote($catchup,'timestamp'));
665  $res = $ilDB->query($query);
666  }
667 
668  $numRows = $res->numRows();
669  if ($numRows > 0)
670  {
671  $row = $ilDB->fetchAssoc($res);
672  // if we have write events, and user never catched one, report as new (1)
673  // if we have write events, and user catched an old write event, report as changed (2)
674  return ($catchup == null) ? 1 : 2;
675  }
676  else
677  {
678  return 0; // user catched all write events, report as unchanged (0)
679  }
680  }
696  public static function _lookupInsideChangeState($parent_obj_id, $usr_id)
697  {
698  global $ilDB;
699 
700  $q = "SELECT ts ".
701  "FROM catch_write_events ".
702  "WHERE obj_id=".$ilDB->quote($parent_obj_id)." ".
703  "AND usr_id=".$ilDB->quote($usr_id);
704  $r = $ilDB->query($q);
705  $catchup = null;
706  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
707  $catchup = $row['ts'];
708  }
709 
710  if($catchup == null)
711  {
712  $ilDB->setLimit(1);
713  $query = sprintf('SELECT * FROM write_event '.
714  'WHERE parent_obj_id = %s '.
715  'AND usr_id <> %s ',
716  $ilDB->quote($parent_obj_id,'integer'),
717  $ilDB->quote($usr_id,'integer'));
718  $res = $ilDB->query($query);
719  }
720  else
721  {
722  $ilDB->setLimit(1);
723  $query = sprintf('SELECT * FROM write_event '.
724  'WHERE parent_obj_id = %s '.
725  'AND usr_id <> %s '.
726  'AND ts > %s ',
727  $ilDB->quote($parent_obj_id,'integer'),
728  $ilDB->quote($usr_id,'integer'),
729  $ilDB->quote($catchup,'timestamp'));
730  $res = $ilDB->query($query);
731  }
732  $numRows = $res->numRows();
733  if ($numRows > 0)
734  {
735  $row = $ilDB->fetchAssoc($res);
736  // if we have write events, and user never catched one, report as new (1)
737  // if we have write events, and user catched an old write event, report as changed (2)
738  return ($catchup == null) ? 1 : 2;
739  }
740  else
741  {
742  return 0; // user catched all write events, report as unchanged (0)
743  }
744  }
789  public static function _lookupReadEvents($obj_id, $usr_id = null)
790  {
791  global $ilDB;
792 
793  if ($usr_id == null)
794  {
795  $query = sprintf('SELECT * FROM read_event '.
796  'WHERE obj_id = %s '.
797  'ORDER BY last_access DESC',
798  $ilDB->quote($obj_id,'integer'));
799  $res = $ilDB->query($query);
800  }
801  else
802  {
803  $query = sprintf('SELECT * FROM read_event '.
804  'WHERE obj_id = %s '.
805  'AND usr_id = %s '.
806  'ORDER BY last_access DESC',
807  $ilDB->quote($obj_id,'integer'),
808  $ilDB->quote($usr_id,'integer'));
809  $res = $ilDB->query($query);
810  }
811 
812  $counter = 0;
813  while ($row = $ilDB->fetchAssoc($res))
814  {
815  $events[$counter]['obj_id'] = $row['obj_id'];
816  $events[$counter]['usr_id'] = $row['usr_id'];
817  $events[$counter]['last_access'] = $row['last_access'];
818  $events[$counter]['read_count'] = $row['read_count'];
819  $events[$counter]['spent_seconds'] = $row['spent_seconds'];
820  $events[$counter]['first_access'] = $row['first_access'];
821 
822  $counter++;
823 
824  }
825  return $events ? $events : array();
826  }
827 
834  public static function lookupUsersInProgress($a_obj_id)
835  {
836  global $ilDB;
837 
838  $query = sprintf('SELECT DISTINCT(usr_id) usr FROM read_event '.
839  'WHERE obj_id = %s ',
840  $ilDB->quote($a_obj_id,'integer'));
841  $res = $ilDB->query($query);
842  while($row = $ilDB->fetchObject($res))
843  {
844  $users[] = $row->usr;
845  }
846  return $users ? $users : array();
847  }
848 
852  static function hasAccessed($a_obj_id, $a_usr_id)
853  {
854  global $ilDB;
855 
856  if (isset(self::$has_accessed[$a_obj_id][$a_usr_id]))
857  {
858  return self::$has_accessed[$a_obj_id][$a_usr_id];
859  }
860 
861  $set = $ilDB->query("SELECT usr_id FROM read_event WHERE ".
862  "obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
863  "usr_id = ".$ilDB->quote($a_usr_id, "integer")
864  );
865  if ($rec = $ilDB->fetchAssoc($set))
866  {
867  return self::$has_accessed[$a_obj_id][$a_usr_id] = true;
868  }
869  return self::$has_accessed[$a_obj_id][$a_usr_id] = false;
870  }
871 
877  public static function _activate() {
879  {
880  return 'change event tracking is already active';
881  }
882  else
883  {
884  global $ilDB;
885 
886  // Insert initial data into table write_event
887  // We need to do this here, because we need
888  // to catch up write events that occured while the change event tracking was
889  // deactivated.
890 
891  // IGNORE isn't supported in oracle
892  $set = $ilDB->query(sprintf('SELECT r1.obj_id,r2.obj_id p,d.owner,%s,d.create_date '.
893  'FROM object_data d '.
894  'LEFT JOIN write_event w ON d.obj_id = w.obj_id '.
895  'JOIN object_reference r1 ON d.obj_id=r1.obj_id '.
896  'JOIN tree t ON t.child=r1.ref_id '.
897  'JOIN object_reference r2 on r2.ref_id=t.parent '.
898  'WHERE w.obj_id IS NULL',
899  $ilDB->quote('create','text')));
900  while ($rec = $ilDB->fetchAssoc($set))
901  {
902  $nid = $ilDB->nextId("write_event");
903  $query = 'INSERT INTO write_event '.
904  '(write_id, obj_id,parent_obj_id,usr_id,action,ts) VALUES ('.
905  $ilDB->quote($nid, "integer").",".
906  $ilDB->quote($rec["obj_id"], "integer").",".
907  $ilDB->quote($rec["p"], "integer").",".
908  $ilDB->quote($rec["owner"], "integer").",".
909  $ilDB->quote("create", "text").",".
910  $ilDB->quote($rec["create_date"], "timestamp").
911  ')';
912  $res = $ilDB->query($query);
913  }
914 
915  if ($ilDB->isError($res) || $ilDB->isError($res->result))
916  {
917  return 'couldn\'t insert initial data into table "write_event": '.
918  (($ilDB->isError($r->result)) ? $r->result->getMessage() : $r->getMessage());
919  }
920 
921 
922  global $ilias;
923  $ilias->setSetting('enable_change_event_tracking', '1');
924 
925  return $res;
926  }
927  }
928 
934  public static function _deactivate() {
935  global $ilias;
936  $ilias->setSetting('enable_change_event_tracking', '0');
937 
938  }
939 
945  public static function _isActive() {
946  global $ilias;
947  return $ilias->getSetting('enable_change_event_tracking', '0') == '1';
948 
949  }
950 
957  public static function _delete($a_obj_id)
958  {
959  global $ilDB;
960 
961  $query = sprintf('DELETE FROM write_event WHERE obj_id = %s ',
962  $ilDB->quote($a_obj_id,'integer'));
963  $aff = $ilDB->manipulate($query);
964 
965  $query = sprintf('DELETE FROM read_event WHERE obj_id = %s ',
966  $ilDB->quote($a_obj_id,'integer'));
967  $aff = $ilDB->manipulate($query);
968  return true;
969  }
970 
971  public static function _deleteReadEvents($a_obj_id)
972  {
973  global $ilDB;
974 
975  $ilDB->manipulate("DELETE FROM read_event".
976  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer"));
977  }
978 
979  public static function _deleteReadEventsForUsers($a_obj_id, array $a_user_ids)
980  {
981  global $ilDB;
982 
983  $ilDB->manipulate("DELETE FROM read_event".
984  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer").
985  " AND ".$ilDB->in("usr_id", $a_user_ids, "", "integer"));
986  }
987 
988  public static function _getAllUserIds($a_obj_id)
989  {
990  global $ilDB;
991 
992  $res = array();
993 
994  $set = $ilDB->query("SELECT usr_id FROM read_event".
995  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer"));
996  while($row = $ilDB->fetchAssoc($set))
997  {
998  $res[] = $row["usr_id"];
999  }
1000 
1001  return $res;
1002  }
1003 
1010  function _updateAccessForScormOfflinePlayer($obj_id, $usr_id, $i_last_access, $t_first_access) {
1011  global $ilDB;
1012  $res = $ilDB->queryF('UPDATE read_event SET first_access=%s, last_access = %s WHERE obj_id=%s AND usr_id=%s',
1013  array('timestamp','integer','integer','integer'),
1014  array($t_first_access,$i_last_access,$obj_id,$usr_id)
1015  );
1016  return $res;
1017  }
1018 }
1019 
1020 ?>