ILIAS  Release_4_1_x_branch Revision 61804
 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  if ($parent_obj_id == null)
60  {
61  $pset = $ilDB->query('SELECT r2.obj_id par_obj_id FROM object_reference r1 '.
62  'JOIN tree t ON t.child = r1.ref_id '.
63  'JOIN object_reference r2 ON r2.ref_id = t.parent '.
64  'WHERE r1.obj_id = '.$ilDB->quote($obj_id,'integer'));
65 
66  while ($prec = $ilDB->fetchAssoc($pset))
67  {
68  $nid = $ilDB->nextId("write_event");
69  $query = sprintf('INSERT INTO write_event '.
70  '(write_id, obj_id, parent_obj_id, usr_id, action, ts) VALUES '.
71  '(%s, %s, %s, %s, %s, '.$ilDB->now().')',
72  $ilDB->quote($nid,'integer'),
73  $ilDB->quote($obj_id,'integer'),
74  $ilDB->quote($prec["par_obj_id"],'integer'),
75  $ilDB->quote($usr_id,'integer'),
76  $ilDB->quote($action,'text'));
77 
78  $aff = $ilDB->manipulate($query);
79  }
80  }
81  else
82  {
83  $nid = $ilDB->nextId("write_event");
84  $query = sprintf('INSERT INTO write_event '.
85  '(write_id, obj_id, parent_obj_id, usr_id, action, ts) '.
86  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().')',
87  $ilDB->quote($nid,'integer'),
88  $ilDB->quote($obj_id,'integer'),
89  $ilDB->quote($parent_obj_id,'integer'),
90  $ilDB->quote($usr_id,'integer'),
91  $ilDB->quote($action,'text'));
92  $aff = $ilDB->manipulate($query);
93 
94  }
95  //error_log ('ilChangeEvent::_recordWriteEvent '.$q);
96  }
97 
106  function _recordReadEvent($a_type, $a_ref_id, $obj_id, $usr_id,
107  $isCatchupWriteEvents = true, $a_ext_rc = false, $a_ext_time = false)
108  {
109  global $ilDB, $tree;
110 
111  include_once('Services/Tracking/classes/class.ilObjUserTracking.php');
112  $validTimeSpan = ilObjUserTracking::_getValidTimeSpan();
113 
114  $query = sprintf('SELECT * FROM read_event '.
115  'WHERE obj_id = %s '.
116  'AND usr_id = %s ',
117  $ilDB->quote($obj_id,'integer'),
118  $ilDB->quote($usr_id,'integer'));
119  $res = $ilDB->query($query);
120  $row = $ilDB->fetchObject($res);
121 
122  // read counter
123  if ($a_ext_rc !== false)
124  {
125  $read_count = 'read_count = '.$ilDB->quote($a_ext_rc, "integer").", ";
126  $read_count_init = max(1, (int) $a_ext_rc);
127  $read_count_diff = max(1, (int) $a_ext_rc) - $row->read_count;
128  }
129  else
130  {
131  $read_count = 'read_count = read_count + 1, ';
132  $read_count_init = 1;
133  $read_count_diff = 1;
134  }
135 
136  if ($row)
137  {
138 
139  if ($a_ext_time !== false)
140  {
141  $time = (int) $a_ext_time;
142  }
143  else
144  {
145  $time = $ilDB->quote((time() - $row->last_access) <= $validTimeSpan
146  ? $row->spent_seconds + time() - $row->last_access
147  : $row->spent_seconds,'integer');
148  }
149  $time_diff = $time - (int) $row->spent_seconds;
150 
151  // Update
152  $query = sprintf('UPDATE read_event SET '.
153  $read_count.
154  'spent_seconds = %s, '.
155  'last_access = %s '.
156  'WHERE obj_id = %s '.
157  'AND usr_id = %s ',
158  $time,
159  $ilDB->quote(time(),'integer'),
160  $ilDB->quote($obj_id,'integer'),
161  $ilDB->quote($usr_id,'integer'));
162  $aff = $ilDB->manipulate($query);
163  }
164  else
165  {
166  if ($a_ext_time !== false)
167  {
168  $time = (int) $a_ext_time;
169  }
170  else
171  {
172  $time = 0;
173  }
174 
175  $time_diff = $time - (int) $row->spent_seconds;
176 
177  $query = sprintf('INSERT INTO read_event (obj_id,usr_id,last_access,read_count,spent_seconds,first_access) '.
178  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().') ',
179  $ilDB->quote($obj_id,'integer'),
180  $ilDB->quote($usr_id,'integer'),
181  $ilDB->quote(time(),'integer'),
182  $ilDB->quote($read_count_init,'integer'),
183  $ilDB->quote($time,'integer'));
184 
185  $aff = $ilDB->manipulate($query);
186 
187  self::$has_accessed[$obj_id][$usr_id] = true;
188  }
189 
190  if ($isCatchupWriteEvents)
191  {
193  }
194 
195  // update parents (no categories or root)
196  if (!in_array($a_type, array("cat", "root", "crs")))
197  {
198  if ($tree->isInTree($a_ref_id))
199  {
200  $path = $tree->getPathId($a_ref_id);
201 
202  foreach ($path as $p)
203  {
204  $obj2_id = ilObject::_lookupObjId($p);
205  $obj2_type = ilObject::_lookupType($obj2_id);
206 //echo "<br>1-$obj2_type-$p-$obj2_id-";
207  if (($p != $a_ref_id) && (in_array($obj2_type, array("crs", "fold", "grp"))))
208  {
209  $query = sprintf('SELECT * FROM read_event '.
210  'WHERE obj_id = %s '.
211  'AND usr_id = %s ',
212  $ilDB->quote($obj2_id, 'integer'),
213  $ilDB->quote($usr_id, 'integer'));
214  $res2 = $ilDB->query($query);
215  if ($row2 = $ilDB->fetchAssoc($res2))
216  {
217 //echo "<br>2";
218  // update read count and spent seconds
219  $query = sprintf('UPDATE read_event SET '.
220  'childs_read_count = childs_read_count + %s ,'.
221  'childs_spent_seconds = childs_spent_seconds + %s '.
222  'WHERE obj_id = %s '.
223  'AND usr_id = %s ',
224  $ilDB->quote((int) $read_count_diff,'integer'),
225  $ilDB->quote((int) $time_diff,'integer'),
226  $ilDB->quote($obj2_id,'integer'),
227  $ilDB->quote($usr_id,'integer'));
228  $aff = $ilDB->manipulate($query);
229  }
230  else
231  {
232 //echo "<br>3";
233 //$ilLog->write("insert read event for obj_id -".$obj2_id."-".$usr_id."-");
234  $query = sprintf('INSERT INTO read_event (obj_id,usr_id,last_access,read_count,spent_seconds,first_access,'.
235  'childs_read_count, childs_spent_seconds) '.
236  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().', %s, %s) ',
237  $ilDB->quote($obj2_id,'integer'),
238  $ilDB->quote($usr_id,'integer'),
239  $ilDB->quote(time(),'integer'),
240  $ilDB->quote(1,'integer'),
241  $ilDB->quote($time,'integer'),
242  $ilDB->quote((int) $read_count_diff,'integer'),
243  $ilDB->quote((int) $time_diff,'integer')
244  );
245  $aff = $ilDB->manipulate($query);
246 
247  self::$has_accessed[$obj2_id][$usr_id] = true;
248  }
249  }
250  }
251  }
252  }
253 
254  // @todo:
255  // - calculate diff of spent_seconds and read_count
256  // - use ref id to get parents of types grp, crs, fold
257  // - add diffs to childs_spent_seconds and childs_read_count
258  }
259 
268  function _catchupWriteEvents($obj_id, $usr_id, $timestamp = null)
269  {
270  global $ilDB;
271 
272  $query = "SELECT obj_id FROM catch_write_events ".
273  "WHERE obj_id = ".$ilDB->quote($obj_id ,'integer')." ".
274  "AND usr_id = ".$ilDB->quote($usr_id ,'integer');
275  $res = $ilDB->query($query);
276  if($res->numRows())
277  {
278  $query = "UPDATE catch_write_events ".
279  "SET ts = ".($timestamp == null ? $ilDB->now() : $ilDB->quote($timestamp, 'timestamp'))." ".
280  "WHERE usr_id = ".$ilDB->quote($usr_id ,'integer')." ".
281  "AND obj_id = ".$ilDB->quote($obj_id ,'integer');
282  $res = $ilDB->manipulate($query);
283  }
284  else
285  {
286  $query = "INSERT INTO catch_write_events (ts,obj_id,usr_id) ".
287  "VALUES( ".
288  $ilDB->now().", ".
289  $ilDB->quote($obj_id,'integer').", ".
290  $ilDB->quote($usr_id,'integer')." ".
291  ")";
292  $res = $ilDB->manipulate($query);
293 
294  }
295 
296  /*
297  $q = "INSERT INTO catch_write_events ".
298  "(obj_id, usr_id, ts) ".
299  "VALUES (".
300  $ilDB->quote($obj_id,'integer').",".
301  $ilDB->quote($usr_id,'integer').",";
302  if ($timestamp == null)
303  {
304  $q .= "NOW()".
305  ") ON DUPLICATE KEY UPDATE ts=NOW()";
306  }
307  else {
308  $q .= $ilDB->quote($timestamp).
309  ") ON DUPLICATE KEY UPDATE ts=".$ilDB->quote($timestamp);
310  }
311  //error_log ('ilChangeEvent::_catchupWriteEvents '.$q);
312  $r = $ilDB->query($q);
313  */
314  }
362  public static function _lookupUncaughtWriteEvents($obj_id, $usr_id)
363  {
364  global $ilDB;
365 
366  $q = "SELECT ts ".
367  "FROM catch_write_events ".
368  "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
369  "AND usr_id=".$ilDB->quote($usr_id ,'integer');
370  $r = $ilDB->query($q);
371  $catchup = null;
372  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
373  $catchup = $row['ts'];
374  }
375 
376  if($catchup == null)
377  {
378  $query = sprintf('SELECT * FROM write_event '.
379  'WHERE obj_id = %s '.
380  'AND usr_id <> %s '.
381  'ORDER BY ts DESC',
382  $ilDB->quote($obj_id,'integer'),
383  $ilDB->quote($usr_id,'integer'));
384  $res = $ilDB->query($query);
385  }
386  else
387  {
388  $query = sprintf('SELECT * FROM write_event '.
389  'WHERE obj_id = %s '.
390  'AND usr_id <> %s '.
391  'AND ts >= %s '.
392  'ORDER BY ts DESC',
393  $ilDB->quote($obj_id,'integer'),
394  $ilDB->quote($usr_id,'integer'),
395  $ilDB->quote($catchup,'timestamp'));
396  $res = $ilDB->query($query);
397  }
398  $events = array();
399  while($row = $ilDB->fetchAssoc($res))
400  {
401  $events[] = $row;
402  }
403  return $events;
404  }
415  public static function _lookupChangeState($obj_id, $usr_id)
416  {
417  global $ilDB;
418 
419  $q = "SELECT ts ".
420  "FROM catch_write_events ".
421  "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
422  "AND usr_id=".$ilDB->quote($usr_id ,'integer');
423  $r = $ilDB->query($q);
424  $catchup = null;
425  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
426  $catchup = $row['ts'];
427  }
428 
429  if($catchup == null)
430  {
431  $ilDB->setLimit(1);
432  $query = sprintf('SELECT * FROM write_event '.
433  'WHERE obj_id = %s '.
434  'AND usr_id <> %s ',
435  $ilDB->quote($obj_id,'integer'),
436  $ilDB->quote($usr_id,'integer'));
437  $res = $ilDB->query($query);
438  }
439  else
440  {
441  $ilDB->setLimit(1);
442  $query = sprintf('SELECT * FROM write_event '.
443  'WHERE obj_id = %s '.
444  'AND usr_id <> %s '.
445  'AND ts > %s ',
446  $ilDB->quote($obj_id,'integer'),
447  $ilDB->quote($usr_id,'integer'),
448  $ilDB->quote($catchup,'timestamp'));
449  $res = $ilDB->query($query);
450  }
451 
452  $numRows = $res->numRows();
453  if ($numRows > 0)
454  {
455  $row = $ilDB->fetchAssoc($res);
456  // if we have write events, and user never catched one, report as new (1)
457  // if we have write events, and user catched an old write event, report as changed (2)
458  return ($catchup == null) ? 1 : 2;
459  }
460  else
461  {
462  return 0; // user catched all write events, report as unchanged (0)
463  }
464  }
480  public static function _lookupInsideChangeState($parent_obj_id, $usr_id)
481  {
482  global $ilDB;
483 
484  $q = "SELECT ts ".
485  "FROM catch_write_events ".
486  "WHERE obj_id=".$ilDB->quote($parent_obj_id)." ".
487  "AND usr_id=".$ilDB->quote($usr_id);
488  $r = $ilDB->query($q);
489  $catchup = null;
490  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
491  $catchup = $row['ts'];
492  }
493 
494  if($catchup == null)
495  {
496  $ilDB->setLimit(1);
497  $query = sprintf('SELECT * FROM write_event '.
498  'WHERE parent_obj_id = %s '.
499  'AND usr_id <> %s ',
500  $ilDB->quote($parent_obj_id,'integer'),
501  $ilDB->quote($usr_id,'integer'));
502  $res = $ilDB->query($query);
503  }
504  else
505  {
506  $ilDB->setLimit(1);
507  $query = sprintf('SELECT * FROM write_event '.
508  'WHERE parent_obj_id = %s '.
509  'AND usr_id <> %s '.
510  'AND ts > %s ',
511  $ilDB->quote($parent_obj_id,'integer'),
512  $ilDB->quote($usr_id,'integer'),
513  $ilDB->quote($catchup,'timestamp'));
514  $res = $ilDB->query($query);
515  }
516  $numRows = $res->numRows();
517  if ($numRows > 0)
518  {
519  $row = $ilDB->fetchAssoc($res);
520  // if we have write events, and user never catched one, report as new (1)
521  // if we have write events, and user catched an old write event, report as changed (2)
522  return ($catchup == null) ? 1 : 2;
523  }
524  else
525  {
526  return 0; // user catched all write events, report as unchanged (0)
527  }
528  }
573  public static function _lookupReadEvents($obj_id, $usr_id = null)
574  {
575  global $ilDB;
576 
577  if ($usr_id == null)
578  {
579  $query = sprintf('SELECT * FROM read_event '.
580  'WHERE obj_id = %s '.
581  'ORDER BY last_access DESC',
582  $ilDB->quote($obj_id,'integer'));
583  $res = $ilDB->query($query);
584  }
585  else
586  {
587  $query = sprintf('SELECT * FROM read_event '.
588  'WHERE obj_id = %s '.
589  'AND usr_id = %s '.
590  'ORDER BY last_access DESC',
591  $ilDB->quote($obj_id,'integer'),
592  $ilDB->quote($usr_id,'integer'));
593  $res = $ilDB->query($query);
594  }
595 
596  $counter = 0;
597  while ($row = $ilDB->fetchAssoc($res))
598  {
599  $events[$counter]['obj_id'] = $row['obj_id'];
600  $events[$counter]['usr_id'] = $row['usr_id'];
601  $events[$counter]['last_access'] = $row['last_access'];
602  $events[$counter]['read_count'] = $row['read_count'];
603  $events[$counter]['spent_seconds'] = $row['spent_seconds'];
604  $events[$counter]['first_access'] = $row['first_access'];
605 
606  $counter++;
607 
608  }
609  return $events ? $events : array();
610  }
611 
618  public static function lookupUsersInProgress($a_obj_id)
619  {
620  global $ilDB;
621 
622  $query = sprintf('SELECT DISTINCT(usr_id) usr FROM read_event '.
623  'WHERE obj_id = %s ',
624  $ilDB->quote($a_obj_id,'integer'));
625  $res = $ilDB->query($query);
626  while($row = $ilDB->fetchObject($res))
627  {
628  $users[] = $row->usr;
629  }
630  return $users ? $users : array();
631  }
632 
636  static function hasAccessed($a_obj_id, $a_usr_id)
637  {
638  global $ilDB;
639 
640  if (isset(self::$has_accessed[$a_obj_id][$a_usr_id]))
641  {
642  return self::$has_accessed[$a_obj_id][$a_usr_id];
643  }
644 
645  $set = $ilDB->query("SELECT usr_id FROM read_event WHERE ".
646  "obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
647  "usr_id = ".$ilDB->quote($a_usr_id, "integer")
648  );
649  if ($rec = $ilDB->fetchAssoc($set))
650  {
651  return self::$has_accessed[$a_obj_id][$a_usr_id] = true;
652  }
653  return self::$has_accessed[$a_obj_id][$a_usr_id] = false;
654  }
655 
661  public static function _activate() {
663  {
664  return 'change event tracking is already active';
665  }
666  else
667  {
668  global $ilDB;
669 
670  // Insert initial data into table write_event
671  // We need to do this here, because we need
672  // to catch up write events that occured while the change event tracking was
673  // deactivated.
674 
675  // IGNORE isn't supported in oracle
676  $set = $ilDB->query(sprintf('SELECT r1.obj_id,r2.obj_id p,d.owner,%s,d.create_date '.
677  'FROM object_data d '.
678  'LEFT JOIN write_event w ON d.obj_id = w.obj_id '.
679  'JOIN object_reference r1 ON d.obj_id=r1.obj_id '.
680  'JOIN tree t ON t.child=r1.ref_id '.
681  'JOIN object_reference r2 on r2.ref_id=t.parent '.
682  'WHERE w.obj_id IS NULL',
683  $ilDB->quote('create','text')));
684  while ($rec = $ilDB->fetchAssoc($set))
685  {
686  $nid = $ilDB->nextId("write_event");
687  $query = 'INSERT INTO write_event '.
688  '(write_id, obj_id,parent_obj_id,usr_id,action,ts) VALUES ('.
689  $ilDB->quote($nid, "integer").",".
690  $ilDB->quote($rec["obj_id"], "integer").",".
691  $ilDB->quote($rec["p"], "integer").",".
692  $ilDB->quote($rec["owner"], "integer").",".
693  $ilDB->quote("create", "text").",".
694  $ilDB->quote($rec["create_date"], "timestamp").
695  ')';
696  $res = $ilDB->query($query);
697  }
698 
699  if ($ilDB->isError($res) || $ilDB->isError($res->result))
700  {
701  return 'couldn\'t insert initial data into table "write_event": '.
702  (($ilDB->isError($r->result)) ? $r->result->getMessage() : $r->getMessage());
703  }
704 
705 
706  global $ilias;
707  $ilias->setSetting('enable_change_event_tracking', '1');
708 
709  return $res;
710  }
711  }
712 
718  public static function _deactivate() {
719  global $ilias;
720  $ilias->setSetting('enable_change_event_tracking', '0');
721 
722  }
723 
729  public static function _isActive() {
730  global $ilias;
731  return $ilias->getSetting('enable_change_event_tracking', '0') == '1';
732 
733  }
734 
741  public static function _delete($a_obj_id)
742  {
743  global $ilDB;
744 
745  $query = sprintf('DELETE FROM write_event WHERE obj_id = %s ',
746  $ilDB->quote($a_obj_id,'integer'));
747  $aff = $ilDB->manipulate($query);
748 
749  $query = sprintf('DELETE FROM read_event WHERE obj_id = %s ',
750  $ilDB->quote($a_obj_id,'integer'));
751  $aff = $ilDB->manipulate($query);
752  return true;
753  }
754 }
755 ?>