ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
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 _updateAccessForScormOfflinePlayer (int $obj_id, int $usr_id, int $i_last_access, string $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 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 44 of file class.ilChangeEvent.php.

Member Function Documentation

◆ _activate()

static ilChangeEvent::_activate ( )
static

Activates change event tracking.

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

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

Referenced by ilObjRepositorySettingsGUI\saveSettings().

676  : bool
677  {
678  if (ilChangeEvent::_isActive()) {
679  return false;
680  } else {
681  global $DIC;
682 
683  $ilDB = $DIC['ilDB'];
684 
685  // Insert initial data into table write_event
686  // We need to do this here, because we need
687  // to catch up write events that occured while the change event tracking was
688  // deactivated.
689 
690  // IGNORE isn't supported in oracle
691  $set = $ilDB->query(
692  sprintf(
693  'SELECT r1.obj_id,r2.obj_id p,d.owner,%s,d.create_date ' .
694  'FROM object_data d ' .
695  'LEFT JOIN write_event w ON d.obj_id = w.obj_id ' .
696  'JOIN object_reference r1 ON d.obj_id=r1.obj_id ' .
697  'JOIN tree t ON t.child=r1.ref_id ' .
698  'JOIN object_reference r2 on r2.ref_id=t.parent ' .
699  'WHERE w.obj_id IS NULL',
700  $ilDB->quote('create', 'text')
701  )
702  );
703  $res = null;
704  while ($rec = $ilDB->fetchAssoc($set)) {
705  $nid = $ilDB->nextId("write_event");
706  $query = 'INSERT INTO write_event ' .
707  '(write_id, obj_id,parent_obj_id,usr_id,action,ts) VALUES (' .
708  $ilDB->quote($nid, "integer") . "," .
709  $ilDB->quote($rec["obj_id"], "integer") . "," .
710  $ilDB->quote($rec["p"], "integer") . "," .
711  $ilDB->quote($rec["owner"], "integer") . "," .
712  $ilDB->quote("create", "text") . "," .
713  $ilDB->quote($rec["create_date"], "timestamp") .
714  ')';
715  $res = $ilDB->query($query);
716  }
717 
718  global $DIC;
719 
720  $ilSetting = $DIC['ilSetting'];
721  $ilSetting->set('enable_change_event_tracking', '1');
722 
723  return $res !== null;
724  }
725  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:25
global $ilSetting
Definition: privfeed.php:32
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

This method was only used to write to catch_write_events, but the methods reading out that table are not used anywhere.

Deprecated:
, will be removed with ILIAS 11

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

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

545  : void {
546  }
+ Here is the caller graph for this function:

◆ _deactivate()

static ilChangeEvent::_deactivate ( )
static

Deactivates change event tracking.

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

References $DIC, and $ilSetting.

Referenced by ilObjRepositorySettingsGUI\saveSettings().

730  : bool
731  {
732  global $DIC;
733 
734  $ilSetting = $DIC['ilSetting'];
735  $ilSetting->set('enable_change_event_tracking', '0');
736  return true;
737  }
global $DIC
Definition: shib_login.php:25
global $ilSetting
Definition: privfeed.php:32
+ Here is the caller graph for this function:

◆ _delete()

static ilChangeEvent::_delete ( int  $a_obj_id)
static

Delete object entries.

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

References $DIC, and $ilDB.

Referenced by ilObjectLP\handleDelete().

753  : bool
754  {
755  global $DIC;
756 
757  $ilDB = $DIC['ilDB'];
758  $query = sprintf(
759  'DELETE FROM write_event WHERE obj_id = %s ',
760  $ilDB->quote($a_obj_id, 'integer')
761  );
762  $aff = $ilDB->manipulate($query);
763 
764  $query = sprintf(
765  'DELETE FROM read_event WHERE obj_id = %s ',
766  $ilDB->quote($a_obj_id, 'integer')
767  );
768  $aff = $ilDB->manipulate($query);
769  return true;
770  }
global $DIC
Definition: shib_login.php:25
+ Here is the caller graph for this function:

◆ _deleteReadEvents()

static ilChangeEvent::_deleteReadEvents ( int  $a_obj_id)
static

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

References $DIC, and $ilDB.

772  : void
773  {
774  global $DIC;
775 
776  $ilDB = $DIC['ilDB'];
777 
778  $ilDB->manipulate(
779  "DELETE FROM read_event" .
780  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer")
781  );
782  }
global $DIC
Definition: shib_login.php:25

◆ _deleteReadEventsForUsers()

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

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

References $DIC, and $ilDB.

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

787  : void {
788  global $DIC;
789 
790  $ilDB = $DIC['ilDB'];
791 
792  $ilDB->manipulate(
793  "DELETE FROM read_event" .
794  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer") .
795  " AND " . $ilDB->in("usr_id", $a_user_ids, "", "integer")
796  );
797  }
global $DIC
Definition: shib_login.php:25
+ Here is the caller graph for this function:

◆ _getAllUserIds()

static ilChangeEvent::_getAllUserIds ( int  $a_obj_id)
static

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

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

Referenced by ilObjectLP\gatherLPUsers().

799  : array
800  {
801  global $DIC;
802 
803  $ilDB = $DIC['ilDB'];
804  $res = array();
805  $set = $ilDB->query(
806  "SELECT usr_id FROM read_event" .
807  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer")
808  );
809  while ($row = $ilDB->fetchAssoc($set)) {
810  $res[] = (int) $row["usr_id"];
811  }
812  return $res;
813  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:25
+ 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 742 of file class.ilChangeEvent.php.

References $DIC, and $ilSetting.

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

742  : bool
743  {
744  global $DIC;
745 
746  $ilSetting = $DIC['ilSetting'];
747  return $ilSetting->get('enable_change_event_tracking', '0') == '1';
748  }
global $DIC
Definition: shib_login.php:25
global $ilSetting
Definition: privfeed.php:32
+ 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

This method is unused, so the table it read from was removed for performance reasons.

Deprecated:
, will be removed with ILIAS 11

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

579  : int
580  {
581  return 0;
582  }

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

References $DIC, $ilDB, and $res.

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

590  {
591  global $DIC;
592 
593  $ilDB = $DIC['ilDB'];
594 
595  if ($usr_id == null) {
596  $query = sprintf(
597  'SELECT * FROM read_event ' .
598  'WHERE obj_id = %s ' .
599  'ORDER BY last_access DESC',
600  $ilDB->quote($obj_id, 'integer')
601  );
602  $res = $ilDB->query($query);
603  } else {
604  $query = sprintf(
605  'SELECT * FROM read_event ' .
606  'WHERE obj_id = %s ' .
607  'AND usr_id = %s ' .
608  'ORDER BY last_access DESC',
609  $ilDB->quote($obj_id, 'integer'),
610  $ilDB->quote($usr_id, 'integer')
611  );
612  $res = $ilDB->query($query);
613  }
614 
615  $counter = 0;
616  $events = [];
617  while ($row = $ilDB->fetchAssoc($res)) {
618  $events[$counter]['obj_id'] = $row['obj_id'];
619  $events[$counter]['usr_id'] = $row['usr_id'];
620  $events[$counter]['last_access'] = $row['last_access'];
621  $events[$counter]['read_count'] = $row['read_count'];
622  $events[$counter]['spent_seconds'] = $row['spent_seconds'];
623  $events[$counter]['first_access'] = $row['first_access'];
624 
625  $counter++;
626  }
627  return $events;
628  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:25
+ 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

This method is unused, so the table it read from was removed for performance reasons.

Deprecated:
, will be removed with ILIAS 11

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

562  : array {
563  return [];
564  }

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

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

329  : void {
330  global $DIC;
331 
332  $ilDB = $DIC['ilDB'];
333 
335  $a_obj_id <= 0) { // #12706
336  return;
337  }
338 
339  $now = time();
340 
341  $fields = array();
342  $fields['log_id'] = array("integer", $ilDB->nextId('obj_stat_log'));
343  $fields["obj_id"] = array("integer", $a_obj_id);
344  $fields["obj_type"] = array("text", ilObject::_lookupType($a_obj_id));
345  $fields["tstamp"] = array("timestamp", $now);
346  $fields["yyyy"] = array("integer", date("Y"));
347  $fields["mm"] = array("integer", date("m"));
348  $fields["dd"] = array("integer", date("d"));
349  $fields["hh"] = array("integer", date("H"));
350  if ($a_spent_seconds > 0) {
351  $fields["spent_seconds"] = array("integer", $a_spent_seconds);
352  }
353  if ($a_read_count > 0) {
354  $fields["read_count"] = array("integer", $a_read_count);
355  }
356  if ($a_childs_spent_seconds > 0) {
357  $fields["childs_spent_seconds"] = array("integer",
358  $a_childs_spent_seconds
359  );
360  }
361  if ($a_child_read_count > 0) {
362  $fields["childs_read_count"] = array("integer",
363  $a_child_read_count
364  );
365  }
366  $ilDB->insert("obj_stat_log", $fields);
367 
368  // 0.01% probability
369  if (mt_rand(1, 100) == 1) {
370  self::_syncObjectStats($now);
371  }
372  }
global $DIC
Definition: shib_login.php:25
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 118 of file class.ilChangeEvent.php.

References $DIC, $ilDB, $path, $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().

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

References $DIC, and $ilDB.

Referenced by ilObjCourseGUI\afterSave(), ILIAS\Repository\Deletion\EventStandardAdapter\beforeSubtreeRemoval(), ilContainerGUI\pasteObject(), ilContainerGUI\performPasteIntoMultipleObjectsObject(), ilObjFileGUI\putObjectInTree(), ilObject2GUI\putObjectInTree(), ilObjectGUI\putObjectInTree(), ilRepUtil\removeObjectsFromSystem(), ilRepUtil\restoreObjects(), ilObjRootFolderGUI\updateObject(), ilObjGroupGUI\updateObject(), ilObjCourseGUI\updateObject(), and ilObjCategoryGUI\updateObject().

67  : void {
68  global $DIC;
69 
70  $ilDB = $DIC['ilDB'];
71 
72  /* see _recordReadEvent
73  if (!ilChangeEvent::_isActive())
74  {
75  return;
76  }
77  */
78 
79  if ($parent_obj_id == null) {
80  $pset = $ilDB->query(
81  'SELECT r2.obj_id par_obj_id FROM object_reference r1 ' .
82  'JOIN tree t ON t.child = r1.ref_id ' .
83  'JOIN object_reference r2 ON r2.ref_id = t.parent ' .
84  'WHERE r1.obj_id = ' . $ilDB->quote($obj_id, 'integer')
85  );
86 
87  while ($prec = $ilDB->fetchAssoc($pset)) {
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) VALUES ' .
92  '(%s, %s, %s, %s, %s, ' . $ilDB->now() . ')',
93  $ilDB->quote($nid, 'integer'),
94  $ilDB->quote($obj_id, 'integer'),
95  $ilDB->quote($prec["par_obj_id"], 'integer'),
96  $ilDB->quote($usr_id, 'integer'),
97  $ilDB->quote($action, 'text')
98  );
99 
100  $aff = $ilDB->manipulate($query);
101  }
102  } else {
103  $nid = $ilDB->nextId("write_event");
104  $query = sprintf(
105  'INSERT INTO write_event ' .
106  '(write_id, obj_id, parent_obj_id, usr_id, action, ts) ' .
107  'VALUES (%s,%s,%s,%s,%s,' . $ilDB->now() . ')',
108  $ilDB->quote($nid, 'integer'),
109  $ilDB->quote($obj_id, 'integer'),
110  $ilDB->quote($parent_obj_id, 'integer'),
111  $ilDB->quote($usr_id, 'integer'),
112  $ilDB->quote($action, 'text')
113  );
114  $aff = $ilDB->manipulate($query);
115  }
116  }
global $DIC
Definition: shib_login.php:25
+ Here is the caller graph for this function:

◆ _syncObjectStats()

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

Definition at line 374 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().

377  {
378  global $DIC;
379 
380  $ilDB = $DIC['ilDB'];
381 
382  if (!$a_now) {
383  $a_now = time();
384  }
385 
386  set_time_limit(0);
387 
388  // has source table enough entries?
389  $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
390  $row = $ilDB->fetchAssoc($set);
391  if ($row["counter"] >= $a_minimum) {
392  $ilAtomQuery = $ilDB->buildAtomQuery();
393  $ilAtomQuery->addTableLock('obj_stat_log');
394  $ilAtomQuery->addTableLock('obj_stat_tmp');
395 
396  $ilAtomQuery->addQueryCallable(
397  function (ilDBInterface $ilDB) use ($a_now, $a_minimum, &$ret) {
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(
401  "SELECT COUNT(*) AS counter FROM obj_stat_log"
402  );
403  $row = $ilDB->fetchAssoc($set);
404  if ($row["counter"] >= $a_minimum) {
405  // use only "full" seconds to have a clear cut
406  $ilDB->query(
407  "INSERT INTO obj_stat_tmp" .
408  " SELECT * FROM obj_stat_log" .
409  " WHERE tstamp < " . $ilDB->quote(
410  $a_now,
411  "timestamp"
412  )
413  );
414 
415  // remove transferred entries from source table
416  $ilDB->query(
417  "DELETE FROM obj_stat_log" .
418  " WHERE tstamp < " . $ilDB->quote(
419  $a_now,
420  "timestamp"
421  )
422  );
423 
424  $ret = true;
425  } else {
426  $ret = false;
427  }
428  }
429  );
430 
431  $ilAtomQuery->run();
432 
433  //continue only if obj_stat_log counter >= $a_minimum
434  if ($ret) {
435  $ilAtomQuery = $ilDB->buildAtomQuery();
436  $ilAtomQuery->addTableLock('obj_stat_tmp');
437  $ilAtomQuery->addTableLock('obj_stat');
438 
439  $ilAtomQuery->addQueryCallable(
440  function (ilDBInterface $ilDB) use ($a_now, $a_minimum) {
441  // process log data (timestamp is not needed anymore)
442  $sql = "SELECT obj_id, obj_type, yyyy, mm, dd, hh, SUM(read_count) AS read_count," .
443  " SUM(childs_read_count) AS childs_read_count, SUM(spent_seconds) AS spent_seconds," .
444  " SUM(childs_spent_seconds) AS childs_spent_seconds" .
445  " FROM obj_stat_tmp" .
446  " GROUP BY obj_id, obj_type, yyyy, mm, dd, hh";
447  $set = $ilDB->query($sql);
448  while ($row = $ilDB->fetchAssoc($set)) {
449  // "primary key"
450  $where = array("obj_id" => array("integer",
451  $row["obj_id"]
452  ),
453  "obj_type" => array("text",
454  $row["obj_type"]
455  ),
456  "yyyy" => array("integer",
457  $row["yyyy"]
458  ),
459  "mm" => array("integer", $row["mm"]),
460  "dd" => array("integer", $row["dd"]),
461  "hh" => array("integer", $row["hh"])
462  );
463 
464  $where_sql = array();
465  foreach ($where as $field => $def) {
466  $where_sql[] = $field . " = " . $ilDB->quote(
467  $def[1],
468  $def[0]
469  );
470  }
471  $where_sql = implode(" AND ", $where_sql);
472 
473  // existing entry?
474  $check = $ilDB->query(
475  "SELECT read_count, childs_read_count, spent_seconds," .
476  "childs_spent_seconds" .
477  " FROM obj_stat" .
478  " WHERE " . $where_sql
479  );
480  if ($ilDB->numRows($check)) {
481  $old = $ilDB->fetchAssoc($check);
482 
483  // add existing values
484  $fields = array("read_count" => array("integer",
485  $old["read_count"] + $row["read_count"]
486  ),
487  "childs_read_count" => array("integer",
488  $old["childs_read_count"] + $row["childs_read_count"]
489  ),
490  "spent_seconds" => array("integer",
491  $old["spent_seconds"] + $row["spent_seconds"]
492  ),
493  "childs_spent_seconds" => array("integer",
494  $old["childs_spent_seconds"] + $row["childs_spent_seconds"]
495  )
496  );
497 
498  $ilDB->update("obj_stat", $fields, $where);
499  } else {
500  // new entry
501  $fields = $where;
502  $fields["read_count"] = array("integer",
503  $row["read_count"]
504  );
505  $fields["childs_read_count"] = array("integer",
506  $row["childs_read_count"]
507  );
508  $fields["spent_seconds"] = array("integer",
509  $row["spent_seconds"]
510  );
511  $fields["childs_spent_seconds"] = array("integer",
512  $row["childs_spent_seconds"]
513  );
514 
515  $ilDB->insert("obj_stat", $fields);
516  }
517  }
518 
519  // clean up transfer table
520  $ilDB->query("DELETE FROM obj_stat_tmp");
521  }
522  );
523 
524  $ilAtomQuery->run();
525  }
526  }
527  }
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: shib_login.php:25
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:

◆ _updateAccessForScormOfflinePlayer()

static ilChangeEvent::_updateAccessForScormOfflinePlayer ( int  $obj_id,
int  $usr_id,
int  $i_last_access,
string  $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

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

References $DIC, $ilDB, and $res.

825  : bool {
826  global $DIC;
827 
828  $ilDB = $DIC->database();
829  $res = $ilDB->queryF(
830  'UPDATE read_event SET first_access=%s, last_access = %s WHERE obj_id=%s AND usr_id=%s',
831  array('timestamp', 'integer', 'integer', 'integer'),
832  array($t_first_access, $i_last_access, $obj_id, $usr_id)
833  );
834  return true;
835  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:25

◆ hasAccessed()

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

Has accessed.

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

References $DIC, and $ilDB.

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

652  : bool
653  {
654  global $DIC;
655 
656  $ilDB = $DIC['ilDB'];
657 
658  if (isset(self::$has_accessed[$a_obj_id][$a_usr_id])) {
659  return self::$has_accessed[$a_obj_id][$a_usr_id];
660  }
661 
662  $set = $ilDB->query(
663  "SELECT usr_id FROM read_event WHERE " .
664  "obj_id = " . $ilDB->quote($a_obj_id, "integer") . " AND " .
665  "usr_id = " . $ilDB->quote($a_usr_id, "integer")
666  );
667  if ($rec = $ilDB->fetchAssoc($set)) {
668  return self::$has_accessed[$a_obj_id][$a_usr_id] = true;
669  }
670  return self::$has_accessed[$a_obj_id][$a_usr_id] = false;
671  }
global $DIC
Definition: shib_login.php:25
+ Here is the caller graph for this function:

◆ lookupUsersInProgress()

static ilChangeEvent::lookupUsersInProgress ( int  $a_obj_id)
static

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

References $DIC, $ilDB, $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().

630  : array
631  {
632  global $DIC;
633 
634  $ilDB = $DIC['ilDB'];
635 
636  $query = sprintf(
637  'SELECT DISTINCT(usr_id) usr FROM read_event ' .
638  'WHERE obj_id = %s ',
639  $ilDB->quote($a_obj_id, 'integer')
640  );
641  $res = $ilDB->query($query);
642  $users = [];
643  while ($row = $ilDB->fetchObject($res)) {
644  $users[] = (int) $row->usr;
645  }
646  return $users;
647  }
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:25
+ 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 46 of file class.ilChangeEvent.php.


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