Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Events API

From MoodleDocs

Events and Event-based Logging. Specification for 2.6

Introduction

  • Starting from Moodle 2.6 logging is implemented in form of event-listening by plugins. The events will be objects with much more details than in 2.5- and much more specific.
  • Logging is performed by plugins listening to events.
  • In 2.6 it will also be possible to subscribe to '*' event (which means everything).
  • Everywhere where in 2.5 we add information to log or trigger an event we must generate the new event. For backward compartibility it will also contain information in the 2.5 format.

Standard Moodle distribution will include simple DB logging plugin storing the data in new format and legacy logging plugin storing the data in old format in {log} table. Old standard reports will use the new event logging. All custom reports will be able to work with {log} table using legacy logging plugin.

Triggering events

  • All events descriptions are objects extending event_base (which is defined in core)
  • Object class name is unique identifier of the event
  • Class name is pluginfullname_event_xxx. Core events will have prefix 'moodle'
  • Plugins store each event object in plugindir/classes/event/xxx.php

Backward compartibility:

  • moodle core and standard plugins will replace all usages of events_trigger() and add_to_log() with proper events
  • For events that already exist in Moodle 2.5 the additional legacy information should be added to the event data (in properties 'legacyeventname' and 'legacyeventdata')
  • For events that substitute add_to_log() call the additional property 'legacylogaction' will be specified
  • Function events_trigger() will create and trigger an instance of event_legacy class with non-empty 'legacyeventname' property and optional 'legacyeventdata'
  • Function add_to_log() will create and trigger an instance of event_legacy class with non-empty 'legacylogaction' property

Handling (observing) events

  • Event handlers can be described as it is done now in plugindir/db/events.php, this file is parsed during install/upgrade of plugin and all handlers are removed on uninstall
  • It is possible to subscribe to all events (*)
  • If event handler refers to the old (2.5) name of event, it will be used only for events that have corresponding 'legacyeventname' property. If it refers to 2.6 event class name it will be used with full data
  • It is also possible to dynamically register/unregister handlers but they are not recommended (same as it is with dynamic caches definitions). Ideally they should only be used in unit and/or behat tests

Handlers (observers) sequence

  • Event handlers can also have an attribute 'sortorder' (positive or negative, default 0).
  • User with appropriate capability can overwrite the sequence of handlers for each event type

Event properties

Those are the fields that an event could define. Depending on the type of event, some can be optional and some can be mandatory. Not all of the mandatory fields have to be set when triggering the event as some logic can help defining them in the constructor. For example, we can use $USER to find out what user is currently logged in.

There are suggested list of properties, with some mandatory fields (*) defined for the base class.

  • Event specification version number*
  • Event name*
  • Type*
    • Error
    • User action
      • Procedural action
      • Manual action
    • System log
  • Datetime* (milliseconds? DateTime object? Let's keep in mind that timestamps are unreliable as they don't include timezone!)
  • Context ID*
  • Category ID
  • Category name
  • Course ID*
  • Course name
  • Course module ID*
  • Course module name
  • Component*
    • core
    • course
    • mod_assign
    • mod_workshop
  • Subject* (Defines the object on which the action is performed)
    • user
    • section
    • assignment
    • submission_phase
  • Subject ID*
  • Subject name (Human readable identifier of the object: Mark Johnson, Course ABC, ...)
  • Subject URL (URL to notice the changes)
  • Action* (The exact action that is performed on the object)
    • created
    • moved (for a course, a section, a module, a user between groups)
    • submitted (for an assignment, or a message)
    • ended (for a submission phase for instance)
  • Actor* (user, cli, cron, ...)
  • Actor ID/User ID* (ID assiacted to the actor, typically the user id)
  • Real actor/user ID* (When logged in as, store the real user ID)
  • Actor IP address*
  • Associated object (Object associated to the subject. Ie: category of origin when a course is moved. User to whom a message is sent.)
    • section
    • category
    • user (to whom you sent a message)
  • Associated object ID
  • Transaction type* (CRUD)
    • create
    • read
    • update
    • delete
  • Level* (Reserved for internal use, probabl no more than 3 types, default to normal)
    • major
    • normal
    • minor
  • Severity (In the case of error logging, we would need to set the severity according to http://tools.ietf.org/html/rfc5424#section-6.2.1, defaults to info)
  • Message (human readable log)
  • Data (serialized/JSON'd data for more any extra field specific to this event)
  • Current URL

Data

The field data should be a placeholder for any extra information which is specific to the event. This array/object of values could describe in more details an entry which has been deleted by storing the data, or an entry updated by storing the differences, etc.... This data could ideally be converted to JSON (by a logger) to easily be stored, which means that PHP Objects cannot be included in there. We would not rely on serialized data as they have been proven not reliable.

event_base class

abstract class event_base implements cacheable_object {
  // ... constants and all properties as protected variables
  protected final function __construct() {}
  protected function __construct($args);
  public static final function create($args) {
    return new self($args);
  }
  public static final funciton restore($object) {
    $event = new self();
    // .. restore each property from $object to $event
  }
  public static final function create_and_trigger($args) {
    $event = self::create($args);
    $event->trigger();
  }
  public final function trigger() {
    // ... 
  }
  public static function event_name();
  public static function event_description();
  public function can_view($user = null);
  public function event_data();
  public function prepare_to_cache() {
    // .. basic implementation caching ALL fields
  }
  public static function wake_from_cache($a) {
    // .. basic implementation restoring ALL fields
  }
}