ILIAS  release_8 Revision v8.24
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.

765 : bool
766 {
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 }
static _isActive()
Returns true, if change event tracking is active.
global $DIC
Definition: feed.php:28
$res
Definition: ltiservices.php:69
global $ilSetting
Definition: privfeed.php:17
$query

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

Referenced by ilObjRepositorySettingsGUI\saveSettings().

+ 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.

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 }
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:70
static now()
Return current timestamp in Y-m-d H:i:s format.

References $timestamp, and ilUtil\now().

Referenced by ilContainerGUI\pasteObject(), ilContainerGUI\performPasteIntoMultipleObjectsObject(), ilObjFileGUI\update(), ilObjCategoryGUI\updateObject(), ilObjCourseGUI\updateObject(), and ilObjGroupGUI\updateObject().

+ 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.

819 : bool
820 {
821 global $DIC;
822
823 $ilSetting = $DIC['ilSetting'];
824 $ilSetting->set('enable_change_event_tracking', '0');
825 return true;
826 }

References $DIC, and $ilSetting.

Referenced by ilObjRepositorySettingsGUI\saveSettings().

+ 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.

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 }

References $DIC, $ilDB, and $query.

Referenced by ilObjectLP\handleDelete().

+ 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.

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 }

References $DIC, and $ilDB.

◆ _deleteReadEventsForUsers()

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

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

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 }

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

+ 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.

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 }

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

Referenced by ilObjectLP\gatherLPUsers().

+ 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.

831 : bool
832 {
833 global $DIC;
834
835 $ilSetting = $DIC['ilSetting'];
836 return $ilSetting->get('enable_change_event_tracking', '0') == '1';
837 }

References $DIC, and $ilSetting.

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

+ 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.

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 }

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

◆ _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.

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 }

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

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

+ 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.

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 }

◆ _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.

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) {
357 }
358 }
static _syncObjectStats(?int $a_now=null, int $a_minimum=20000)
static _lookupType(int $id, bool $reference=false)

◆ _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.

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
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
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 }
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 _catchupWriteEvents(int $obj_id, int $usr_id, ?string $timestamp=null)
Catches up with all write events which occured before the specified timestamp.
static _lookupObjId(int $ref_id)
$path
Definition: ltiservices.php:32

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

+ 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.

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 }

References $ilDB, and $query.

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

+ 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.

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 }
$check
Definition: buildRTE.php:81
Interface ilDBInterface.

References $check, $DIC, and $ilDB.

Referenced by ilLPObjectStatisticsGUI\adminSync().

+ 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.

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 }

References $DIC, and $ilDB.

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

+ 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.

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 }

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

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

+ 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: