ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
ilChangeEvent Class Reference

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

+ Collaboration diagram for ilChangeEvent:

Static Public Member Functions

static _recordWriteEvent (int $obj_id, int $usr_id, string $action, ?int $parent_obj_id=null)
 Records a write event. More...
 
static _recordReadEvent (string $a_type, int $a_ref_id, int $obj_id, int $usr_id, bool $isCatchupWriteEvents=true, $a_ext_rc=null, $a_ext_time=null)
 
static _recordObjStats (int $a_obj_id, ?int $a_spent_seconds, ?int $a_read_count, ?int $a_childs_spent_seconds=null, ?int $a_child_read_count=null)
 
static _syncObjectStats (?int $a_now=null, int $a_minimum=20000)
 
static _catchupWriteEvents (int $obj_id, int $usr_id, ?string $timestamp=null)
 Catches up with all write events which occured before the specified timestamp. More...
 
static _lookupUncaughtWriteEvents (int $obj_id, int $usr_id)
 Reads all write events which occured on the object which happened after the last time the user caught up with them. More...
 
static _lookupChangeState (int $obj_id, int $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. More...
 
static lookupUsersInProgress (int $a_obj_id)
 
static hasAccessed (int $a_obj_id, int $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 (int $a_obj_id)
 Delete object entries. More...
 
static _deleteReadEvents (int $a_obj_id)
 
static _deleteReadEventsForUsers (int $a_obj_id, array $a_user_ids)
 
static _getAllUserIds (int $a_obj_id)
 

Static Private Attributes

static array $has_accessed = []
 

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

Member Function Documentation

◆ _activate()

static ilChangeEvent::_activate ( )
static

Activates change event tracking.

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

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

Referenced by ilObjRepositorySettingsGUI\saveSettings().

765  : bool
766  {
767  if (ilChangeEvent::_isActive()) {
768  return false;
769  } else {
770  global $DIC;
771 
772  $ilDB = $DIC['ilDB'];
773 
774  // Insert initial data into table write_event
775  // We need to do this here, because we need
776  // to catch up write events that occured while the change event tracking was
777  // deactivated.
778 
779  // IGNORE isn't supported in oracle
780  $set = $ilDB->query(
781  sprintf(
782  'SELECT r1.obj_id,r2.obj_id p,d.owner,%s,d.create_date ' .
783  'FROM object_data d ' .
784  'LEFT JOIN write_event w ON d.obj_id = w.obj_id ' .
785  'JOIN object_reference r1 ON d.obj_id=r1.obj_id ' .
786  'JOIN tree t ON t.child=r1.ref_id ' .
787  'JOIN object_reference r2 on r2.ref_id=t.parent ' .
788  'WHERE w.obj_id IS NULL',
789  $ilDB->quote('create', 'text')
790  )
791  );
792  $res = null;
793  while ($rec = $ilDB->fetchAssoc($set)) {
794  $nid = $ilDB->nextId("write_event");
795  $query = 'INSERT INTO write_event ' .
796  '(write_id, obj_id,parent_obj_id,usr_id,action,ts) VALUES (' .
797  $ilDB->quote($nid, "integer") . "," .
798  $ilDB->quote($rec["obj_id"], "integer") . "," .
799  $ilDB->quote($rec["p"], "integer") . "," .
800  $ilDB->quote($rec["owner"], "integer") . "," .
801  $ilDB->quote("create", "text") . "," .
802  $ilDB->quote($rec["create_date"], "timestamp") .
803  ')';
804  $res = $ilDB->query($query);
805  }
806 
807  global $DIC;
808 
809  $ilSetting = $DIC['ilSetting'];
810  $ilSetting->set('enable_change_event_tracking', '1');
811 
812  return $res !== null;
813  }
814  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: feed.php:28
$query
global $ilSetting
Definition: privfeed.php:17
static _isActive()
Returns true, if change event tracking is active.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _catchupWriteEvents()

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

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

Parameters
$obj_idint The object.
$usr_idint The user.
$timestampstring|null timestamp.
Returns
void

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

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

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

529  : void {
530  global $DIC;
531 
532  $ilDB = $DIC['ilDB'];
533 
534  $query = "SELECT obj_id FROM catch_write_events " .
535  "WHERE obj_id = " . $ilDB->quote($obj_id, 'integer') . " " .
536  "AND usr_id = " . $ilDB->quote($usr_id, 'integer');
537  $res = $ilDB->query($query);
538  if ($res->numRows()) {
539  $ts = ($timestamp == null)
540  ? ilUtil::now()
541  : $timestamp;
542  } else {
543  $ts = ilUtil::now();
544  }
545 
546  // alex, use replace due to bug #10406
547  $ilDB->replace(
548  "catch_write_events",
549  array(
550  "obj_id" => array("integer", $obj_id),
551  "usr_id" => array("integer", $usr_id)
552  ),
553  array(
554  "ts" => array("timestamp", $ts)
555  )
556  );
557  }
$res
Definition: ltiservices.php:69
static now()
Return current timestamp in Y-m-d H:i:s format.
global $DIC
Definition: feed.php:28
$query
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:70
+ 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.

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

References $DIC, and $ilSetting.

Referenced by ilObjRepositorySettingsGUI\saveSettings().

819  : bool
820  {
821  global $DIC;
822 
823  $ilSetting = $DIC['ilSetting'];
824  $ilSetting->set('enable_change_event_tracking', '0');
825  return true;
826  }
global $DIC
Definition: feed.php:28
global $ilSetting
Definition: privfeed.php:17
+ Here is the caller graph for this function:

◆ _delete()

static ilChangeEvent::_delete ( int  $a_obj_id)
static

Delete object entries.

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

References $DIC, $ilDB, and $query.

Referenced by ilObjectLP\handleDelete().

842  : bool
843  {
844  global $DIC;
845 
846  $ilDB = $DIC['ilDB'];
847  $query = sprintf(
848  'DELETE FROM write_event WHERE obj_id = %s ',
849  $ilDB->quote($a_obj_id, 'integer')
850  );
851  $aff = $ilDB->manipulate($query);
852 
853  $query = sprintf(
854  'DELETE FROM read_event WHERE obj_id = %s ',
855  $ilDB->quote($a_obj_id, 'integer')
856  );
857  $aff = $ilDB->manipulate($query);
858  return true;
859  }
global $DIC
Definition: feed.php:28
$query
+ Here is the caller graph for this function:

◆ _deleteReadEvents()

static ilChangeEvent::_deleteReadEvents ( int  $a_obj_id)
static

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

References $DIC, and $ilDB.

861  : void
862  {
863  global $DIC;
864 
865  $ilDB = $DIC['ilDB'];
866 
867  $ilDB->manipulate(
868  "DELETE FROM read_event" .
869  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer")
870  );
871  }
global $DIC
Definition: feed.php:28

◆ _deleteReadEventsForUsers()

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

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

References $DIC, and $ilDB.

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

876  : void {
877  global $DIC;
878 
879  $ilDB = $DIC['ilDB'];
880 
881  $ilDB->manipulate(
882  "DELETE FROM read_event" .
883  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer") .
884  " AND " . $ilDB->in("usr_id", $a_user_ids, "", "integer")
885  );
886  }
global $DIC
Definition: feed.php:28
+ Here is the caller graph for this function:

◆ _getAllUserIds()

static ilChangeEvent::_getAllUserIds ( int  $a_obj_id)
static

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

References $DIC, $ilDB, $res, and ILIAS\Repository\int().

Referenced by ilObjectLP\gatherLPUsers().

888  : array
889  {
890  global $DIC;
891 
892  $ilDB = $DIC['ilDB'];
893  $res = array();
894  $set = $ilDB->query(
895  "SELECT usr_id FROM read_event" .
896  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer")
897  );
898  while ($row = $ilDB->fetchAssoc($set)) {
899  $res[] = (int) $row["usr_id"];
900  }
901  return $res;
902  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: feed.php:28
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _isActive()

static ilChangeEvent::_isActive ( )
static

Returns true, if change event tracking is active.

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

References $DIC, and $ilSetting.

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

831  : bool
832  {
833  global $DIC;
834 
835  $ilSetting = $DIC['ilSetting'];
836  return $ilSetting->get('enable_change_event_tracking', '0') == '1';
837  }
global $DIC
Definition: feed.php:28
global $ilSetting
Definition: privfeed.php:17
+ Here is the caller graph for this function:

◆ _lookupChangeState()

static ilChangeEvent::_lookupChangeState ( int  $obj_id,
int  $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
int 0 = object is unchanged, 1 = object is new, 2 = object has changed

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

References $DIC, $ilDB, $query, $res, and ilDBConstants\FETCHMODE_ASSOC.

622  : int
623  {
624  global $DIC;
625 
626  $ilDB = $DIC['ilDB'];
627 
628  $q = "SELECT ts " .
629  "FROM catch_write_events " .
630  "WHERE obj_id=" . $ilDB->quote($obj_id, 'integer') . " " .
631  "AND usr_id=" . $ilDB->quote($usr_id, 'integer');
632  $r = $ilDB->query($q);
633  $catchup = null;
634  while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
635  $catchup = $row['ts'];
636  }
637 
638  if ($catchup == null) {
639  $ilDB->setLimit(1);
640  $query = sprintf(
641  'SELECT * FROM write_event ' .
642  'WHERE obj_id = %s ' .
643  'AND usr_id <> %s ',
644  $ilDB->quote($obj_id, 'integer'),
645  $ilDB->quote($usr_id, 'integer')
646  );
647  $res = $ilDB->query($query);
648  } else {
649  $ilDB->setLimit(1);
650  $query = sprintf(
651  'SELECT * FROM write_event ' .
652  'WHERE obj_id = %s ' .
653  'AND usr_id <> %s ' .
654  'AND ts > %s ',
655  $ilDB->quote($obj_id, 'integer'),
656  $ilDB->quote($usr_id, 'integer'),
657  $ilDB->quote($catchup, 'timestamp')
658  );
659  $res = $ilDB->query($query);
660  }
661 
662  $numRows = $res->numRows();
663  if ($numRows > 0) {
664  $row = $ilDB->fetchAssoc($res);
665  // if we have write events, and user never catched one, report as new (1)
666  // if we have write events, and user catched an old write event, report as changed (2)
667  return ($catchup == null) ? 1 : 2;
668  } else {
669  return 0; // user catched all write events, report as unchanged (0)
670  }
671  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: feed.php:28
$query

◆ _lookupReadEvents()

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

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

References $DIC, $ilDB, $query, and $res.

Referenced by ilLPStatusContentVisited\_getCompleted(), ilLPStatusTypicalLearningTime\_getCompleted(), ilLPStatusVisits\_getCompleted(), ilLPStatusTypicalLearningTime\_getInProgress(), ilLPStatusVisits\_getInProgress(), ilLearningProgress\_getProgress(), ilLearningProgress\_lookupProgressByObjId(), ilInfoScreenGUI\addMetaDataSections(), ilLPStatusTypicalLearningTime\determinePercentage(), ilLPStatusVisits\determinePercentage(), ilLPStatusTypicalLearningTime\determineStatus(), ilLPStatusVisits\determineStatus(), ilObjSCORMLearningModule\importSuccessForSahsUser(), and ILIAS\MediaCast\Presentation\VideoViewGUI\renderSideColumn().

679  {
680  global $DIC;
681 
682  $ilDB = $DIC['ilDB'];
683 
684  if ($usr_id == null) {
685  $query = sprintf(
686  'SELECT * FROM read_event ' .
687  'WHERE obj_id = %s ' .
688  'ORDER BY last_access DESC',
689  $ilDB->quote($obj_id, 'integer')
690  );
691  $res = $ilDB->query($query);
692  } else {
693  $query = sprintf(
694  'SELECT * FROM read_event ' .
695  'WHERE obj_id = %s ' .
696  'AND usr_id = %s ' .
697  'ORDER BY last_access DESC',
698  $ilDB->quote($obj_id, 'integer'),
699  $ilDB->quote($usr_id, 'integer')
700  );
701  $res = $ilDB->query($query);
702  }
703 
704  $counter = 0;
705  $events = [];
706  while ($row = $ilDB->fetchAssoc($res)) {
707  $events[$counter]['obj_id'] = $row['obj_id'];
708  $events[$counter]['usr_id'] = $row['usr_id'];
709  $events[$counter]['last_access'] = $row['last_access'];
710  $events[$counter]['read_count'] = $row['read_count'];
711  $events[$counter]['spent_seconds'] = $row['spent_seconds'];
712  $events[$counter]['first_access'] = $row['first_access'];
713 
714  $counter++;
715  }
716  return $events;
717  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: feed.php:28
$query
+ Here is the caller graph for this function:

◆ _lookupUncaughtWriteEvents()

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

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

References $DIC, $ilDB, $query, $res, and ilDBConstants\FETCHMODE_ASSOC.

569  : array {
570  global $DIC;
571 
572  $ilDB = $DIC['ilDB'];
573  $q = "SELECT ts " .
574  "FROM catch_write_events " .
575  "WHERE obj_id=" . $ilDB->quote($obj_id, 'integer') . " " .
576  "AND usr_id=" . $ilDB->quote($usr_id, 'integer');
577  $r = $ilDB->query($q);
578  $catchup = null;
579  while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
580  $catchup = $row['ts'];
581  }
582 
583  if ($catchup == null) {
584  $query = sprintf(
585  'SELECT * FROM write_event ' .
586  'WHERE obj_id = %s ' .
587  'AND usr_id <> %s ' .
588  'ORDER BY ts DESC',
589  $ilDB->quote($obj_id, 'integer'),
590  $ilDB->quote($usr_id, 'integer')
591  );
592  $res = $ilDB->query($query);
593  } else {
594  $query = sprintf(
595  'SELECT * FROM write_event ' .
596  'WHERE obj_id = %s ' .
597  'AND usr_id <> %s ' .
598  'AND ts >= %s ' .
599  'ORDER BY ts DESC',
600  $ilDB->quote($obj_id, 'integer'),
601  $ilDB->quote($usr_id, 'integer'),
602  $ilDB->quote($catchup, 'timestamp')
603  );
604  $res = $ilDB->query($query);
605  }
606  $events = array();
607  while ($row = $ilDB->fetchAssoc($res)) {
608  $events[] = $row;
609  }
610  return $events;
611  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: feed.php:28
$query

◆ _recordObjStats()

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

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

References $DIC, $ilDB, ilObjUserTracking\_enabledObjectStatistics(), and ilObject\_lookupType().

315  : void {
316  global $DIC;
317 
318  $ilDB = $DIC['ilDB'];
319 
321  $a_obj_id <= 0) { // #12706
322  return;
323  }
324 
325  $now = time();
326 
327  $fields = array();
328  $fields['log_id'] = array("integer", $ilDB->nextId('obj_stat_log'));
329  $fields["obj_id"] = array("integer", $a_obj_id);
330  $fields["obj_type"] = array("text", ilObject::_lookupType($a_obj_id));
331  $fields["tstamp"] = array("timestamp", $now);
332  $fields["yyyy"] = array("integer", date("Y"));
333  $fields["mm"] = array("integer", date("m"));
334  $fields["dd"] = array("integer", date("d"));
335  $fields["hh"] = array("integer", date("H"));
336  if ($a_spent_seconds > 0) {
337  $fields["spent_seconds"] = array("integer", $a_spent_seconds);
338  }
339  if ($a_read_count > 0) {
340  $fields["read_count"] = array("integer", $a_read_count);
341  }
342  if ($a_childs_spent_seconds > 0) {
343  $fields["childs_spent_seconds"] = array("integer",
344  $a_childs_spent_seconds
345  );
346  }
347  if ($a_child_read_count > 0) {
348  $fields["childs_read_count"] = array("integer",
349  $a_child_read_count
350  );
351  }
352  $ilDB->insert("obj_stat_log", $fields);
353 
354  // 0.01% probability
355  if (mt_rand(1, 100) == 1) {
356  self::_syncObjectStats($now);
357  }
358  }
global $DIC
Definition: feed.php:28
static _lookupType(int $id, bool $reference=false)
+ Here is the call graph for this function:

◆ _recordReadEvent()

static ilChangeEvent::_recordReadEvent ( string  $a_type,
int  $a_ref_id,
int  $obj_id,
int  $usr_id,
bool  $isCatchupWriteEvents = true,
  $a_ext_rc = null,
  $a_ext_time = null 
)
static

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

References $DIC, $ilDB, $path, $query, $res, _catchupWriteEvents(), ilObjUserTracking\_getValidTimeSpan(), ilObject\_lookupObjId(), ilObject\_lookupType(), and ILIAS\Repository\int().

Referenced by ilSCORM2004Tracking\_syncReadEvent(), ilObjSCORMTracking\_syncReadEvent(), ilLearningProgress\_tracProgress(), ilRemoteObjectBaseGUI\callObject(), ilSurveyExecutionGUI\executeCommand(), ilObjForumGUI\getContent(), ilObjSCORMLearningModule\importSuccessForSahsUser(), ilWikiPageGUI\increaseViewCount(), ilContainerGUI\performPasteIntoMultipleObjectsObject(), ilObjIndividualAssessmentGUI\recordIndividualAssessmentRead(), ilObjLearningSequenceGUI\recordLearningSequenceRead(), ilObjLinkResourceGUI\redirectToLink(), ilObjPortfolioBaseGUI\renderFullscreenHeader(), ilObjBlogGUI\renderFullscreenHeader(), ilObjCategoryGUI\renderObject(), ILIAS\MediaObjects\Tracking\TrackingManager\saveCompletion(), ilObjFileGUI\sendFile(), ilContainerContentGUI\setOutput(), ilObjMediaCastGUI\showContentObject(), ilObjSessionGUI\showJoinRequestButton(), ilObjSCORMTracking\syncGlobalStatus(), ilLMTracker\trackAccess(), ilObjCmiXapiGUI\trackObjectReadEvent(), ilObjLTIConsumerGUI\trackObjectReadEvent(), ilObjTestGUI\trackTestObjectReadEvent(), ilObjectGUI\viewObject(), and ilObjForumGUI\viewThreadObject().

111  : void {
112  global $DIC;
113 
114  $ilDB = $DIC['ilDB'];
115  $tree = $DIC['tree'];
116 
117  $validTimeSpan = ilObjUserTracking::_getValidTimeSpan();
118 
119  $query = sprintf(
120  'SELECT * FROM read_event ' .
121  'WHERE obj_id = %s ' .
122  'AND usr_id = %s ',
123  $ilDB->quote($obj_id, 'integer'),
124  $ilDB->quote($usr_id, 'integer')
125  );
126  $res = $ilDB->query($query);
127  $row = $ilDB->fetchObject($res);
128 
129  // read counter
130  if ($a_ext_rc !== null) {
131  $read_count = 'read_count = ' . $ilDB->quote(
132  $a_ext_rc,
133  "integer"
134  ) . ", ";
135  $read_count_init = max(1, (int) $a_ext_rc);
136  $read_count_diff = max(1, (int) $a_ext_rc) - $row->read_count;
137  } else {
138  $read_count = 'read_count = read_count + 1, ';
139  $read_count_init = 1;
140  $read_count_diff = 1;
141  }
142 
143  if ($row) {
144  if ($a_ext_time !== null) {
145  $time = (int) $a_ext_time;
146  } else {
147  $time = $ilDB->quote(
148  (time() - $row->last_access) <= $validTimeSpan
149  ? $row->spent_seconds + time() - $row->last_access
150  : $row->spent_seconds,
151  'integer'
152  );
153 
154  // if we are in the valid interval, we do not
155  // add anything to the read_count, since this is the
156  // same access for us
157  if ((time() - $row->last_access) <= $validTimeSpan) {
158  $read_count = '';
159  $read_count_init = 1;
160  $read_count_diff = 0;
161  }
162  }
163  $time_diff = $time - (int) ($row->spent_seconds ?? 0);
164 
165  // Update
166  $query = sprintf(
167  'UPDATE read_event SET ' .
168  $read_count .
169  'spent_seconds = %s, ' .
170  'last_access = %s ' .
171  'WHERE obj_id = %s ' .
172  'AND usr_id = %s ',
173  $time,
174  $ilDB->quote(time(), 'integer'),
175  $ilDB->quote($obj_id, 'integer'),
176  $ilDB->quote($usr_id, 'integer')
177  );
178  $aff = $ilDB->manipulate($query);
179 
180  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
181  } else {
182  if ($a_ext_time !== false) {
183  $time = (int) $a_ext_time;
184  } else {
185  $time = 0;
186  }
187 
188  $time_diff = $time - (int) ($row->spent_seconds ?? 0);
189 
190  // #10407
191  $ilDB->replace(
192  'read_event',
193  array(
194  'obj_id' => array('integer', $obj_id),
195  'usr_id' => array('integer', $usr_id)
196  ),
197  array(
198  'read_count' => array('integer', $read_count_init),
199  'spent_seconds' => array('integer', $time),
200  'first_access' => array('timestamp', date("Y-m-d H:i:s")),
201  // was $ilDB->now()
202  'last_access' => array('integer', time())
203  )
204  );
205 
206  self::$has_accessed[$obj_id][$usr_id] = true;
207 
208  self::_recordObjStats($obj_id, $time_diff, $read_count_diff);
209  }
210 
211  if ($isCatchupWriteEvents) {
212  ilChangeEvent::_catchupWriteEvents($obj_id, $usr_id);
213  }
214 
215  // update parents (no categories or root)
216  if (!in_array($a_type, array("cat", "root", "crs"))) {
217  if ($tree->isInTree($a_ref_id)) {
218  $path = $tree->getPathId($a_ref_id);
219 
220  foreach ($path as $p) {
221  $obj2_id = ilObject::_lookupObjId($p);
222  $obj2_type = ilObject::_lookupType($obj2_id);
223  //echo "<br>1-$obj2_type-$p-$obj2_id-";
224  if (($p != $a_ref_id) && (in_array(
225  $obj2_type,
226  array("crs",
227  "fold",
228  "grp",
229  "lso"
230  )
231  ))) {
232  $query = sprintf(
233  'SELECT * FROM read_event ' .
234  'WHERE obj_id = %s ' .
235  'AND usr_id = %s ',
236  $ilDB->quote($obj2_id, 'integer'),
237  $ilDB->quote($usr_id, 'integer')
238  );
239  $res2 = $ilDB->query($query);
240  if ($row2 = $ilDB->fetchAssoc($res2)) {
241  //echo "<br>2";
242  // update read count and spent seconds
243  $query = sprintf(
244  'UPDATE read_event SET ' .
245  'childs_read_count = childs_read_count + %s ,' .
246  'childs_spent_seconds = childs_spent_seconds + %s ' .
247  'WHERE obj_id = %s ' .
248  'AND usr_id = %s ',
249  $ilDB->quote((int) $read_count_diff, 'integer'),
250  $ilDB->quote((int) $time_diff, 'integer'),
251  $ilDB->quote($obj2_id, 'integer'),
252  $ilDB->quote($usr_id, 'integer')
253  );
254  $aff = $ilDB->manipulate($query);
255 
256  self::_recordObjStats(
257  $obj2_id,
258  null,
259  null,
260  (int) $time_diff,
261  (int) $read_count_diff
262  );
263  } else {
264 
265  // #10407
266  $ilDB->replace(
267  'read_event',
268  array(
269  'obj_id' => array('integer', $obj2_id),
270  'usr_id' => array('integer', $usr_id)
271  ),
272  array(
273  'read_count' => array('integer', 1),
274  'spent_seconds' => array('integer', $time),
275  'first_access' => array('timestamp',
276  date("Y-m-d H:i:s")
277  ), // was $ilDB->now()
278  'last_access' => array('integer', time()),
279  'childs_read_count' => array('integer',
280  (int) $read_count_diff
281  ),
282  'childs_spent_seconds' => array('integer',
283  (int) $time_diff
284  )
285  )
286  );
287 
288  self::$has_accessed[$obj2_id][$usr_id] = true;
289 
290  self::_recordObjStats(
291  $obj2_id,
292  $time,
293  1,
294  (int) $time_diff,
295  (int) $read_count_diff
296  );
297  }
298  }
299  }
300  }
301  }
302 
303  // @todo:
304  // - calculate diff of spent_seconds and read_count
305  // - use ref id to get parents of types grp, crs, fold
306  // - add diffs to childs_spent_seconds and childs_read_count
307  }
$res
Definition: ltiservices.php:69
$path
Definition: ltiservices.php:32
static _lookupObjId(int $ref_id)
global $DIC
Definition: feed.php:28
$query
static _lookupType(int $id, bool $reference=false)
static _catchupWriteEvents(int $obj_id, int $usr_id, ?string $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()

static ilChangeEvent::_recordWriteEvent ( int  $obj_id,
int  $usr_id,
string  $action,
?int  $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
int$obj_idThe object which was written to.
int$usr_idThe user who performed a write action.
string$actionThe name of the write action. 'create', 'update', 'delete', 'add', 'remove', 'undelete'.
int | null$parent_obj_idThe 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.
Returns
void

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

References $DIC, $ilDB, and $query.

Referenced by ilObjCourseGUI\afterSave(), ilObjRootFolderGUI\getEditFormValues(), ilContainerGUI\pasteObject(), ilContainerGUI\performPasteIntoMultipleObjectsObject(), ilObject2GUI\putObjectInTree(), ilObjectGUI\putObjectInTree(), ilRepUtil\removeObjectsFromSystem(), ilRepUtil\restoreObjects(), ilObjFileGUI\update(), ilObjGroupGUI\updateObject(), ilObjCourseGUI\updateObject(), and ilObjCategoryGUI\updateObject().

52  : void {
53  global $DIC;
54 
55  $ilDB = $DIC['ilDB'];
56 
57  /* see _recordReadEvent
58  if (!ilChangeEvent::_isActive())
59  {
60  return;
61  }
62  */
63 
64  if ($parent_obj_id == null) {
65  $pset = $ilDB->query(
66  'SELECT r2.obj_id par_obj_id FROM object_reference r1 ' .
67  'JOIN tree t ON t.child = r1.ref_id ' .
68  'JOIN object_reference r2 ON r2.ref_id = t.parent ' .
69  'WHERE r1.obj_id = ' . $ilDB->quote($obj_id, 'integer')
70  );
71 
72  while ($prec = $ilDB->fetchAssoc($pset)) {
73  $nid = $ilDB->nextId("write_event");
74  $query = sprintf(
75  'INSERT INTO write_event ' .
76  '(write_id, obj_id, parent_obj_id, usr_id, action, ts) VALUES ' .
77  '(%s, %s, %s, %s, %s, ' . $ilDB->now() . ')',
78  $ilDB->quote($nid, 'integer'),
79  $ilDB->quote($obj_id, 'integer'),
80  $ilDB->quote($prec["par_obj_id"], 'integer'),
81  $ilDB->quote($usr_id, 'integer'),
82  $ilDB->quote($action, 'text')
83  );
84 
85  $aff = $ilDB->manipulate($query);
86  }
87  } else {
88  $nid = $ilDB->nextId("write_event");
89  $query = sprintf(
90  'INSERT INTO write_event ' .
91  '(write_id, obj_id, parent_obj_id, usr_id, action, ts) ' .
92  'VALUES (%s,%s,%s,%s,%s,' . $ilDB->now() . ')',
93  $ilDB->quote($nid, 'integer'),
94  $ilDB->quote($obj_id, 'integer'),
95  $ilDB->quote($parent_obj_id, 'integer'),
96  $ilDB->quote($usr_id, 'integer'),
97  $ilDB->quote($action, 'text')
98  );
99  $aff = $ilDB->manipulate($query);
100  }
101  }
global $DIC
Definition: feed.php:28
$query
+ Here is the caller graph for this function:

◆ _syncObjectStats()

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

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

References $check, $DIC, $ilDB, ilDBInterface\buildAtomQuery(), ilDBInterface\fetchAssoc(), ilDBInterface\insert(), ilDBInterface\numRows(), ilDBInterface\query(), ilDBInterface\quote(), and ilDBInterface\update().

Referenced by ilLPObjectStatisticsGUI\adminSync().

363  {
364  global $DIC;
365 
366  $ilDB = $DIC['ilDB'];
367 
368  if (!$a_now) {
369  $a_now = time();
370  }
371 
372  set_time_limit(0);
373 
374  // has source table enough entries?
375  $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
376  $row = $ilDB->fetchAssoc($set);
377  if ($row["counter"] >= $a_minimum) {
378  $ilAtomQuery = $ilDB->buildAtomQuery();
379  $ilAtomQuery->addTableLock('obj_stat_log');
380  $ilAtomQuery->addTableLock('obj_stat_tmp');
381 
382  $ilAtomQuery->addQueryCallable(
383  function (ilDBInterface $ilDB) use ($a_now, $a_minimum, &$ret) {
384 
385  // if other process was transferring, we had to wait for the lock and
386  // the source table should now have less than minimum/needed entries
387  $set = $ilDB->query(
388  "SELECT COUNT(*) AS counter FROM obj_stat_log"
389  );
390  $row = $ilDB->fetchAssoc($set);
391  if ($row["counter"] >= $a_minimum) {
392  // use only "full" seconds to have a clear cut
393  $ilDB->query(
394  "INSERT INTO obj_stat_tmp" .
395  " SELECT * FROM obj_stat_log" .
396  " WHERE tstamp < " . $ilDB->quote(
397  $a_now,
398  "timestamp"
399  )
400  );
401 
402  // remove transferred entries from source table
403  $ilDB->query(
404  "DELETE FROM obj_stat_log" .
405  " WHERE tstamp < " . $ilDB->quote(
406  $a_now,
407  "timestamp"
408  )
409  );
410 
411  $ret = true;
412  } else {
413  $ret = false;
414  }
415  }
416  );
417 
418  $ilAtomQuery->run();
419 
420  //continue only if obj_stat_log counter >= $a_minimum
421  if ($ret) {
422  $ilAtomQuery = $ilDB->buildAtomQuery();
423  $ilAtomQuery->addTableLock('obj_stat_tmp');
424  $ilAtomQuery->addTableLock('obj_stat');
425 
426  $ilAtomQuery->addQueryCallable(
427  function (ilDBInterface $ilDB) use ($a_now, $a_minimum) {
428 
429  // process log data (timestamp is not needed anymore)
430  $sql = "SELECT obj_id, obj_type, yyyy, mm, dd, hh, SUM(read_count) AS read_count," .
431  " SUM(childs_read_count) AS childs_read_count, SUM(spent_seconds) AS spent_seconds," .
432  " SUM(childs_spent_seconds) AS childs_spent_seconds" .
433  " FROM obj_stat_tmp" .
434  " GROUP BY obj_id, obj_type, yyyy, mm, dd, hh";
435  $set = $ilDB->query($sql);
436  while ($row = $ilDB->fetchAssoc($set)) {
437  // "primary key"
438  $where = array("obj_id" => array("integer",
439  $row["obj_id"]
440  ),
441  "obj_type" => array("text",
442  $row["obj_type"]
443  ),
444  "yyyy" => array("integer",
445  $row["yyyy"]
446  ),
447  "mm" => array("integer", $row["mm"]),
448  "dd" => array("integer", $row["dd"]),
449  "hh" => array("integer", $row["hh"])
450  );
451 
452  $where_sql = array();
453  foreach ($where as $field => $def) {
454  $where_sql[] = $field . " = " . $ilDB->quote(
455  $def[1],
456  $def[0]
457  );
458  }
459  $where_sql = implode(" AND ", $where_sql);
460 
461  // existing entry?
462  $check = $ilDB->query(
463  "SELECT read_count, childs_read_count, spent_seconds," .
464  "childs_spent_seconds" .
465  " FROM obj_stat" .
466  " WHERE " . $where_sql
467  );
468  if ($ilDB->numRows($check)) {
469  $old = $ilDB->fetchAssoc($check);
470 
471  // add existing values
472  $fields = array("read_count" => array("integer",
473  $old["read_count"] + $row["read_count"]
474  ),
475  "childs_read_count" => array("integer",
476  $old["childs_read_count"] + $row["childs_read_count"]
477  ),
478  "spent_seconds" => array("integer",
479  $old["spent_seconds"] + $row["spent_seconds"]
480  ),
481  "childs_spent_seconds" => array("integer",
482  $old["childs_spent_seconds"] + $row["childs_spent_seconds"]
483  )
484  );
485 
486  $ilDB->update("obj_stat", $fields, $where);
487  } else {
488  // new entry
489  $fields = $where;
490  $fields["read_count"] = array("integer",
491  $row["read_count"]
492  );
493  $fields["childs_read_count"] = array("integer",
494  $row["childs_read_count"]
495  );
496  $fields["spent_seconds"] = array("integer",
497  $row["spent_seconds"]
498  );
499  $fields["childs_spent_seconds"] = array("integer",
500  $row["childs_spent_seconds"]
501  );
502 
503  $ilDB->insert("obj_stat", $fields);
504  }
505  }
506 
507  // clean up transfer table
508  $ilDB->query("DELETE FROM obj_stat_tmp");
509  }
510  );
511 
512  $ilAtomQuery->run();
513  }
514  }
515  }
numRows(ilDBStatement $statement)
insert(string $table_name, array $values)
fetchAssoc(ilDBStatement $statement)
update(string $table_name, array $values, array $where)
$where MUST contain existing columns only.
quote($value, string $type)
global $DIC
Definition: feed.php:28
query(string $query)
Run a (read-only) Query on the database.
$check
Definition: buildRTE.php:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ hasAccessed()

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

Has accessed.

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

References $DIC, and $ilDB.

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

741  : bool
742  {
743  global $DIC;
744 
745  $ilDB = $DIC['ilDB'];
746 
747  if (isset(self::$has_accessed[$a_obj_id][$a_usr_id])) {
748  return self::$has_accessed[$a_obj_id][$a_usr_id];
749  }
750 
751  $set = $ilDB->query(
752  "SELECT usr_id FROM read_event WHERE " .
753  "obj_id = " . $ilDB->quote($a_obj_id, "integer") . " AND " .
754  "usr_id = " . $ilDB->quote($a_usr_id, "integer")
755  );
756  if ($rec = $ilDB->fetchAssoc($set)) {
757  return self::$has_accessed[$a_obj_id][$a_usr_id] = true;
758  }
759  return self::$has_accessed[$a_obj_id][$a_usr_id] = false;
760  }
global $DIC
Definition: feed.php:28
+ Here is the caller graph for this function:

◆ lookupUsersInProgress()

static ilChangeEvent::lookupUsersInProgress ( int  $a_obj_id)
static

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

References $DIC, $ilDB, $query, $res, and ILIAS\Repository\int().

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

719  : array
720  {
721  global $DIC;
722 
723  $ilDB = $DIC['ilDB'];
724 
725  $query = sprintf(
726  'SELECT DISTINCT(usr_id) usr FROM read_event ' .
727  'WHERE obj_id = %s ',
728  $ilDB->quote($a_obj_id, 'integer')
729  );
730  $res = $ilDB->query($query);
731  $users = [];
732  while ($row = $ilDB->fetchObject($res)) {
733  $users[] = (int) $row->usr;
734  }
735  return $users;
736  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: feed.php:28
$query
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Field Documentation

◆ $has_accessed

array ilChangeEvent::$has_accessed = []
staticprivate

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


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