ILIAS  release_4-4 Revision
ilChangeEvent Class Reference

Class ilChangeEvent tracks change events on repository objects. More...

+ Collaboration diagram for ilChangeEvent:

Public Member Functions

 _recordWriteEvent ($obj_id, $usr_id, $action, $parent_obj_id=null)
 Records a write event. More...
 
 _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. More...
 
 _recordObjStats ($a_obj_id, $a_spent_seconds, $a_read_count, $a_childs_spent_seconds=null, $a_child_read_count=null)
 
 _syncObjectStats ($a_now=null, $a_minimum=20000)
 Process object statistics log data. More...
 
 _catchupWriteEvents ($obj_id, $usr_id, $timestamp=null)
 Catches up with all write events which occured before the specified timestamp. More...
 
 _updateAccessForScormOfflinePlayer ($obj_id, $usr_id, $i_last_access, $t_first_access)
 _updateAccessForScormOfflinePlayer needed to synchronize last_access and first_access when learning modul is used offline called in . More...
 

Static Public Member Functions

static _lookupUncaughtWriteEvents ($obj_id, $usr_id)
 Catches up with all write events which occured before the specified timestamp. More...
 
static _lookupChangeState ($obj_id, $usr_id)
 Returns the change state of the object for the specified user. More...
 
static _lookupInsideChangeState ($parent_obj_id, $usr_id)
 Returns the changed state of objects which are children of the specified parent object. More...
 
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 up with them. More...
 
static lookupUsersInProgress ($a_obj_id)
 Lookup users in progress. More...
 
static hasAccessed ($a_obj_id, $a_usr_id)
 Has accessed. More...
 
static _activate ()
 Activates change event tracking. More...
 
static _deactivate ()
 Deactivates change event tracking. More...
 
static _isActive ()
 Returns true, if change event tracking is active. More...
 
static _delete ($a_obj_id)
 Delete object entries. More...
 
static _deleteReadEvents ($a_obj_id)
 
static _deleteReadEventsForUsers ($a_obj_id, array $a_user_ids)
 
static _getAllUserIds ($a_obj_id)
 

Static Private Attributes

static $has_accessed = array()
 

Detailed Description

Class ilChangeEvent tracks change events on repository objects.

The following events are considered to be a 'write event':

  • The creation of a new repository object
  • A change of the data or meta-data of an object
  • A move, link, copy, deletion or undeletion of the object UI objects, which cause a 'write event', must call _recordWriteEvent(...) In most cases, UI objects let the user catch up with write events on the object, when doing this call.

The following events are considered to be a 'read event':

  • Opening a container object in the browser*
  • Opening / downloading / reading an object UI objects, which cause a 'read event', must call _recordReadEvent(...). In most cases, UI objects let the user catch up with write events on the object, when doing this call.

*reading the content of a container using WebDAV is not counted, because WebDAV clients can't see all objects in a container.

A user can catch up with write events, by calling __catchupWriteEvents(...).

A user can query, if an object has changed, since the last time he has caught up with write events, by calling _lookupUncaughtWriteEvents(...).

Author
Werner Randelshofer werne.nosp@m.r.ra.nosp@m.ndels.nosp@m.hofe.nosp@m.r@hsl.nosp@m.u.ch
Version
Id
class.ilChangeEvent.php,v 1.02 2007/05/07 19:25:34 wrandels Exp

Definition at line 36 of file class.ilChangeEvent.php.

Member Function Documentation

◆ _activate()

static ilChangeEvent::_activate ( )
static

Activates change event tracking.

Returns
mixed true on success, a string with an error message on failure.

Definition at line 849 of file class.ilChangeEvent.php.

References $query, $r, $res, and _isActive().

Referenced by ilObjRepositorySettingsGUI\saveSettings(), and ilTrackingTest\testChangeEvent().

849  {
851  {
852  return 'change event tracking is already active';
853  }
854  else
855  {
856  global $ilDB;
857 
858  // Insert initial data into table write_event
859  // We need to do this here, because we need
860  // to catch up write events that occured while the change event tracking was
861  // deactivated.
862 
863  // IGNORE isn't supported in oracle
864  $set = $ilDB->query(sprintf('SELECT r1.obj_id,r2.obj_id p,d.owner,%s,d.create_date '.
865  'FROM object_data d '.
866  'LEFT JOIN write_event w ON d.obj_id = w.obj_id '.
867  'JOIN object_reference r1 ON d.obj_id=r1.obj_id '.
868  'JOIN tree t ON t.child=r1.ref_id '.
869  'JOIN object_reference r2 on r2.ref_id=t.parent '.
870  'WHERE w.obj_id IS NULL',
871  $ilDB->quote('create','text')));
872  while ($rec = $ilDB->fetchAssoc($set))
873  {
874  $nid = $ilDB->nextId("write_event");
875  $query = 'INSERT INTO write_event '.
876  '(write_id, obj_id,parent_obj_id,usr_id,action,ts) VALUES ('.
877  $ilDB->quote($nid, "integer").",".
878  $ilDB->quote($rec["obj_id"], "integer").",".
879  $ilDB->quote($rec["p"], "integer").",".
880  $ilDB->quote($rec["owner"], "integer").",".
881  $ilDB->quote("create", "text").",".
882  $ilDB->quote($rec["create_date"], "timestamp").
883  ')';
884  $res = $ilDB->query($query);
885  }
886 
887  if ($ilDB->isError($res) || $ilDB->isError($res->result))
888  {
889  return 'couldn\'t insert initial data into table "write_event": '.
890  (($ilDB->isError($r->result)) ? $r->result->getMessage() : $r->getMessage());
891  }
892 
893 
894  global $ilias;
895  $ilias->setSetting('enable_change_event_tracking', '1');
896 
897  return $res;
898  }
899  }
static _isActive()
Returns true, if change event tracking is active.
$r
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _catchupWriteEvents()

ilChangeEvent::_catchupWriteEvents (   $obj_id,
  $usr_id,
  $timestamp = null 
)

Catches up with all write events which occured before the specified timestamp.

Parameters
$obj_idint The object.
$usr_idint The user.
$timestampSQL timestamp.

Definition at line 456 of file class.ilChangeEvent.php.

References $query, $res, $timestamp, and $usr_id.

Referenced by _recordReadEvent(), ilContainerGUI\pasteObject(), ilContainerGUI\performPasteIntoMultipleObjectsObject(), ilDAVServer\PUT(), ilRepUtil\restoreObjects(), ilObjFileGUI\update(), ilObjRootFolderGUI\updateObject(), ilObjGroupGUI\updateObject(), ilObjCategoryGUI\updateObject(), and ilObjCourseGUI\updateObject().

457  {
458  global $ilDB;
459 
460  $query = "SELECT obj_id FROM catch_write_events ".
461  "WHERE obj_id = ".$ilDB->quote($obj_id ,'integer')." ".
462  "AND usr_id = ".$ilDB->quote($usr_id ,'integer');
463  $res = $ilDB->query($query);
464  if($res->numRows())
465  {
466  $query = "UPDATE catch_write_events ".
467  "SET ts = ".($timestamp == null ? $ilDB->now() : $ilDB->quote($timestamp, 'timestamp'))." ".
468  "WHERE usr_id = ".$ilDB->quote($usr_id ,'integer')." ".
469  "AND obj_id = ".$ilDB->quote($obj_id ,'integer');
470  $res = $ilDB->manipulate($query);
471  }
472  else
473  {
474  $query = "INSERT INTO catch_write_events (ts,obj_id,usr_id) ".
475  "VALUES( ".
476  $ilDB->now().", ".
477  $ilDB->quote($obj_id,'integer').", ".
478  $ilDB->quote($usr_id,'integer')." ".
479  ")";
480  $res = $ilDB->manipulate($query);
481 
482  }
483 
484  /*
485  $q = "INSERT INTO catch_write_events ".
486  "(obj_id, usr_id, ts) ".
487  "VALUES (".
488  $ilDB->quote($obj_id,'integer').",".
489  $ilDB->quote($usr_id,'integer').",";
490  if ($timestamp == null)
491  {
492  $q .= "NOW()".
493  ") ON DUPLICATE KEY UPDATE ts=NOW()";
494  }
495  else {
496  $q .= $ilDB->quote($timestamp).
497  ") ON DUPLICATE KEY UPDATE ts=".$ilDB->quote($timestamp);
498  }
499  //error_log ('ilChangeEvent::_catchupWriteEvents '.$q);
500  $r = $ilDB->query($q);
501  */
502  }
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:81
+ Here is the caller graph for this function:

◆ _deactivate()

static ilChangeEvent::_deactivate ( )
static

Deactivates change event tracking.

Returns
mixed true on success, a string with an error message on failure.

Definition at line 906 of file class.ilChangeEvent.php.

Referenced by ilObjRepositorySettingsGUI\saveSettings(), and ilTrackingTest\testChangeEvent().

906  {
907  global $ilias;
908  $ilias->setSetting('enable_change_event_tracking', '0');
909 
910  }
+ Here is the caller graph for this function:

◆ _delete()

static ilChangeEvent::_delete (   $a_obj_id)
static

Delete object entries.

Returns

Definition at line 929 of file class.ilChangeEvent.php.

References $query.

Referenced by ilObjectLP\handleDelete().

930  {
931  global $ilDB;
932 
933  $query = sprintf('DELETE FROM write_event WHERE obj_id = %s ',
934  $ilDB->quote($a_obj_id,'integer'));
935  $aff = $ilDB->manipulate($query);
936 
937  $query = sprintf('DELETE FROM read_event WHERE obj_id = %s ',
938  $ilDB->quote($a_obj_id,'integer'));
939  $aff = $ilDB->manipulate($query);
940  return true;
941  }
+ Here is the caller graph for this function:

◆ _deleteReadEvents()

static ilChangeEvent::_deleteReadEvents (   $a_obj_id)
static

Definition at line 943 of file class.ilChangeEvent.php.

944  {
945  global $ilDB;
946 
947  $ilDB->manipulate("DELETE FROM read_event".
948  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer"));
949  }

◆ _deleteReadEventsForUsers()

static ilChangeEvent::_deleteReadEventsForUsers (   $a_obj_id,
array  $a_user_ids 
)
static

Definition at line 951 of file class.ilChangeEvent.php.

Referenced by ilObjectLP\resetLPDataForUserIds().

952  {
953  global $ilDB;
954 
955  $ilDB->manipulate("DELETE FROM read_event".
956  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer").
957  " AND ".$ilDB->in("usr_id", $a_user_ids, "", "integer"));
958  }
+ Here is the caller graph for this function:

◆ _getAllUserIds()

static ilChangeEvent::_getAllUserIds (   $a_obj_id)
static

Definition at line 960 of file class.ilChangeEvent.php.

References $res, and $row.

Referenced by ilObjectLP\gatherLPUsers().

961  {
962  global $ilDB;
963 
964  $res = array();
965 
966  $set = $ilDB->query("SELECT usr_id FROM read_event".
967  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer"));
968  while($row = $ilDB->fetchAssoc($set))
969  {
970  $res[] = $row["usr_id"];
971  }
972 
973  return $res;
974  }
+ Here is the caller graph for this function:

◆ _isActive()

static ilChangeEvent::_isActive ( )
static

Returns true, if change event tracking is active.

Returns
mixed true on success, a string with an error message on failure.

Definition at line 917 of file class.ilChangeEvent.php.

Referenced by ilObjUserTracking\__readSettings(), _activate(), ilInfoScreenGUI\addObjectSections(), ilObjRepositorySettingsGUI\addToExternalSettingsForm(), ilObjectListGUI\getProperties(), and ilObjRepositorySettingsGUI\initSettingsForm().

917  {
918  global $ilias;
919  return $ilias->getSetting('enable_change_event_tracking', '0') == '1';
920 
921  }
+ Here is the caller graph for this function:

◆ _lookupChangeState()

static ilChangeEvent::_lookupChangeState (   $obj_id,
  $usr_id 
)
static

Returns the change state of the object for the specified user.

which happened after the last time the user caught up with them.

Parameters
$obj_idint The object
$usr_idint The user who is interested into these events.
Returns
0 = object is unchanged, 1 = object is new, 2 = object has changed

Definition at line 603 of file class.ilChangeEvent.php.

References $query, $r, $res, $row, $usr_id, and DB_FETCHMODE_ASSOC.

Referenced by ilObjectListGUI\getProperties(), and ilTrackingTest\testChangeEvent().

604  {
605  global $ilDB;
606 
607  $q = "SELECT ts ".
608  "FROM catch_write_events ".
609  "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
610  "AND usr_id=".$ilDB->quote($usr_id ,'integer');
611  $r = $ilDB->query($q);
612  $catchup = null;
613  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
614  $catchup = $row['ts'];
615  }
616 
617  if($catchup == null)
618  {
619  $ilDB->setLimit(1);
620  $query = sprintf('SELECT * FROM write_event '.
621  'WHERE obj_id = %s '.
622  'AND usr_id <> %s ',
623  $ilDB->quote($obj_id,'integer'),
624  $ilDB->quote($usr_id,'integer'));
625  $res = $ilDB->query($query);
626  }
627  else
628  {
629  $ilDB->setLimit(1);
630  $query = sprintf('SELECT * FROM write_event '.
631  'WHERE obj_id = %s '.
632  'AND usr_id <> %s '.
633  'AND ts > %s ',
634  $ilDB->quote($obj_id,'integer'),
635  $ilDB->quote($usr_id,'integer'),
636  $ilDB->quote($catchup,'timestamp'));
637  $res = $ilDB->query($query);
638  }
639 
640  $numRows = $res->numRows();
641  if ($numRows > 0)
642  {
643  $row = $ilDB->fetchAssoc($res);
644  // if we have write events, and user never catched one, report as new (1)
645  // if we have write events, and user catched an old write event, report as changed (2)
646  return ($catchup == null) ? 1 : 2;
647  }
648  else
649  {
650  return 0; // user catched all write events, report as unchanged (0)
651  }
652  }
const DB_FETCHMODE_ASSOC
Definition: class.ilDB.php:10
$r
+ Here is the caller graph for this function:

◆ _lookupInsideChangeState()

static ilChangeEvent::_lookupInsideChangeState (   $parent_obj_id,
  $usr_id 
)
static

Returns the changed state of objects which are children of the specified parent object.

Note this gives a different result than calling _lookupChangeState of each child object. This is because, this function treats a catch on the write events on the parent as a catch up for all child objects. This difference was made, because it greatly improves performance of this function.

Parameters
$parent_obj_idint The object id of the parent object.
$usr_idint The user who is interested into these events.
Returns
0 = object has not been changed inside 1 = object has been changed inside

Definition at line 668 of file class.ilChangeEvent.php.

References $query, $r, $res, $row, $usr_id, and DB_FETCHMODE_ASSOC.

Referenced by ilObjectListGUI\getProperties(), and ilTrackingTest\testChangeEvent().

669  {
670  global $ilDB;
671 
672  $q = "SELECT ts ".
673  "FROM catch_write_events ".
674  "WHERE obj_id=".$ilDB->quote($parent_obj_id)." ".
675  "AND usr_id=".$ilDB->quote($usr_id);
676  $r = $ilDB->query($q);
677  $catchup = null;
678  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
679  $catchup = $row['ts'];
680  }
681 
682  if($catchup == null)
683  {
684  $ilDB->setLimit(1);
685  $query = sprintf('SELECT * FROM write_event '.
686  'WHERE parent_obj_id = %s '.
687  'AND usr_id <> %s ',
688  $ilDB->quote($parent_obj_id,'integer'),
689  $ilDB->quote($usr_id,'integer'));
690  $res = $ilDB->query($query);
691  }
692  else
693  {
694  $ilDB->setLimit(1);
695  $query = sprintf('SELECT * FROM write_event '.
696  'WHERE parent_obj_id = %s '.
697  'AND usr_id <> %s '.
698  'AND ts > %s ',
699  $ilDB->quote($parent_obj_id,'integer'),
700  $ilDB->quote($usr_id,'integer'),
701  $ilDB->quote($catchup,'timestamp'));
702  $res = $ilDB->query($query);
703  }
704  $numRows = $res->numRows();
705  if ($numRows > 0)
706  {
707  $row = $ilDB->fetchAssoc($res);
708  // if we have write events, and user never catched one, report as new (1)
709  // if we have write events, and user catched an old write event, report as changed (2)
710  return ($catchup == null) ? 1 : 2;
711  }
712  else
713  {
714  return 0; // user catched all write events, report as unchanged (0)
715  }
716  }
const DB_FETCHMODE_ASSOC
Definition: class.ilDB.php:10
$r
+ Here is the caller graph for this function:

◆ _lookupReadEvents()

static ilChangeEvent::_lookupReadEvents (   $obj_id,
  $usr_id = null 
)
static

Reads all read events which occured on the object which happened after the last time the user caught up with them.

NOTE: THIS FUNCTION NEEDS TO BE REWRITTEN. READ EVENTS ARE OF INTEREST AT REF_ID's OF OBJECTS.

Parameters
$obj_idint The object
$usr_idint The user who is interested into these events. / public static function _lookupUncaughtReadEvents($obj_id, $usr_id) { global $ilDB;

$q = "SELECT ts ". "FROM catch_read_events ". "WHERE obj_id=".$ilDB->quote($obj_id)." ". "AND usr_id=".$ilDB->quote($usr_id); $r = $ilDB->query($q); $catchup = null; while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) { $catchup = $row['ts']; }

$q = "SELECT * ". "FROM read_event ". "WHERE obj_id=".$ilDB->quote($obj_id)." ". ($catchup == null ? "" : "AND last_access > ".$ilDB->quote($catchup))." ". ($catchup == null ? "" : "AND last_access > ".$ilDB->quote($catchup))." ". "ORDER BY last_access DESC"; $r = $ilDB->query($q); $events = array(); while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) { $events[] = $row; } return $events; } Reads all read events which occured on the object.

Parameters
$obj_idint The object
$usr_idint Optional, the user who performed these events.

Definition at line 761 of file class.ilChangeEvent.php.

References $query, $res, $row, and $usr_id.

Referenced by ilLPStatusVisits\_getCompleted(), ilLPStatusTypicalLearningTime\_getCompleted(), ilLPStatusVisits\_getInProgress(), ilLPStatusTypicalLearningTime\_getInProgress(), ilLearningProgress\_getProgress(), ilLearningProgress\_lookupProgressByObjId(), ilInfoScreenGUI\addObjectSections(), ilLPStatusVisits\determinePercentage(), ilLPStatusTypicalLearningTime\determinePercentage(), ilLPStatusVisits\determineStatus(), ilLPStatusTypicalLearningTime\determineStatus(), and ilSCORMOfflineMode\il2sopSahsUser().

762  {
763  global $ilDB;
764 
765  if ($usr_id == null)
766  {
767  $query = sprintf('SELECT * FROM read_event '.
768  'WHERE obj_id = %s '.
769  'ORDER BY last_access DESC',
770  $ilDB->quote($obj_id,'integer'));
771  $res = $ilDB->query($query);
772  }
773  else
774  {
775  $query = sprintf('SELECT * FROM read_event '.
776  'WHERE obj_id = %s '.
777  'AND usr_id = %s '.
778  'ORDER BY last_access DESC',
779  $ilDB->quote($obj_id,'integer'),
780  $ilDB->quote($usr_id,'integer'));
781  $res = $ilDB->query($query);
782  }
783 
784  $counter = 0;
785  while ($row = $ilDB->fetchAssoc($res))
786  {
787  $events[$counter]['obj_id'] = $row['obj_id'];
788  $events[$counter]['usr_id'] = $row['usr_id'];
789  $events[$counter]['last_access'] = $row['last_access'];
790  $events[$counter]['read_count'] = $row['read_count'];
791  $events[$counter]['spent_seconds'] = $row['spent_seconds'];
792  $events[$counter]['first_access'] = $row['first_access'];
793 
794  $counter++;
795 
796  }
797  return $events ? $events : array();
798  }
+ Here is the caller graph for this function:

◆ _lookupUncaughtWriteEvents()

static ilChangeEvent::_lookupUncaughtWriteEvents (   $obj_id,
  $usr_id 
)
static

Catches up with all write events which occured before the specified timestamp.

THIS FUNCTION IS CURRENTLY NOT IN USE. BEFORE IT CAN BE USED, THE TABLE catch_read_events MUST BE CREATED.

Parameters
$obj_idint The object.
$usr_idint The user.
$timestampSQL timestamp. / function _catchupReadEvents($obj_id, $usr_id, $timestamp = null) { global $ilDB;
    $q = "INSERT INTO catch_read_events ".
            "(obj_id, usr_id, action, ts) ".
            "VALUES (".
            $ilDB->quote($obj_id).",".
            $ilDB->quote($usr_id).",".
            $ilDB->quote('read').",";
    if ($timestamp == null)
    {
            $q .= "NOW()".
            ") ON DUPLICATE KEY UPDATE ts=NOW()";
    }
    else {
            $q .= $ilDB->quote($timestamp).
            ") ON DUPLICATE KEY UPDATE ts=".$ilDB->quote($timestamp);
    }

    $r = $ilDB->query($q);

} Reads all write events which occured on the object which happened after the last time the user caught up with them.

Parameters
$obj_idint The object
$usr_idint The user who is interested into these events.
Returns
array with rows from table write_event

Definition at line 550 of file class.ilChangeEvent.php.

References $query, $r, $res, $row, $usr_id, and DB_FETCHMODE_ASSOC.

Referenced by ilTrackingTest\testChangeEvent().

551  {
552  global $ilDB;
553 
554  $q = "SELECT ts ".
555  "FROM catch_write_events ".
556  "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
557  "AND usr_id=".$ilDB->quote($usr_id ,'integer');
558  $r = $ilDB->query($q);
559  $catchup = null;
560  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
561  $catchup = $row['ts'];
562  }
563 
564  if($catchup == null)
565  {
566  $query = sprintf('SELECT * FROM write_event '.
567  'WHERE obj_id = %s '.
568  'AND usr_id <> %s '.
569  'ORDER BY ts DESC',
570  $ilDB->quote($obj_id,'integer'),
571  $ilDB->quote($usr_id,'integer'));
572  $res = $ilDB->query($query);
573  }
574  else
575  {
576  $query = sprintf('SELECT * FROM write_event '.
577  'WHERE obj_id = %s '.
578  'AND usr_id <> %s '.
579  'AND ts >= %s '.
580  'ORDER BY ts DESC',
581  $ilDB->quote($obj_id,'integer'),
582  $ilDB->quote($usr_id,'integer'),
583  $ilDB->quote($catchup,'timestamp'));
584  $res = $ilDB->query($query);
585  }
586  $events = array();
587  while($row = $ilDB->fetchAssoc($res))
588  {
589  $events[] = $row;
590  }
591  return $events;
592  }
const DB_FETCHMODE_ASSOC
Definition: class.ilDB.php:10
$r
+ Here is the caller graph for this function:

◆ _recordObjStats()

ilChangeEvent::_recordObjStats (   $a_obj_id,
  $a_spent_seconds,
  $a_read_count,
  $a_childs_spent_seconds = null,
  $a_child_read_count = null 
)

Definition at line 292 of file class.ilChangeEvent.php.

References ilObjUserTracking\_enabledObjectStatistics(), and ilObject\_lookupType().

293  {
294  global $ilDB;
295 
297  (int)$a_obj_id <= 0) // #12706
298  {
299  return;
300  }
301 
302  $now = time();
303 
304  $fields = array();
305  $fields["obj_id"] = array("integer", $a_obj_id);
306  $fields["obj_type"] = array("text", ilObject::_lookupType($a_obj_id));
307  $fields["tstamp"] = array("timestamp", $now);
308  $fields["yyyy"] = array("integer", date("Y"));
309  $fields["mm"] = array("integer", date("m"));
310  $fields["dd"] = array("integer", date("d"));
311  $fields["hh"] = array("integer", date("H"));
312  if($a_spent_seconds > 0)
313  {
314  $fields["spent_seconds"] = array("integer", $a_spent_seconds);
315  }
316  if($a_read_count > 0)
317  {
318  $fields["read_count"] = array("integer", $a_read_count);
319  }
320  if($a_childs_spent_seconds > 0)
321  {
322  $fields["childs_spent_seconds"] = array("integer", $a_childs_spent_seconds);
323  }
324  if($a_child_read_count > 0)
325  {
326  $fields["childs_read_count"] = array("integer", $a_child_read_count);
327  }
328  $ilDB->insert("obj_stat_log", $fields);
329 
330  // 0.01% probability
331  if(mt_rand(1, 100) == 1)
332  {
333  self::_syncObjectStats($now);
334  }
335  }
static _enabledObjectStatistics()
check wether object statistics is enabled or not
static _lookupType($a_id, $a_reference=false)
lookup object type
+ Here is the call graph for this function:

◆ _recordReadEvent()

ilChangeEvent::_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.

Parameters
$obj_idint The object which was read.
$usr_idint The user who performed a read action.
$catchupWriteEventsboolean If true, this function catches up with write events.

Definition at line 113 of file class.ilChangeEvent.php.

References $path, $query, $res, $row, $usr_id, _catchupWriteEvents(), ilObjUserTracking\_getValidTimeSpan(), ilObject\_lookupObjId(), and ilObject\_lookupType().

Referenced by ilLicense\_noteAccess(), ilObjSCORMTracking\_syncReadEvent(), ilSCORM2004Tracking\_syncReadEvent(), ilLearningProgress\_tracProgress(), ilDAVServer\COPY(), ilDAVServer\GET(), ilWikiPageGUI\increaseViewCount(), ilObjSessionGUI\infoScreen(), ilContainerGUI\performPasteIntoMultipleObjectsObject(), ilDAVServer\PROPFIND(), ilObjLinkResourceGUI\redirectToLink(), ilObjFileGUI\sendFile(), ilContainerContentGUI\setOutput(), ilObjSCORMTracking\syncGlobalStatus(), ilSCORM2004StoreData\syncGlobalStatus(), ilCourseContentGUI\view(), and ilObjectGUI\viewObject().

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  $query = sprintf('INSERT INTO read_event (obj_id,usr_id,last_access,read_count,spent_seconds,first_access) '.
204  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().') ',
205  $ilDB->quote($obj_id,'integer'),
206  $ilDB->quote($usr_id,'integer'),
207  $ilDB->quote(time(),'integer'),
208  $ilDB->quote($read_count_init,'integer'),
209  $ilDB->quote($time,'integer'));
210 
211  $aff = $ilDB->manipulate($query);
212 
213  self::$has_accessed[$obj_id][$usr_id] = true;
214 
215  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
216  }
217 
218  if ($isCatchupWriteEvents)
219  {
221  }
222 
223  // update parents (no categories or root)
224  if (!in_array($a_type, array("cat", "root", "crs")))
225  {
226  if ($tree->isInTree($a_ref_id))
227  {
228  $path = $tree->getPathId($a_ref_id);
229 
230  foreach ($path as $p)
231  {
232  $obj2_id = ilObject::_lookupObjId($p);
233  $obj2_type = ilObject::_lookupType($obj2_id);
234 //echo "<br>1-$obj2_type-$p-$obj2_id-";
235  if (($p != $a_ref_id) && (in_array($obj2_type, array("crs", "fold", "grp"))))
236  {
237  $query = sprintf('SELECT * FROM read_event '.
238  'WHERE obj_id = %s '.
239  'AND usr_id = %s ',
240  $ilDB->quote($obj2_id, 'integer'),
241  $ilDB->quote($usr_id, 'integer'));
242  $res2 = $ilDB->query($query);
243  if ($row2 = $ilDB->fetchAssoc($res2))
244  {
245 //echo "<br>2";
246  // update read count and spent seconds
247  $query = sprintf('UPDATE read_event SET '.
248  'childs_read_count = childs_read_count + %s ,'.
249  'childs_spent_seconds = childs_spent_seconds + %s '.
250  'WHERE obj_id = %s '.
251  'AND usr_id = %s ',
252  $ilDB->quote((int) $read_count_diff,'integer'),
253  $ilDB->quote((int) $time_diff,'integer'),
254  $ilDB->quote($obj2_id,'integer'),
255  $ilDB->quote($usr_id,'integer'));
256  $aff = $ilDB->manipulate($query);
257 
258  self::_recordObjStats($obj2_id, null, null, (int)$time_diff, (int)$read_count_diff);
259  }
260  else
261  {
262 //echo "<br>3";
263 //$ilLog->write("insert read event for obj_id -".$obj2_id."-".$usr_id."-");
264  $query = sprintf('INSERT INTO read_event (obj_id,usr_id,last_access,read_count,spent_seconds,first_access,'.
265  'childs_read_count, childs_spent_seconds) '.
266  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().', %s, %s) ',
267  $ilDB->quote($obj2_id,'integer'),
268  $ilDB->quote($usr_id,'integer'),
269  $ilDB->quote(time(),'integer'),
270  $ilDB->quote(1,'integer'),
271  $ilDB->quote($time,'integer'),
272  $ilDB->quote((int) $read_count_diff,'integer'),
273  $ilDB->quote((int) $time_diff,'integer')
274  );
275  $aff = $ilDB->manipulate($query);
276 
277  self::$has_accessed[$obj2_id][$usr_id] = true;
278 
279  self::_recordObjStats($obj2_id, $time, 1, (int)$time_diff, (int)$read_count_diff);
280  }
281  }
282  }
283  }
284  }
285 
286  // @todo:
287  // - calculate diff of spent_seconds and read_count
288  // - use ref id to get parents of types grp, crs, fold
289  // - add diffs to childs_spent_seconds and childs_read_count
290  }
static _lookupObjId($a_id)
static _lookupType($a_id, $a_reference=false)
lookup object type
$path
Definition: index.php:22
_catchupWriteEvents($obj_id, $usr_id, $timestamp=null)
Catches up with all write events which occured before the specified timestamp.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _recordWriteEvent()

ilChangeEvent::_recordWriteEvent (   $obj_id,
  $usr_id,
  $action,
  $parent_obj_id = null 
)

Records a write event.

The parent object should be specified for the 'delete', 'undelete' and 'add' and 'remove' events.

Parameters
$obj_idint The object which was written to.
$usr_idint The user who performed a write action.
$actionstring The name of the write action. 'create', 'update', 'delete', 'add', 'remove', 'undelete'.
$parent_obj_idint The object id of the parent object. If this is null, then the event is recorded for all parents of the object. If this is not null, then the event is only recorded for the specified parent.

Definition at line 55 of file class.ilChangeEvent.php.

References $query, and $usr_id.

Referenced by ilObjCourseGUI\afterSave(), ilDAVServer\COPY(), ilDAVServer\DELETE(), ilObjFileGUI\handleFileUpload(), ilDAVServer\MKCOL(), ilDAVServer\MOVE(), ilContainerGUI\pasteObject(), ilContainerGUI\performPasteIntoMultipleObjectsObject(), ilDAVServer\PUT(), ilObject2GUI\putObjectInTree(), ilObjectGUI\putObjectInTree(), ilRepUtil\removeObjectsFromSystem(), ilRepUtil\restoreObjects(), ilObjFileGUI\save(), ilObjFileGUI\update(), ilObjRootFolderGUI\updateObject(), ilObjGroupGUI\updateObject(), ilObjCategoryGUI\updateObject(), and ilObjCourseGUI\updateObject().

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  }
+ Here is the caller graph for this function:

◆ _syncObjectStats()

ilChangeEvent::_syncObjectStats (   $a_now = null,
  $a_minimum = 20000 
)

Process object statistics log data.

Parameters
integer$a_now
integer$a_minimum

Definition at line 343 of file class.ilChangeEvent.php.

References $row, and ilDB\LOCK_WRITE.

Referenced by ilLPObjectStatisticsGUI\adminSync().

344  {
345  global $ilDB;
346 
347  if(!$a_now)
348  {
349  $a_now = time();
350  }
351 
352  set_time_limit(0);
353 
354  // has source table enough entries?
355  $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
356  $row = $ilDB->fetchAssoc($set);
357  if($row["counter"] >= $a_minimum)
358  {
359  // lock source and transfer table
360  $ilDB->lockTables(array(array("name"=>"obj_stat_log", "type"=>ilDB::LOCK_WRITE),
361  array("name"=>"obj_stat_tmp", "type"=>ilDB::LOCK_WRITE)));
362 
363  // if other process was transferring, we had to wait for the lock and
364  // the source table should now have less than minimum/needed entries
365  $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
366  $row = $ilDB->fetchAssoc($set);
367  if($row["counter"] >= $a_minimum)
368  {
369  // use only "full" seconds to have a clear cut
370  $ilDB->query("INSERT INTO obj_stat_tmp".
371  " SELECT * FROM obj_stat_log".
372  " WHERE tstamp < ".$ilDB->quote($a_now, "timestamp"));
373 
374  // remove transferred entries from source table
375  $ilDB->query("DELETE FROM obj_stat_log".
376  " WHERE tstamp < ".$ilDB->quote($a_now, "timestamp"));
377 
378  // remove lock from source table
379  $ilDB->unlockTables();
380 
381  // lock transfer and target table (is this needed?)
382  $ilDB->lockTables(array(array("name"=>"obj_stat_tmp", "type"=>ilDB::LOCK_WRITE),
383  array("name"=>"obj_stat", "type"=>ilDB::LOCK_WRITE)));
384 
385  // process log data (timestamp is not needed anymore)
386  $sql = "SELECT obj_id, obj_type, yyyy, mm, dd, hh, SUM(read_count) AS read_count,".
387  " SUM(childs_read_count) AS childs_read_count, SUM(spent_seconds) AS spent_seconds,".
388  " SUM(childs_spent_seconds) AS childs_spent_seconds".
389  " FROM obj_stat_tmp".
390  " GROUP BY obj_id, obj_type, yyyy, mm, dd, hh";
391  $set = $ilDB->query($sql);
392  while($row = $ilDB->fetchAssoc($set))
393  {
394  // "primary key"
395  $where = array("obj_id" => array("integer", $row["obj_id"]),
396  "obj_type" => array("text", $row["obj_type"]),
397  "yyyy" => array("integer", $row["yyyy"]),
398  "mm" => array("integer", $row["mm"]),
399  "dd" => array("integer", $row["dd"]),
400  "hh" => array("integer", $row["hh"]));
401 
402  $where_sql = array();
403  foreach($where as $field => $def)
404  {
405  $where_sql[] = $field." = ".$ilDB->quote($def[1], $def[0]);
406  }
407  $where_sql = implode(" AND ", $where_sql);
408 
409  // existing entry?
410  $check = $ilDB->query("SELECT read_count, childs_read_count, spent_seconds,".
411  "childs_spent_seconds".
412  " FROM obj_stat".
413  " WHERE ".$where_sql);
414  if($ilDB->numRows($check))
415  {
416  $old = $ilDB->fetchAssoc($check);
417 
418  // add existing values
419  $fields = array("read_count" => array("integer", $old["read_count"]+$row["read_count"]),
420  "childs_read_count" => array("integer", $old["childs_read_count"]+$row["childs_read_count"]),
421  "spent_seconds" => array("integer", $old["spent_seconds"]+$row["spent_seconds"]),
422  "childs_spent_seconds" => array("integer", $old["childs_spent_seconds"]+$row["childs_spent_seconds"]));
423 
424  $ilDB->update("obj_stat", $fields, $where);
425  }
426  else
427  {
428  // new entry
429  $fields = $where;
430  $fields["read_count"] = array("integer", $row["read_count"]);
431  $fields["childs_read_count"] = array("integer", $row["childs_read_count"]);
432  $fields["spent_seconds"] = array("integer", $row["spent_seconds"]);
433  $fields["childs_spent_seconds"] = array("integer", $row["childs_spent_seconds"]);
434 
435  $ilDB->insert("obj_stat", $fields);
436  }
437  }
438 
439  // clean up transfer table
440  $ilDB->query("DELETE FROM obj_stat_tmp");
441  }
442 
443  // remove all locks (does not matter if transfer was actually performed)
444  $ilDB->unlockTables();
445  }
446  }
const LOCK_WRITE
Definition: class.ilDB.php:30
+ Here is the caller graph for this function:

◆ _updateAccessForScormOfflinePlayer()

ilChangeEvent::_updateAccessForScormOfflinePlayer (   $obj_id,
  $usr_id,
  $i_last_access,
  $t_first_access 
)

_updateAccessForScormOfflinePlayer needed to synchronize last_access and first_access when learning modul is used offline called in .

/Modules/ScormAicc/classes/class.ilSCORMOfflineMode.php

Returns
true

Definition at line 982 of file class.ilChangeEvent.php.

References $res, and $usr_id.

Referenced by ilSCORMOfflineMode\scormPlayerUnloadForSop2il().

982  {
983  global $ilDB;
984  $res = $ilDB->queryF('UPDATE read_event SET first_access=%s, last_access = %s WHERE obj_id=%s AND usr_id=%s',
985  array('timestamp','integer','integer','integer'),
986  array($t_first_access,$i_last_access,$obj_id,$usr_id)
987  );
988  return $res;
989  }
+ Here is the caller graph for this function:

◆ hasAccessed()

static ilChangeEvent::hasAccessed (   $a_obj_id,
  $a_usr_id 
)
static

Has accessed.

Definition at line 824 of file class.ilChangeEvent.php.

Referenced by ilLPStatusManual\determineStatus(), ilLPStatusVisits\determineStatus(), ilLPStatusTypicalLearningTime\determineStatus(), ilLPStatusExerciseReturned\determineStatus(), ilLPStatusObjectives\determineStatus(), ilLPStatusManualByTutor\determineStatus(), ilLPStatusSCORM\determineStatus(), and ilLPStatusCollection\determineStatus().

825  {
826  global $ilDB;
827 
828  if (isset(self::$has_accessed[$a_obj_id][$a_usr_id]))
829  {
830  return self::$has_accessed[$a_obj_id][$a_usr_id];
831  }
832 
833  $set = $ilDB->query("SELECT usr_id FROM read_event WHERE ".
834  "obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
835  "usr_id = ".$ilDB->quote($a_usr_id, "integer")
836  );
837  if ($rec = $ilDB->fetchAssoc($set))
838  {
839  return self::$has_accessed[$a_obj_id][$a_usr_id] = true;
840  }
841  return self::$has_accessed[$a_obj_id][$a_usr_id] = false;
842  }
+ Here is the caller graph for this function:

◆ lookupUsersInProgress()

static ilChangeEvent::lookupUsersInProgress (   $a_obj_id)
static

Lookup users in progress.

Returns

Definition at line 806 of file class.ilChangeEvent.php.

References $query, $res, and $row.

Referenced by ilLPStatusManual\_getInProgress(), ilLPStatusObjectives\_getInProgress(), ilLPStatusExerciseReturned\_getInProgress(), ilLPStatusCollection\_getInProgress(), and ilLPStatusManualByTutor\_getInProgress().

807  {
808  global $ilDB;
809 
810  $query = sprintf('SELECT DISTINCT(usr_id) usr FROM read_event '.
811  'WHERE obj_id = %s ',
812  $ilDB->quote($a_obj_id,'integer'));
813  $res = $ilDB->query($query);
814  while($row = $ilDB->fetchObject($res))
815  {
816  $users[] = $row->usr;
817  }
818  return $users ? $users : array();
819  }
+ Here is the caller graph for this function:

Field Documentation

◆ $has_accessed

ilChangeEvent::$has_accessed = array()
staticprivate

Definition at line 38 of file class.ilChangeEvent.php.


The documentation for this class was generated from the following file: