Development:Events API
The Events API is a new core system in Moodle to allow better communication between modules. It's based on modules triggering new events with attached data, and the other modules handling those events with custom functions.
Overview
We'll be using the example of a grade being posted from a module into the new gradebook in Moodle 1.9, but there are obviously all kinds of events possible.
Triggering an event
Whenever a grade is created or changed by a module, it should “tell” the system about it (in addition to any local working storage it uses). So, using the quiz as an example, we first define an object as follows:
$eventdata = new object; $eventdata->courseid = $course->id; $eventdata->itemname = $quiz->name; $eventdata->itemtype = 'mod'; $eventdata->itemmodule = 'quiz'; $eventdata->iteminstance = $quiz->id; $eventdata->itemnumber = 1; $eventdata->iteminfo = $quiz->info; $eventdata->idnumber = $cm->idnumber; // new field in 1.9 $eventdata->grademax = $quiz->grade; $eventdata->grademin = 0; $eventdata->userid = $USER->id; $eventdata->gradevalue = $currentvalue;
Then we post the object as an event and forget about it:
trigger_event('grade_added', $eventdata);
Handling an event
Modules can define an events.php in their db directory which defines events they want to be notified about, and describes which of their functions or class methods should be notified. For example, an export plugin could register something like:
$events = array ( 'grade_added' => array ( 'file' => '/grade/export/banner/lib.php', 'function' => 'banner_handle_grade', // argument to call_user_func(), could be an array 'timing' => 'cron' ); );
These are parsed during install / upgrade and stored in a simple database table.
Then, when a grade_added event happens, all the registered functions for that event will be called something like this (but with more error handling):
include_once($CFG->dirroot.$events['grade_added']['file']; call_user_func($events['grade_added']['function'], $eventdata);
All plugins in Moodle have access to this and can this easily “hook in” to 'grade_added' events (and of course any other events).
Database structure
There are 3 core tables for events. Note that if a handler is queued, and yet to be processed or processing failed, then all subsequent calls on that handler must be queued.
events_handlers
This table is for storing which components requests what type of event, and the location of the responsible handlers. For example, the grade book can register 'grade_added' event with a function add_grade() that should be called event time an 'grade_added' event is triggered by a module.
These entries are created by parsing events.php files in all the modules, and can be rebuilt any time (during an upgrade, say).
Field | Type | Info |
id | int(10) | auto increment identifier |
eventname | varchar(255) | name of the event, e.g. 'grade_added' |
handlermodule | varchar(255) | e.g. moodle, mod/forum, block/rss_client |
handlerfile | varchar(255) | path to the file of the function, eg /grade/export/lib.php |
handlerfunction | text | serialized string or array describing function, suitable to be passed to call_user_func() |
events_queues
This table is for storing queued events. It stores only one copy of the eventdata here, and entries from this table are being references by the event_queue_handlers_todo table.
Field | Type | Info |
id | int(10) | auto increment identifier |
eventdata | longtext | serialized version of the data object passed to the event handler. |
schedule | varchar(255) | 'cron' or 'instant'. |
stackdump | text | serialized debug_backtrace showing where the event was fired from |
userid | int(10) | $USER->id when the event was fired |
timecreated | int(10) | time stamp of the first time this was added |
events_queue_handlers
This is the list of queued handlers for processing. The event object is retrieved from the event_queued_events table. When no further reference is made to the event_queued_events table, the corresponding entry in the event_queued_events table should be deleted. Entry should get deleted (?) after a successful event processing by the specified handler.
Field | Type | Info |
id | int(10) | auto increment identifier |
queuedeventid | int(10) | foreign key id corresponding to the id of the event_queued_events table |
handlerid | int(10) | foreign key id corresponding to the id of the event_handlers table |
status | int(10) | number of failed attempts to process this handler |
errormessage | text | if an error happened last time we tried to process this event, record it here. |
timemodified | int(10) | time stamp of the last attempt to run this from the queue |
Standards for naming events
All event names should follow a consistent naming pattern, such as modulename_noun_verb