ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
ilChangeEvent Class Reference

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

+ Collaboration diagram for ilChangeEvent:

Public Member Functions

 _recordWriteEvent ($obj_id, $usr_id, $action, $parent_obj_id=null)
 Records a write event. More...
 
 _recordReadEvent ($a_type, $a_ref_id, $obj_id, $usr_id, $isCatchupWriteEvents=true, $a_ext_rc=false, $a_ext_time=false)
 Records a read event and catches up with write events. More...
 
 _recordObjStats ($a_obj_id, $a_spent_seconds, $a_read_count, $a_childs_spent_seconds=null, $a_child_read_count=null)
 
 _syncObjectStats ($a_now=null, $a_minimum=20000)
 Process object statistics log data. More...
 
 _catchupWriteEvents ($obj_id, $usr_id, $timestamp=null)
 Catches up with all write events which occured before the specified timestamp. More...
 
 _updateAccessForScormOfflinePlayer ($obj_id, $usr_id, $i_last_access, $t_first_access)
 _updateAccessForScormOfflinePlayer needed to synchronize last_access and first_access when learning modul is used offline called in . More...
 

Static Public Member Functions

static _lookupUncaughtWriteEvents ($obj_id, $usr_id)
 Catches up with all write events which occured before the specified timestamp. More...
 
static _lookupChangeState ($obj_id, $usr_id)
 Returns the change state of the object for the specified user. More...
 
static _lookupInsideChangeState ($parent_obj_id, $usr_id)
 Returns the changed state of objects which are children of the specified parent object. More...
 
static _lookupReadEvents ($obj_id, $usr_id=null)
 Reads all read events which occured on the object which happened after the last time the user caught up with them. More...
 
static lookupUsersInProgress ($a_obj_id)
 Lookup users in progress. More...
 
static hasAccessed ($a_obj_id, $a_usr_id)
 Has accessed. More...
 
static _activate ()
 Activates change event tracking. More...
 
static _deactivate ()
 Deactivates change event tracking. More...
 
static _isActive ()
 Returns true, if change event tracking is active. More...
 
static _delete ($a_obj_id)
 Delete object entries. More...
 
static _deleteReadEvents ($a_obj_id)
 
static _deleteReadEventsForUsers ($a_obj_id, array $a_user_ids)
 
static _getAllUserIds ($a_obj_id)
 

Static Private Attributes

static $has_accessed = array()
 

Detailed Description

Class ilChangeEvent tracks change events on repository objects.

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

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

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

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

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

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

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

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

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

Member Function Documentation

◆ _activate()

static ilChangeEvent::_activate ( )
static

Activates change event tracking.

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

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

877 {
879 {
880 return 'change event tracking is already active';
881 }
882 else
883 {
884 global $ilDB;
885
886 // Insert initial data into table write_event
887 // We need to do this here, because we need
888 // to catch up write events that occured while the change event tracking was
889 // deactivated.
890
891 // IGNORE isn't supported in oracle
892 $set = $ilDB->query(sprintf('SELECT r1.obj_id,r2.obj_id p,d.owner,%s,d.create_date '.
893 'FROM object_data d '.
894 'LEFT JOIN write_event w ON d.obj_id = w.obj_id '.
895 'JOIN object_reference r1 ON d.obj_id=r1.obj_id '.
896 'JOIN tree t ON t.child=r1.ref_id '.
897 'JOIN object_reference r2 on r2.ref_id=t.parent '.
898 'WHERE w.obj_id IS NULL',
899 $ilDB->quote('create','text')));
900 while ($rec = $ilDB->fetchAssoc($set))
901 {
902 $nid = $ilDB->nextId("write_event");
903 $query = 'INSERT INTO write_event '.
904 '(write_id, obj_id,parent_obj_id,usr_id,action,ts) VALUES ('.
905 $ilDB->quote($nid, "integer").",".
906 $ilDB->quote($rec["obj_id"], "integer").",".
907 $ilDB->quote($rec["p"], "integer").",".
908 $ilDB->quote($rec["owner"], "integer").",".
909 $ilDB->quote("create", "text").",".
910 $ilDB->quote($rec["create_date"], "timestamp").
911 ')';
912 $res = $ilDB->query($query);
913 }
914
915 if ($ilDB->isError($res) || $ilDB->isError($res->result))
916 {
917 return 'couldn\'t insert initial data into table "write_event": '.
918 (($ilDB->isError($r->result)) ? $r->result->getMessage() : $r->getMessage());
919 }
920
921
922 global $ilias;
923 $ilias->setSetting('enable_change_event_tracking', '1');
924
925 return $res;
926 }
927 }
static _isActive()
Returns true, if change event tracking is active.
$r
Definition: example_031.php:79
global $ilDB

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

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

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _catchupWriteEvents()

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

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

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

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

490 {
491 global $ilDB;
492
493 $query = "SELECT obj_id FROM catch_write_events ".
494 "WHERE obj_id = ".$ilDB->quote($obj_id ,'integer')." ".
495 "AND usr_id = ".$ilDB->quote($usr_id ,'integer');
496 $res = $ilDB->query($query);
497 if($res->numRows())
498 {
499 $ts = ($timestamp == null)
500 ? ilUtil::now()
501 : $timestamp;
502/* $query = "UPDATE catch_write_events ".
503 "SET ts = ".($timestamp == null ? $ilDB->now() : $ilDB->quote($timestamp, 'timestamp'))." ".
504 "WHERE usr_id = ".$ilDB->quote($usr_id ,'integer')." ".
505 "AND obj_id = ".$ilDB->quote($obj_id ,'integer');
506 $res = $ilDB->manipulate($query);*/
507 }
508 else
509 {
510 $ts = ilUtil::now();
511/* $query = "INSERT INTO catch_write_events (ts,obj_id,usr_id) ".
512 "VALUES( ".
513 $ilDB->now().", ".
514 $ilDB->quote($obj_id,'integer').", ".
515 $ilDB->quote($usr_id,'integer')." ".
516 ")";
517 $res = $ilDB->manipulate($query);*/
518 }
519
520 // alex, use replace due to bug #10406
521 $ilDB->replace("catch_write_events",
522 array(
523 "obj_id" => array("integer", $obj_id),
524 "usr_id" => array("integer", $usr_id)
525 ),
526 array(
527 "ts" => array("timestamp", $ts))
528 );
529 }
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:81
static now()
Return current timestamp in Y-m-d H:i:s format.

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

Referenced by _recordReadEvent(), ilContainerGUI\pasteObject(), ilContainerGUI\performPasteIntoMultipleObjectsObject(), ilDAVServer\PUT(), ilRepUtil\restoreObjects(), ilObjFileGUI\update(), ilObjCategoryGUI\updateObject(), ilObjCourseGUI\updateObject(), ilObjGroupGUI\updateObject(), and ilObjRootFolderGUI\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.

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

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

934 {
935 global $ilias;
936 $ilias->setSetting('enable_change_event_tracking', '0');
937
938 }

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

+ Here is the caller graph for this function:

◆ _delete()

static ilChangeEvent::_delete (   $a_obj_id)
static

Delete object entries.

Returns

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

958 {
959 global $ilDB;
960
961 $query = sprintf('DELETE FROM write_event WHERE obj_id = %s ',
962 $ilDB->quote($a_obj_id,'integer'));
963 $aff = $ilDB->manipulate($query);
964
965 $query = sprintf('DELETE FROM read_event WHERE obj_id = %s ',
966 $ilDB->quote($a_obj_id,'integer'));
967 $aff = $ilDB->manipulate($query);
968 return true;
969 }

References $ilDB, and $query.

Referenced by ilObjectLP\handleDelete().

+ Here is the caller graph for this function:

◆ _deleteReadEvents()

static ilChangeEvent::_deleteReadEvents (   $a_obj_id)
static

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

972 {
973 global $ilDB;
974
975 $ilDB->manipulate("DELETE FROM read_event".
976 " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer"));
977 }

References $ilDB.

◆ _deleteReadEventsForUsers()

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

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

980 {
981 global $ilDB;
982
983 $ilDB->manipulate("DELETE FROM read_event".
984 " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer").
985 " AND ".$ilDB->in("usr_id", $a_user_ids, "", "integer"));
986 }

References $ilDB.

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

+ Here is the caller graph for this function:

◆ _getAllUserIds()

static ilChangeEvent::_getAllUserIds (   $a_obj_id)
static

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

989 {
990 global $ilDB;
991
992 $res = array();
993
994 $set = $ilDB->query("SELECT usr_id FROM read_event".
995 " WHERE obj_id = ".$ilDB->quote($a_obj_id, "integer"));
996 while($row = $ilDB->fetchAssoc($set))
997 {
998 $res[] = $row["usr_id"];
999 }
1000
1001 return $res;
1002 }

References $ilDB, $res, and $row.

Referenced by ilObjectLP\gatherLPUsers().

+ Here is the caller graph for this function:

◆ _isActive()

static ilChangeEvent::_isActive ( )
static

Returns true, if change event tracking is active.

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

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

945 {
946 global $ilias;
947 return $ilias->getSetting('enable_change_event_tracking', '0') == '1';
948
949 }

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

+ Here is the caller graph for this function:

◆ _lookupChangeState()

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

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

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

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

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

632 {
633 global $ilDB;
634
635 $q = "SELECT ts ".
636 "FROM catch_write_events ".
637 "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
638 "AND usr_id=".$ilDB->quote($usr_id ,'integer');
639 $r = $ilDB->query($q);
640 $catchup = null;
641 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
642 $catchup = $row['ts'];
643 }
644
645 if($catchup == null)
646 {
647 $ilDB->setLimit(1);
648 $query = sprintf('SELECT * FROM write_event '.
649 'WHERE obj_id = %s '.
650 'AND usr_id <> %s ',
651 $ilDB->quote($obj_id,'integer'),
652 $ilDB->quote($usr_id,'integer'));
653 $res = $ilDB->query($query);
654 }
655 else
656 {
657 $ilDB->setLimit(1);
658 $query = sprintf('SELECT * FROM write_event '.
659 'WHERE obj_id = %s '.
660 'AND usr_id <> %s '.
661 'AND ts > %s ',
662 $ilDB->quote($obj_id,'integer'),
663 $ilDB->quote($usr_id,'integer'),
664 $ilDB->quote($catchup,'timestamp'));
665 $res = $ilDB->query($query);
666 }
667
668 $numRows = $res->numRows();
669 if ($numRows > 0)
670 {
671 $row = $ilDB->fetchAssoc($res);
672 // if we have write events, and user never catched one, report as new (1)
673 // if we have write events, and user catched an old write event, report as changed (2)
674 return ($catchup == null) ? 1 : 2;
675 }
676 else
677 {
678 return 0; // user catched all write events, report as unchanged (0)
679 }
680 }
const DB_FETCHMODE_ASSOC
Definition: class.ilDB.php:10

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

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

+ Here is the caller graph for this function:

◆ _lookupInsideChangeState()

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

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

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

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

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

697 {
698 global $ilDB;
699
700 $q = "SELECT ts ".
701 "FROM catch_write_events ".
702 "WHERE obj_id=".$ilDB->quote($parent_obj_id)." ".
703 "AND usr_id=".$ilDB->quote($usr_id);
704 $r = $ilDB->query($q);
705 $catchup = null;
706 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
707 $catchup = $row['ts'];
708 }
709
710 if($catchup == null)
711 {
712 $ilDB->setLimit(1);
713 $query = sprintf('SELECT * FROM write_event '.
714 'WHERE parent_obj_id = %s '.
715 'AND usr_id <> %s ',
716 $ilDB->quote($parent_obj_id,'integer'),
717 $ilDB->quote($usr_id,'integer'));
718 $res = $ilDB->query($query);
719 }
720 else
721 {
722 $ilDB->setLimit(1);
723 $query = sprintf('SELECT * FROM write_event '.
724 'WHERE parent_obj_id = %s '.
725 'AND usr_id <> %s '.
726 'AND ts > %s ',
727 $ilDB->quote($parent_obj_id,'integer'),
728 $ilDB->quote($usr_id,'integer'),
729 $ilDB->quote($catchup,'timestamp'));
730 $res = $ilDB->query($query);
731 }
732 $numRows = $res->numRows();
733 if ($numRows > 0)
734 {
735 $row = $ilDB->fetchAssoc($res);
736 // if we have write events, and user never catched one, report as new (1)
737 // if we have write events, and user catched an old write event, report as changed (2)
738 return ($catchup == null) ? 1 : 2;
739 }
740 else
741 {
742 return 0; // user catched all write events, report as unchanged (0)
743 }
744 }

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

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

+ Here is the caller graph for this function:

◆ _lookupReadEvents()

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

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

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

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

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

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

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

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

790 {
791 global $ilDB;
792
793 if ($usr_id == null)
794 {
795 $query = sprintf('SELECT * FROM read_event '.
796 'WHERE obj_id = %s '.
797 'ORDER BY last_access DESC',
798 $ilDB->quote($obj_id,'integer'));
799 $res = $ilDB->query($query);
800 }
801 else
802 {
803 $query = sprintf('SELECT * FROM read_event '.
804 'WHERE obj_id = %s '.
805 'AND usr_id = %s '.
806 'ORDER BY last_access DESC',
807 $ilDB->quote($obj_id,'integer'),
808 $ilDB->quote($usr_id,'integer'));
809 $res = $ilDB->query($query);
810 }
811
812 $counter = 0;
813 while ($row = $ilDB->fetchAssoc($res))
814 {
815 $events[$counter]['obj_id'] = $row['obj_id'];
816 $events[$counter]['usr_id'] = $row['usr_id'];
817 $events[$counter]['last_access'] = $row['last_access'];
818 $events[$counter]['read_count'] = $row['read_count'];
819 $events[$counter]['spent_seconds'] = $row['spent_seconds'];
820 $events[$counter]['first_access'] = $row['first_access'];
821
822 $counter++;
823
824 }
825 return $events ? $events : array();
826 }

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

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

+ Here is the caller graph for this function:

◆ _lookupUncaughtWriteEvents()

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

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

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

Parameters
$obj_idint The object.
$usr_idint The user.
$timestampSQL timestamp. / function _catchupReadEvents($obj_id, $usr_id, $timestamp = null) { global $ilDB;

$q = "INSERT INTO catch_read_events ". "(obj_id, usr_id, action, ts) ". "VALUES (". $ilDB->quote($obj_id).",". $ilDB->quote($usr_id).",". $ilDB->quote('read').","; if ($timestamp == null) { $q .= "NOW()". ") ON DUPLICATE KEY UPDATE ts=NOW()"; } else { $q .= $ilDB->quote($timestamp). ") ON DUPLICATE KEY UPDATE ts=".$ilDB->quote($timestamp); }

$r = $ilDB->query($q); } Reads all write events which occured on the object which happened after the last time the user caught up with them.

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

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

579 {
580 global $ilDB;
581
582 $q = "SELECT ts ".
583 "FROM catch_write_events ".
584 "WHERE obj_id=".$ilDB->quote($obj_id ,'integer')." ".
585 "AND usr_id=".$ilDB->quote($usr_id ,'integer');
586 $r = $ilDB->query($q);
587 $catchup = null;
588 while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC)) {
589 $catchup = $row['ts'];
590 }
591
592 if($catchup == null)
593 {
594 $query = sprintf('SELECT * FROM write_event '.
595 'WHERE obj_id = %s '.
596 'AND usr_id <> %s '.
597 'ORDER BY ts DESC',
598 $ilDB->quote($obj_id,'integer'),
599 $ilDB->quote($usr_id,'integer'));
600 $res = $ilDB->query($query);
601 }
602 else
603 {
604 $query = sprintf('SELECT * FROM write_event '.
605 'WHERE obj_id = %s '.
606 'AND usr_id <> %s '.
607 'AND ts >= %s '.
608 'ORDER BY ts DESC',
609 $ilDB->quote($obj_id,'integer'),
610 $ilDB->quote($usr_id,'integer'),
611 $ilDB->quote($catchup,'timestamp'));
612 $res = $ilDB->query($query);
613 }
614 $events = array();
615 while($row = $ilDB->fetchAssoc($res))
616 {
617 $events[] = $row;
618 }
619 return $events;
620 }

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

Referenced by ilTrackingTest\testChangeEvent().

+ Here is the caller graph for this function:

◆ _recordObjStats()

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

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

326 {
327 global $ilDB;
328
330 (int)$a_obj_id <= 0) // #12706
331 {
332 return;
333 }
334
335 $now = time();
336
337 $fields = array();
338 $fields["obj_id"] = array("integer", $a_obj_id);
339 $fields["obj_type"] = array("text", ilObject::_lookupType($a_obj_id));
340 $fields["tstamp"] = array("timestamp", $now);
341 $fields["yyyy"] = array("integer", date("Y"));
342 $fields["mm"] = array("integer", date("m"));
343 $fields["dd"] = array("integer", date("d"));
344 $fields["hh"] = array("integer", date("H"));
345 if($a_spent_seconds > 0)
346 {
347 $fields["spent_seconds"] = array("integer", $a_spent_seconds);
348 }
349 if($a_read_count > 0)
350 {
351 $fields["read_count"] = array("integer", $a_read_count);
352 }
353 if($a_childs_spent_seconds > 0)
354 {
355 $fields["childs_spent_seconds"] = array("integer", $a_childs_spent_seconds);
356 }
357 if($a_child_read_count > 0)
358 {
359 $fields["childs_read_count"] = array("integer", $a_child_read_count);
360 }
361 $ilDB->insert("obj_stat_log", $fields);
362
363 // 0.01% probability
364 if(mt_rand(1, 100) == 1)
365 {
367 }
368 }
_syncObjectStats($a_now=null, $a_minimum=20000)
Process object statistics log data.
static _enabledObjectStatistics()
check wether object statistics is enabled or not
static _lookupType($a_id, $a_reference=false)
lookup object type

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

Referenced by _recordReadEvent().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _recordReadEvent()

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

Records a read event and catches up with write events.

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

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

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

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

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

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _recordWriteEvent()

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

Records a write event.

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

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

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

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

References $ilDB, and $query.

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

+ Here is the caller graph for this function:

◆ _syncObjectStats()

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

Process object statistics log data.

Parameters
integer$a_now
integer$a_minimum

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

377 {
378 global $ilDB;
379
380 if(!$a_now)
381 {
382 $a_now = time();
383 }
384
385 set_time_limit(0);
386
387 // has source table enough entries?
388 $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
389 $row = $ilDB->fetchAssoc($set);
390 if($row["counter"] >= $a_minimum)
391 {
392 // lock source and transfer table
393 $ilDB->lockTables(array(array("name"=>"obj_stat_log", "type"=>ilDB::LOCK_WRITE),
394 array("name"=>"obj_stat_tmp", "type"=>ilDB::LOCK_WRITE)));
395
396 // if other process was transferring, we had to wait for the lock and
397 // the source table should now have less than minimum/needed entries
398 $set = $ilDB->query("SELECT COUNT(*) AS counter FROM obj_stat_log");
399 $row = $ilDB->fetchAssoc($set);
400 if($row["counter"] >= $a_minimum)
401 {
402 // use only "full" seconds to have a clear cut
403 $ilDB->query("INSERT INTO obj_stat_tmp".
404 " SELECT * FROM obj_stat_log".
405 " WHERE tstamp < ".$ilDB->quote($a_now, "timestamp"));
406
407 // remove transferred entries from source table
408 $ilDB->query("DELETE FROM obj_stat_log".
409 " WHERE tstamp < ".$ilDB->quote($a_now, "timestamp"));
410
411 // remove lock from source table
412 $ilDB->unlockTables();
413
414 // lock transfer and target table (is this needed?)
415 $ilDB->lockTables(array(array("name"=>"obj_stat_tmp", "type"=>ilDB::LOCK_WRITE),
416 array("name"=>"obj_stat", "type"=>ilDB::LOCK_WRITE)));
417
418 // process log data (timestamp is not needed anymore)
419 $sql = "SELECT obj_id, obj_type, yyyy, mm, dd, hh, SUM(read_count) AS read_count,".
420 " SUM(childs_read_count) AS childs_read_count, SUM(spent_seconds) AS spent_seconds,".
421 " SUM(childs_spent_seconds) AS childs_spent_seconds".
422 " FROM obj_stat_tmp".
423 " GROUP BY obj_id, obj_type, yyyy, mm, dd, hh";
424 $set = $ilDB->query($sql);
425 while($row = $ilDB->fetchAssoc($set))
426 {
427 // "primary key"
428 $where = array("obj_id" => array("integer", $row["obj_id"]),
429 "obj_type" => array("text", $row["obj_type"]),
430 "yyyy" => array("integer", $row["yyyy"]),
431 "mm" => array("integer", $row["mm"]),
432 "dd" => array("integer", $row["dd"]),
433 "hh" => array("integer", $row["hh"]));
434
435 $where_sql = array();
436 foreach($where as $field => $def)
437 {
438 $where_sql[] = $field." = ".$ilDB->quote($def[1], $def[0]);
439 }
440 $where_sql = implode(" AND ", $where_sql);
441
442 // existing entry?
443 $check = $ilDB->query("SELECT read_count, childs_read_count, spent_seconds,".
444 "childs_spent_seconds".
445 " FROM obj_stat".
446 " WHERE ".$where_sql);
447 if($ilDB->numRows($check))
448 {
449 $old = $ilDB->fetchAssoc($check);
450
451 // add existing values
452 $fields = array("read_count" => array("integer", $old["read_count"]+$row["read_count"]),
453 "childs_read_count" => array("integer", $old["childs_read_count"]+$row["childs_read_count"]),
454 "spent_seconds" => array("integer", $old["spent_seconds"]+$row["spent_seconds"]),
455 "childs_spent_seconds" => array("integer", $old["childs_spent_seconds"]+$row["childs_spent_seconds"]));
456
457 $ilDB->update("obj_stat", $fields, $where);
458 }
459 else
460 {
461 // new entry
462 $fields = $where;
463 $fields["read_count"] = array("integer", $row["read_count"]);
464 $fields["childs_read_count"] = array("integer", $row["childs_read_count"]);
465 $fields["spent_seconds"] = array("integer", $row["spent_seconds"]);
466 $fields["childs_spent_seconds"] = array("integer", $row["childs_spent_seconds"]);
467
468 $ilDB->insert("obj_stat", $fields);
469 }
470 }
471
472 // clean up transfer table
473 $ilDB->query("DELETE FROM obj_stat_tmp");
474 }
475
476 // remove all locks (does not matter if transfer was actually performed)
477 $ilDB->unlockTables();
478 }
479 }
const LOCK_WRITE
Definition: class.ilDB.php:30

References $ilDB, $row, and ilDB\LOCK_WRITE.

Referenced by _recordObjStats(), and ilLPObjectStatisticsGUI\adminSync().

+ Here is the caller graph for this function:

◆ _updateAccessForScormOfflinePlayer()

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

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

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

Returns
true

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

1010 {
1011 global $ilDB;
1012 $res = $ilDB->queryF('UPDATE read_event SET first_access=%s, last_access = %s WHERE obj_id=%s AND usr_id=%s',
1013 array('timestamp','integer','integer','integer'),
1014 array($t_first_access,$i_last_access,$obj_id,$usr_id)
1015 );
1016 return $res;
1017 }

References $ilDB, and $res.

Referenced by ilSCORMOfflineMode\scormPlayerUnloadForSop2il().

+ Here is the caller graph for this function:

◆ hasAccessed()

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

Has accessed.

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

853 {
854 global $ilDB;
855
856 if (isset(self::$has_accessed[$a_obj_id][$a_usr_id]))
857 {
858 return self::$has_accessed[$a_obj_id][$a_usr_id];
859 }
860
861 $set = $ilDB->query("SELECT usr_id FROM read_event WHERE ".
862 "obj_id = ".$ilDB->quote($a_obj_id, "integer")." AND ".
863 "usr_id = ".$ilDB->quote($a_usr_id, "integer")
864 );
865 if ($rec = $ilDB->fetchAssoc($set))
866 {
867 return self::$has_accessed[$a_obj_id][$a_usr_id] = true;
868 }
869 return self::$has_accessed[$a_obj_id][$a_usr_id] = false;
870 }

References $ilDB.

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

+ Here is the caller graph for this function:

◆ lookupUsersInProgress()

static ilChangeEvent::lookupUsersInProgress (   $a_obj_id)
static

Lookup users in progress.

Returns

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

835 {
836 global $ilDB;
837
838 $query = sprintf('SELECT DISTINCT(usr_id) usr FROM read_event '.
839 'WHERE obj_id = %s ',
840 $ilDB->quote($a_obj_id,'integer'));
841 $res = $ilDB->query($query);
842 while($row = $ilDB->fetchObject($res))
843 {
844 $users[] = $row->usr;
845 }
846 return $users ? $users : array();
847 }

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

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

+ Here is the caller graph for this function:

Field Documentation

◆ $has_accessed

ilChangeEvent::$has_accessed = array()
staticprivate

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


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