ILIAS  release_5-2 Revision v5.2.25-18-g3f80b82851
ilChangeEvent Class Reference

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

+ Collaboration diagram for ilChangeEvent:

Static Public Member Functions

static _recordWriteEvent ($obj_id, $usr_id, $action, $parent_obj_id=null)
 Records a write event. More...
 
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. More...
 
static _recordObjStats ($a_obj_id, $a_spent_seconds, $a_read_count, $a_childs_spent_seconds=null, $a_child_read_count=null)
 
static _syncObjectStats ($a_now=null, $a_minimum=20000)
 Process object statistics log data. More...
 
static _catchupWriteEvents ($obj_id, $usr_id, $timestamp=null)
 Catches up with all write events which occured before the specified timestamp. More...
 
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 _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 _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 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 829 of file class.ilChangeEvent.php.

References $ilDB, $ilSetting, $query, $res, and _isActive().

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

829  {
831  {
832  return 'change event tracking is already active';
833  }
834  else
835  {
836  global $ilDB;
837 
838  // Insert initial data into table write_event
839  // We need to do this here, because we need
840  // to catch up write events that occured while the change event tracking was
841  // deactivated.
842 
843  // IGNORE isn't supported in oracle
844  $set = $ilDB->query(sprintf('SELECT r1.obj_id,r2.obj_id p,d.owner,%s,d.create_date '.
845  'FROM object_data d '.
846  'LEFT JOIN write_event w ON d.obj_id = w.obj_id '.
847  'JOIN object_reference r1 ON d.obj_id=r1.obj_id '.
848  'JOIN tree t ON t.child=r1.ref_id '.
849  'JOIN object_reference r2 on r2.ref_id=t.parent '.
850  'WHERE w.obj_id IS NULL',
851  $ilDB->quote('create','text')));
852  while ($rec = $ilDB->fetchAssoc($set))
853  {
854  $nid = $ilDB->nextId("write_event");
855  $query = 'INSERT INTO write_event '.
856  '(write_id, obj_id,parent_obj_id,usr_id,action,ts) VALUES ('.
857  $ilDB->quote($nid, "integer").",".
858  $ilDB->quote($rec["obj_id"], "integer").",".
859  $ilDB->quote($rec["p"], "integer").",".
860  $ilDB->quote($rec["owner"], "integer").",".
861  $ilDB->quote("create", "text").",".
862  $ilDB->quote($rec["create_date"], "timestamp").
863  ')';
864  $res = $ilDB->query($query);
865  }
866 
867  global $ilSetting;
868  $ilSetting->set('enable_change_event_tracking', '1');
869 
870  return $res;
871  }
872  }
global $ilSetting
Definition: privfeed.php:17
static _isActive()
Returns true, if change event tracking is active.
global $ilDB
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _catchupWriteEvents()

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

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 504 of file class.ilChangeEvent.php.

References $ilDB, $query, $res, $timestamp, array, and ilUtil\now().

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

505  {
506  global $ilDB;
507 
508  $query = "SELECT obj_id FROM catch_write_events ".
509  "WHERE obj_id = ".$ilDB->quote($obj_id ,'integer')." ".
510  "AND usr_id = ".$ilDB->quote($usr_id ,'integer');
511  $res = $ilDB->query($query);
512  if($res->numRows())
513  {
514  $ts = ($timestamp == null)
515  ? ilUtil::now()
516  : $timestamp;
517 /* $query = "UPDATE catch_write_events ".
518  "SET ts = ".($timestamp == null ? $ilDB->now() : $ilDB->quote($timestamp, 'timestamp'))." ".
519  "WHERE usr_id = ".$ilDB->quote($usr_id ,'integer')." ".
520  "AND obj_id = ".$ilDB->quote($obj_id ,'integer');
521  $res = $ilDB->manipulate($query);*/
522  }
523  else
524  {
525  $ts = ilUtil::now();
526 /* $query = "INSERT INTO catch_write_events (ts,obj_id,usr_id) ".
527  "VALUES( ".
528  $ilDB->now().", ".
529  $ilDB->quote($obj_id,'integer').", ".
530  $ilDB->quote($usr_id,'integer')." ".
531  ")";
532  $res = $ilDB->manipulate($query);*/
533  }
534 
535  // alex, use replace due to bug #10406
536  $ilDB->replace("catch_write_events",
537  array(
538  "obj_id" => array("integer", $obj_id),
539  "usr_id" => array("integer", $usr_id)
540  ),
541  array(
542  "ts" => array("timestamp", $ts))
543  );
544  }
static now()
Return current timestamp in Y-m-d H:i:s format.
Create styles array
The data for the language used.
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:81
global $ilDB
+ Here is the call graph for this function:
+ 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 879 of file class.ilChangeEvent.php.

References $ilSetting.

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

879  {
880  global $ilSetting;
881  $ilSetting->set('enable_change_event_tracking', '0');
882  }
global $ilSetting
Definition: privfeed.php:17
+ Here is the caller graph for this function:

◆ _delete()

static ilChangeEvent::_delete (   $a_obj_id)
static

Delete object entries.

Returns

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

References $ilDB, and $query.

Referenced by ilObjectLP\handleDelete().

901  {
902  global $ilDB;
903 
904  $query = sprintf('DELETE FROM write_event WHERE obj_id = %s ',
905  $ilDB->quote($a_obj_id,'integer'));
906  $aff = $ilDB->manipulate($query);
907 
908  $query = sprintf('DELETE FROM read_event WHERE obj_id = %s ',
909  $ilDB->quote($a_obj_id,'integer'));
910  $aff = $ilDB->manipulate($query);
911  return true;
912  }
global $ilDB
+ Here is the caller graph for this function:

◆ _deleteReadEvents()

static ilChangeEvent::_deleteReadEvents (   $a_obj_id)
static

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

References $ilDB.

915  {
916  global $ilDB;
917 
918  $ilDB->manipulate("DELETE FROM read_event".
919  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer"));
920  }
global $ilDB

◆ _deleteReadEventsForUsers()

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

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

References $ilDB.

Referenced by ilObjSCORM2004LearningModule\deleteTrackingDataOfUsers(), ilObjSCORMLearningModule\deleteTrackingDataOfUsers(), and ilObjectLP\resetLPDataForUserIds().

923  {
924  global $ilDB;
925 
926  $ilDB->manipulate("DELETE FROM read_event".
927  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer").
928  " AND ".$ilDB->in("usr_id", $a_user_ids, "", "integer"));
929  }
global $ilDB
+ Here is the caller graph for this function:

◆ _getAllUserIds()

static ilChangeEvent::_getAllUserIds (   $a_obj_id)
static

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

References $ilDB, $res, $row, and array.

Referenced by ilObjectLP\gatherLPUsers().

932  {
933  global $ilDB;
934 
935  $res = array();
936 
937  $set = $ilDB->query("SELECT usr_id FROM read_event".
938  " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer"));
939  while($row = $ilDB->fetchAssoc($set))
940  {
941  $res[] = $row["usr_id"];
942  }
943 
944  return $res;
945  }
Create styles array
The data for the language used.
global $ilDB
+ 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 889 of file class.ilChangeEvent.php.

References $ilSetting.

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

889  {
890  global $ilSetting;
891  return $ilSetting->get('enable_change_event_tracking', '0') == '1';
892  }
global $ilSetting
Definition: privfeed.php:17
+ 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 646 of file class.ilChangeEvent.php.

References $ilDB, $query, $r, $res, $row, and ilDBConstants\FETCHMODE_ASSOC.

Referenced by ilTrackingTest\testChangeEvent().

647  {
648  global $ilDB;
649 
650  $q = "SELECT ts ".
651  "FROM catch_write_events ".
652  "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
653  "AND usr_id=".$ilDB->quote($usr_id ,'integer');
654  $r = $ilDB->query($q);
655  $catchup = null;
656  while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
657  $catchup = $row['ts'];
658  }
659 
660  if($catchup == null)
661  {
662  $ilDB->setLimit(1);
663  $query = sprintf('SELECT * FROM write_event '.
664  'WHERE obj_id = %s '.
665  'AND usr_id <> %s ',
666  $ilDB->quote($obj_id,'integer'),
667  $ilDB->quote($usr_id,'integer'));
668  $res = $ilDB->query($query);
669  }
670  else
671  {
672  $ilDB->setLimit(1);
673  $query = sprintf('SELECT * FROM write_event '.
674  'WHERE obj_id = %s '.
675  'AND usr_id <> %s '.
676  'AND ts > %s ',
677  $ilDB->quote($obj_id,'integer'),
678  $ilDB->quote($usr_id,'integer'),
679  $ilDB->quote($catchup,'timestamp'));
680  $res = $ilDB->query($query);
681  }
682 
683  $numRows = $res->numRows();
684  if ($numRows > 0)
685  {
686  $row = $ilDB->fetchAssoc($res);
687  // if we have write events, and user never catched one, report as new (1)
688  // if we have write events, and user catched an old write event, report as changed (2)
689  return ($catchup == null) ? 1 : 2;
690  }
691  else
692  {
693  return 0; // user catched all write events, report as unchanged (0)
694  }
695  }
$r
Definition: example_031.php:79
global $ilDB
+ 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(ilDBConstants::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(ilDBConstants::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 741 of file class.ilChangeEvent.php.

References $counter, $ilDB, $query, $res, $row, and array.

Referenced by ilLPStatusDownloaded\_getCompleted(), 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().

742  {
743  global $ilDB;
744 
745  if ($usr_id == null)
746  {
747  $query = sprintf('SELECT * FROM read_event '.
748  'WHERE obj_id = %s '.
749  'ORDER BY last_access DESC',
750  $ilDB->quote($obj_id,'integer'));
751  $res = $ilDB->query($query);
752  }
753  else
754  {
755  $query = sprintf('SELECT * FROM read_event '.
756  'WHERE obj_id = %s '.
757  'AND usr_id = %s '.
758  'ORDER BY last_access DESC',
759  $ilDB->quote($obj_id,'integer'),
760  $ilDB->quote($usr_id,'integer'));
761  $res = $ilDB->query($query);
762  }
763 
764  $counter = 0;
765  while ($row = $ilDB->fetchAssoc($res))
766  {
767  $events[$counter]['obj_id'] = $row['obj_id'];
768  $events[$counter]['usr_id'] = $row['usr_id'];
769  $events[$counter]['last_access'] = $row['last_access'];
770  $events[$counter]['read_count'] = $row['read_count'];
771  $events[$counter]['spent_seconds'] = $row['spent_seconds'];
772  $events[$counter]['first_access'] = $row['first_access'];
773 
774  $counter++;
775 
776  }
777  return $events ? $events : array();
778  }
$counter
Create styles array
The data for the language used.
global $ilDB
+ 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 593 of file class.ilChangeEvent.php.

References $ilDB, $query, $r, $res, $row, array, and ilDBConstants\FETCHMODE_ASSOC.

Referenced by ilTrackingTest\testChangeEvent().

594  {
595  global $ilDB;
596 
597  $q = "SELECT ts ".
598  "FROM catch_write_events ".
599  "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
600  "AND usr_id=".$ilDB->quote($usr_id ,'integer');
601  $r = $ilDB->query($q);
602  $catchup = null;
603  while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
604  $catchup = $row['ts'];
605  }
606 
607  if($catchup == null)
608  {
609  $query = sprintf('SELECT * FROM write_event '.
610  'WHERE obj_id = %s '.
611  'AND usr_id <> %s '.
612  'ORDER BY ts DESC',
613  $ilDB->quote($obj_id,'integer'),
614  $ilDB->quote($usr_id,'integer'));
615  $res = $ilDB->query($query);
616  }
617  else
618  {
619  $query = sprintf('SELECT * FROM write_event '.
620  'WHERE obj_id = %s '.
621  'AND usr_id <> %s '.
622  'AND ts >= %s '.
623  'ORDER BY ts DESC',
624  $ilDB->quote($obj_id,'integer'),
625  $ilDB->quote($usr_id,'integer'),
626  $ilDB->quote($catchup,'timestamp'));
627  $res = $ilDB->query($query);
628  }
629  $events = array();
630  while($row = $ilDB->fetchAssoc($res))
631  {
632  $events[] = $row;
633  }
634  return $events;
635  }
$r
Definition: example_031.php:79
Create styles array
The data for the language used.
global $ilDB
+ Here is the caller graph for this function:

◆ _recordObjStats()

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

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

References $ilDB, ilObjUserTracking\_enabledObjectStatistics(), ilObject\_lookupType(), array, date, and time.

325  {
326  global $ilDB;
327 
329  (int)$a_obj_id <= 0) // #12706
330  {
331  return;
332  }
333 
334  $now = time();
335 
336  $fields = array();
337  $fields['log_id'] = array("integer", $ilDB->nextId('obj_stat_log'));
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  {
366  self::_syncObjectStats($now);
367  }
368  }
static _enabledObjectStatistics()
check wether object statistics is enabled or not
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
Create styles array
The data for the language used.
static _lookupType($a_id, $a_reference=false)
lookup object type
global $ilDB
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
+ Here is the call graph for this function:

◆ _recordReadEvent()

static ilChangeEvent::_recordReadEvent (   $a_type,
  $a_ref_id,
  $obj_id,
  $usr_id,
  $isCatchupWriteEvents = true,
  $a_ext_rc = false,
  $a_ext_time = false 
)
static

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 112 of file class.ilChangeEvent.php.

References $a_type, $ilDB, $path, $query, $res, $row, $time_diff, _catchupWriteEvents(), ilObjUserTracking\_getValidTimeSpan(), ilObject\_lookupObjId(), ilObject\_lookupType(), array, date, and time.

Referenced by ilLicense\_noteAccess(), ilObjSCORMTracking\_syncReadEvent(), ilSCORM2004Tracking\_syncReadEvent(), ilLearningProgress\_tracProgress(), ilRemoteObjectBaseGUI\callObject(), ilDAVServer\COPY(), ilDAVServer\GET(), ilObjMediaCast\handleLPUpdate(), ilObjSCORMLearningModule\importSuccessForSahsUser(), ilWikiPageGUI\increaseViewCount(), ilObjSessionGUI\infoScreen(), ilContainerGUI\performPasteIntoMultipleObjectsObject(), ilDAVServer\PROPFIND(), ilObjLinkResourceGUI\redirectToLink(), ilObjPortfolioBaseGUI\renderFullscreenHeader(), ilObjBlogGUI\renderFullscreenHeader(), ilObjFileGUI\sendFile(), ilContainerContentGUI\setOutput(), ilObjMediaCastGUI\showContentObject(), ilObjSCORMTracking\syncGlobalStatus(), ilObjTestGUI\trackTestObjectReadEvent(), ilCourseContentGUI\view(), and ilObjectGUI\viewObject().

114  {
115  global $ilDB, $tree;
116 
117  /* read_event data is now used for several features, so we are always keeping track
118  if (!ilChangeEvent::_isActive())
119  {
120  return;
121  }
122  */
123 
124  include_once('Services/Tracking/classes/class.ilObjUserTracking.php');
125  $validTimeSpan = ilObjUserTracking::_getValidTimeSpan();
126 
127  $query = sprintf('SELECT * FROM read_event '.
128  'WHERE obj_id = %s '.
129  'AND usr_id = %s ',
130  $ilDB->quote($obj_id,'integer'),
131  $ilDB->quote($usr_id,'integer'));
132  $res = $ilDB->query($query);
133  $row = $ilDB->fetchObject($res);
134 
135  // read counter
136  if ($a_ext_rc !== false)
137  {
138  $read_count = 'read_count = '.$ilDB->quote($a_ext_rc, "integer").", ";
139  $read_count_init = max(1, (int) $a_ext_rc);
140  $read_count_diff = max(1, (int) $a_ext_rc) - $row->read_count;
141  }
142  else
143  {
144  $read_count = 'read_count = read_count + 1, ';
145  $read_count_init = 1;
146  $read_count_diff = 1;
147  }
148 
149  if ($row)
150  {
151 
152  if ($a_ext_time !== false)
153  {
154  $time = (int) $a_ext_time;
155  }
156  else
157  {
158  $time = $ilDB->quote((time() - $row->last_access) <= $validTimeSpan
159  ? $row->spent_seconds + time() - $row->last_access
160  : $row->spent_seconds,'integer');
161 
162  // if we are in the valid interval, we do not
163  // add anything to the read_count, since this is the
164  // same access for us
165  if ((time() - $row->last_access) <= $validTimeSpan)
166  {
167  $read_count = '';
168  $read_count_init = 1;
169  $read_count_diff = 0;
170  }
171  }
172  $time_diff = $time - (int) $row->spent_seconds;
173 
174  // Update
175  $query = sprintf('UPDATE read_event SET '.
176  $read_count.
177  'spent_seconds = %s, '.
178  'last_access = %s '.
179  'WHERE obj_id = %s '.
180  'AND usr_id = %s ',
181  $time,
182  $ilDB->quote(time(),'integer'),
183  $ilDB->quote($obj_id,'integer'),
184  $ilDB->quote($usr_id,'integer'));
185  $aff = $ilDB->manipulate($query);
186 
187  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
188  }
189  else
190  {
191  if ($a_ext_time !== false)
192  {
193  $time = (int) $a_ext_time;
194  }
195  else
196  {
197  $time = 0;
198  }
199 
200  $time_diff = $time - (int) $row->spent_seconds;
201 
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  $ilDB->manipulate($query);
211  */
212 
213  // #10407
214  $ilDB->replace('read_event',
215  array(
216  'obj_id' => array('integer', $obj_id),
217  'usr_id' => array('integer', $usr_id)
218  ),
219  array(
220  'read_count' => array('integer', $read_count_init),
221  'spent_seconds' => array('integer', $time),
222  'first_access' => array('timestamp', date("Y-m-d H:i:s")), // was $ilDB->now()
223  'last_access' => array('integer', time())
224  )
225  );
226 
227  self::$has_accessed[$obj_id][$usr_id] = true;
228 
229  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
230  }
231 
232  if ($isCatchupWriteEvents)
233  {
234  ilChangeEvent::_catchupWriteEvents($obj_id, $usr_id);
235  }
236 
237  // update parents (no categories or root)
238  if (!in_array($a_type, array("cat", "root", "crs")))
239  {
240  if ($tree->isInTree($a_ref_id))
241  {
242  $path = $tree->getPathId($a_ref_id);
243 
244  foreach ($path as $p)
245  {
246  $obj2_id = ilObject::_lookupObjId($p);
247  $obj2_type = ilObject::_lookupType($obj2_id);
248 //echo "<br>1-$obj2_type-$p-$obj2_id-";
249  if (($p != $a_ref_id) && (in_array($obj2_type, array("crs", "fold", "grp"))))
250  {
251  $query = sprintf('SELECT * FROM read_event '.
252  'WHERE obj_id = %s '.
253  'AND usr_id = %s ',
254  $ilDB->quote($obj2_id, 'integer'),
255  $ilDB->quote($usr_id, 'integer'));
256  $res2 = $ilDB->query($query);
257  if ($row2 = $ilDB->fetchAssoc($res2))
258  {
259 //echo "<br>2";
260  // update read count and spent seconds
261  $query = sprintf('UPDATE read_event SET '.
262  'childs_read_count = childs_read_count + %s ,'.
263  'childs_spent_seconds = childs_spent_seconds + %s '.
264  'WHERE obj_id = %s '.
265  'AND usr_id = %s ',
266  $ilDB->quote((int) $read_count_diff,'integer'),
267  $ilDB->quote((int) $time_diff,'integer'),
268  $ilDB->quote($obj2_id,'integer'),
269  $ilDB->quote($usr_id,'integer'));
270  $aff = $ilDB->manipulate($query);
271 
272  self::_recordObjStats($obj2_id, null, null, (int)$time_diff, (int)$read_count_diff);
273  }
274  else
275  {
276 //echo "<br>3";
277 //$ilLog->write("insert read event for obj_id -".$obj2_id."-".$usr_id."-");
278  /*
279  $query = sprintf('INSERT INTO read_event (obj_id,usr_id,last_access,read_count,spent_seconds,first_access,'.
280  'childs_read_count, childs_spent_seconds) '.
281  'VALUES (%s,%s,%s,%s,%s,'.$ilDB->now().', %s, %s) ',
282  $ilDB->quote($obj2_id,'integer'),
283  $ilDB->quote($usr_id,'integer'),
284  $ilDB->quote(time(),'integer'),
285  $ilDB->quote(1,'integer'),
286  $ilDB->quote($time,'integer'),
287  $ilDB->quote((int) $read_count_diff,'integer'),
288  $ilDB->quote((int) $time_diff,'integer')
289  );
290  $aff = $ilDB->manipulate($query);
291  */
292 
293  // #10407
294  $ilDB->replace('read_event',
295  array(
296  'obj_id' => array('integer', $obj2_id),
297  'usr_id' => array('integer', $usr_id)
298  ),
299  array(
300  'read_count' => array('integer', 1),
301  'spent_seconds' => array('integer', $time),
302  'first_access' => array('timestamp', date("Y-m-d H:i:s")), // was $ilDB->now()
303  'last_access' => array('integer', time()),
304  'childs_read_count' => array('integer', (int)$read_count_diff),
305  'childs_spent_seconds' => array('integer', (int)$time_diff)
306  )
307  );
308 
309  self::$has_accessed[$obj2_id][$usr_id] = true;
310 
311  self::_recordObjStats($obj2_id, $time, 1, (int)$time_diff, (int)$read_count_diff);
312  }
313  }
314  }
315  }
316  }
317 
318  // @todo:
319  // - calculate diff of spent_seconds and read_count
320  // - use ref id to get parents of types grp, crs, fold
321  // - add diffs to childs_spent_seconds and childs_read_count
322  }
$path
Definition: aliased.php:25
static _catchupWriteEvents($obj_id, $usr_id, $timestamp=null)
Catches up with all write events which occured before the specified timestamp.
$a_type
Definition: workflow.php:93
$time_diff
Definition: langcheck.php:760
static _lookupObjId($a_id)
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
Create styles array
The data for the language used.
static _lookupType($a_id, $a_reference=false)
lookup object type
global $ilDB
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _recordWriteEvent()

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

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 $ilDB, and $query.

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

◆ _syncObjectStats()

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

Process object statistics log data.

Parameters
integer$a_now
integer$a_minimum

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

References $ilDB, $old, $ret, $row, array, ilDBInterface\buildAtomQuery(), ilDBInterface\fetchAssoc(), ilDBInterface\insert(), ilDBInterface\numRows(), ilDBInterface\query(), ilDBInterface\quote(), time, and ilDBInterface\update().

Referenced by ilLPObjectStatisticsGUI\adminSync().

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  $ilAtomQuery = $ilDB->buildAtomQuery();
393  $ilAtomQuery->addTableLock('obj_stat_log');
394  $ilAtomQuery->addTableLock('obj_stat_tmp');
395 
396  $ilAtomQuery->addQueryCallable(function(ilDBInterface $ilDB) use($a_now, $a_minimum, &$ret){
397 
398  // if other process was transferring, we had to wait for the lock and
399  // the source table should now have less than minimum/needed entries
400  $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
401  $row = $ilDB->fetchAssoc($set);
402  if($row["counter"] >= $a_minimum)
403  {
404  // use only "full" seconds to have a clear cut
405  $ilDB->query("INSERT INTO obj_stat_tmp".
406  " SELECT * FROM obj_stat_log".
407  " WHERE tstamp < ".$ilDB->quote($a_now, "timestamp"));
408 
409  // remove transferred entries from source table
410  $ilDB->query("DELETE FROM obj_stat_log".
411  " WHERE tstamp < ".$ilDB->quote($a_now, "timestamp"));
412 
413  $ret = true;
414  }
415  else
416  {
417  $ret = false;
418  }
419  });
420 
421  $ilAtomQuery->run();
422 
423  //continue only if obj_stat_log counter >= $a_minimum
424  if($ret)
425  {
426  $ilAtomQuery = $ilDB->buildAtomQuery();
427  $ilAtomQuery->addTableLock('obj_stat_tmp');
428  $ilAtomQuery->addTableLock('obj_stat');
429 
430  $ilAtomQuery->addQueryCallable(function(ilDBInterface $ilDB) use($a_now, $a_minimum){
431 
432  // process log data (timestamp is not needed anymore)
433  $sql = "SELECT obj_id, obj_type, yyyy, mm, dd, hh, SUM(read_count) AS read_count,".
434  " SUM(childs_read_count) AS childs_read_count, SUM(spent_seconds) AS spent_seconds,".
435  " SUM(childs_spent_seconds) AS childs_spent_seconds".
436  " FROM obj_stat_tmp".
437  " GROUP BY obj_id, obj_type, yyyy, mm, dd, hh";
438  $set = $ilDB->query($sql);
439  while($row = $ilDB->fetchAssoc($set))
440  {
441  // "primary key"
442  $where = array("obj_id" => array("integer", $row["obj_id"]),
443  "obj_type" => array("text", $row["obj_type"]),
444  "yyyy" => array("integer", $row["yyyy"]),
445  "mm" => array("integer", $row["mm"]),
446  "dd" => array("integer", $row["dd"]),
447  "hh" => array("integer", $row["hh"]));
448 
449  $where_sql = array();
450  foreach($where as $field => $def)
451  {
452  $where_sql[] = $field." = ".$ilDB->quote($def[1], $def[0]);
453  }
454  $where_sql = implode(" AND ", $where_sql);
455 
456  // existing entry?
457  $check = $ilDB->query("SELECT read_count, childs_read_count, spent_seconds,".
458  "childs_spent_seconds".
459  " FROM obj_stat".
460  " WHERE ".$where_sql);
461  if($ilDB->numRows($check))
462  {
463  $old = $ilDB->fetchAssoc($check);
464 
465  // add existing values
466  $fields = array("read_count" => array("integer", $old["read_count"]+$row["read_count"]),
467  "childs_read_count" => array("integer", $old["childs_read_count"]+$row["childs_read_count"]),
468  "spent_seconds" => array("integer", $old["spent_seconds"]+$row["spent_seconds"]),
469  "childs_spent_seconds" => array("integer", $old["childs_spent_seconds"]+$row["childs_spent_seconds"]));
470 
471  $ilDB->update("obj_stat", $fields, $where);
472  }
473  else
474  {
475  // new entry
476  $fields = $where;
477  $fields["read_count"] = array("integer", $row["read_count"]);
478  $fields["childs_read_count"] = array("integer", $row["childs_read_count"]);
479  $fields["spent_seconds"] = array("integer", $row["spent_seconds"]);
480  $fields["childs_spent_seconds"] = array("integer", $row["childs_spent_seconds"]);
481 
482  $ilDB->insert("obj_stat", $fields);
483  }
484  }
485 
486  // clean up transfer table
487  $ilDB->query("DELETE FROM obj_stat_tmp");
488 
489  });
490 
491  $ilAtomQuery->run();
492  }
493  }
494  }
update($table_name, $values, $where)
numRows($query_result)
Interface ilDBInterface.
quote($value, $type)
$old
Create styles array
The data for the language used.
global $ilDB
$ret
Definition: parser.php:6
query($query)
insert($table_name, $values)
fetchAssoc($query_result)
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _updateAccessForScormOfflinePlayer()

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

_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 953 of file class.ilChangeEvent.php.

References $ilDB, $res, and array.

Referenced by ilSCORMOfflineMode\scormPlayerUnloadForSop2il().

953  {
954  global $ilDB;
955  $res = $ilDB->queryF('UPDATE read_event SET first_access=%s, last_access = %s WHERE obj_id=%s AND usr_id=%s',
956  array('timestamp','integer','integer','integer'),
957  array($t_first_access,$i_last_access,$obj_id,$usr_id)
958  );
959  return $res;
960  }
Create styles array
The data for the language used.
global $ilDB
+ Here is the caller graph for this function:

◆ hasAccessed()

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

Has accessed.

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

References $ilDB.

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

805  {
806  global $ilDB;
807 
808  if (isset(self::$has_accessed[$a_obj_id][$a_usr_id]))
809  {
810  return self::$has_accessed[$a_obj_id][$a_usr_id];
811  }
812 
813  $set = $ilDB->query("SELECT usr_id FROM read_event WHERE ".
814  "obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
815  "usr_id = ".$ilDB->quote($a_usr_id, "integer")
816  );
817  if ($rec = $ilDB->fetchAssoc($set))
818  {
819  return self::$has_accessed[$a_obj_id][$a_usr_id] = true;
820  }
821  return self::$has_accessed[$a_obj_id][$a_usr_id] = false;
822  }
global $ilDB
+ Here is the caller graph for this function:

◆ lookupUsersInProgress()

static ilChangeEvent::lookupUsersInProgress (   $a_obj_id)
static

Lookup users in progress.

Returns

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

References $ilDB, $query, $res, $row, and array.

Referenced by ilLPStatusQuestions\_getCompleted(), ilLPStatusQuestions\_getInProgress(), ilLPStatusVisitedPages\_getInProgress(), ilLPStatusManual\_getInProgress(), ilLPStatusExerciseReturned\_getInProgress(), ilLPStatusCollection\_getInProgress(), ilLPStatusManualByTutor\_getInProgress(), and ilLPStatusObjectives\_getStatusInfo().

787  {
788  global $ilDB;
789 
790  $query = sprintf('SELECT DISTINCT(usr_id) usr FROM read_event '.
791  'WHERE obj_id = %s ',
792  $ilDB->quote($a_obj_id,'integer'));
793  $res = $ilDB->query($query);
794  while($row = $ilDB->fetchObject($res))
795  {
796  $users[] = $row->usr;
797  }
798  return $users ? $users : array();
799  }
Create styles array
The data for the language used.
global $ilDB
+ 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: