<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Neogic</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Neogic"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Neogic"/>
	<updated>2026-06-09T20:35:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=New_feature_ideas&amp;diff=26067</id>
		<title>New feature ideas</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=New_feature_ideas&amp;diff=26067"/>
		<updated>2011-06-17T21:01:00Z</updated>

		<summary type="html">&lt;p&gt;Neogic: /* What happens next? */  Roadmap link doesn&amp;#039;t exist - removed link.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Where to begin==&lt;br /&gt;
&lt;br /&gt;
Have you any ideas for new features or improvements you&#039;d like included in Moodle? If so, please&lt;br /&gt;
&lt;br /&gt;
# Start by [http://moodle.org/public/search/ searching moodle.org] to check whether someone else has had the same idea. The Moodle community is very large, so it&#039;s quite likely you&#039;ll find someone else with the same idea as you ;-)&lt;br /&gt;
# Either join an existing discussion about your idea or start a new discussion in an appropriate [http://moodle.org/course/view.php?id=5 Using Moodle forum].&lt;br /&gt;
# Assuming others agree with your idea, [http://tracker.moodle.org/secure/CreateIssue!default.jspa create a new issue in the Moodle tracker], selecting &#039;New feature&#039; or &#039;Improvement&#039; as the issue type. (You&#039;ll need to create a tracker account to be able to create a new issue.) Include a link to the discussion thread in the tracker issue.&lt;br /&gt;
# Post the tracker issue number in the discussion thread, so that others can watch / comment / vote for it to be implemented.&lt;br /&gt;
&lt;br /&gt;
==What happens next?==&lt;br /&gt;
&lt;br /&gt;
# The [http://tracker.moodle.org/secure/IssueNavigator.jspa?mode=hide&amp;amp;requestId=10512 list of most voted-for new features] is regularly reviewed by Moodle HQ and other core developers.&lt;br /&gt;
# Promising ideas are added to the Roadmap (depending on funding availability) and/or to the list of [[Projects for new developers]].&lt;br /&gt;
# Small feature ideas and improvements may be added to core by the component maintainer (see [[Credits]] for the list of component maintainers).&lt;br /&gt;
&lt;br /&gt;
==How to maximize the chance of your idea being implemented==&lt;br /&gt;
&lt;br /&gt;
Ideas with lots of votes are more likely to be implemented, however votes are not the only deciding factor.&lt;br /&gt;
&lt;br /&gt;
The M in Moodle stands for modular, and so the easiest ideas for new developers to implement are new modules and plugins, such as course formats (e.g. GSOC 2006 project [[Student projects/AJAX course format|AJAX course format]]), question types (e.g. GSOC 2007 project [[Student projects/New question types|New question types]]) or gradebook reports (e.g. GSOC 2008 project [[Student projects/Animated grade statistics report|Animated grade statistics report]]).&lt;br /&gt;
&lt;br /&gt;
If you&#039;re able to provide funding for your idea to be implemented, please submit a ticket at the [http://moodle.com/helpdesk/ Moodle.com helpdesk] or contact a [http://moodle.com/custom/ Moodle Partner specializing in custom development].&lt;br /&gt;
&lt;br /&gt;
If you&#039;re a developer and can [[How to create a patch|create a patch]] for your feature idea or improvement, please attach it to the tracker issue for review by the component maintainer.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program, including a list of GSOC projects from 2006, 2007 and 2008&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Project]]&lt;/div&gt;</summary>
		<author><name>Neogic</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24373</id>
		<title>Old Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24373"/>
		<updated>2011-06-07T00:58:46Z</updated>

		<summary type="html">&lt;p&gt;Neogic: /* Groups */  more compact and readable params lists&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The Events API is a core system in Moodle to allow communication between modules.  &lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;&#039;event&#039;&#039;&#039; is when something &amp;quot;interesting&amp;quot; happens in Moodle that is worth alerting the system about.&lt;br /&gt;
&lt;br /&gt;
Any Moodle modules can &#039;&#039;&#039;trigger&#039;&#039;&#039; new events (with attached data), and other modules can elect to &#039;&#039;&#039;handle&#039;&#039;&#039; those events with custom functions that operate on the given data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s look at an example of how events are used to implement Messaging in Moodle 2.0.  In the messaging system, textual messages are generated for users by different modules, and the user can decide how certain types of messages are displayed.&lt;br /&gt;
&lt;br /&gt;
===Triggering an event===&lt;br /&gt;
&lt;br /&gt;
When a messaging event occurs, the module should trigger a &amp;quot;message_send&amp;quot; event.   In this example let&#039;s pretend someone just posted to a forum.&lt;br /&gt;
&lt;br /&gt;
The forum module needs to create an object with the data that this event needs.  This may vary completely for different types of events, it&#039;s just a data object.&lt;br /&gt;
&lt;br /&gt;
 $eventdata = new object();&lt;br /&gt;
 $eventdata-&amp;gt;component         = &#039;mod/forum&#039;;    // path in Moodle&lt;br /&gt;
 $eventdata-&amp;gt;name              = &#039;posts&#039;;        // type of message from that module (as module defines it)&lt;br /&gt;
 $eventdata-&amp;gt;userfrom          = $userfrom;      // user object&lt;br /&gt;
 $eventdata-&amp;gt;userto            = $userto;        // user object&lt;br /&gt;
 $eventdata-&amp;gt;subject           = &amp;quot;Hi there&amp;quot;;     // short one-line subject&lt;br /&gt;
 $eventdata-&amp;gt;fullmessage       = &amp;quot;Here is the full message&amp;quot;;      // raw text&lt;br /&gt;
 $eventdata-&amp;gt;fullmessageformat = FORMAT_PLAIN;   // text format&lt;br /&gt;
 $eventdata-&amp;gt;fullmessagehtml   = &amp;quot;Here is the &amp;amp;lt;b&amp;gt;full&amp;amp;lt;/b&amp;gt; message&amp;quot;;    // html rendered version   (optional)&lt;br /&gt;
 $eventdata-&amp;gt;smallmessage      = &amp;quot;Here is the truncated message&amp;quot;;      // useful for plugins like sms or twitter  (optional)&lt;br /&gt;
&lt;br /&gt;
Then we post the object as an event and forget about it:&lt;br /&gt;
&lt;br /&gt;
 events_trigger(&#039;message_send&#039;, $eventdata);&lt;br /&gt;
&lt;br /&gt;
===Handling an event===&lt;br /&gt;
&lt;br /&gt;
Modules or core code can define an events.php in the db directory which defines events they want to be notified about, and describes which of their functions or class methods should be notified.  For this case, there is this definition of a handler in lib/db/events.php&lt;br /&gt;
&lt;br /&gt;
 $handlers = array (&lt;br /&gt;
     &#039;message_send&#039; =&amp;gt; array (&lt;br /&gt;
          &#039;handlerfile&#039;      =&amp;gt; &#039;/lib/messagelib.php&#039;,&lt;br /&gt;
          &#039;handlerfunction&#039;  =&amp;gt; &#039;message_send_handler&#039;,&lt;br /&gt;
          &#039;schedule&#039;         =&amp;gt; &#039;instant&#039;&lt;br /&gt;
      )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
These events.php files are parsed during install / upgrade and stored in a simple database table.&lt;br /&gt;
&lt;br /&gt;
Now, when a &#039;&#039;&#039;message_send&#039;&#039;&#039; event happens, all the registered handlers functions for that event will be called something like this (but with more error handling):&lt;br /&gt;
&lt;br /&gt;
          include_once($CFG-&amp;gt;dirroot.$handlers[&#039;message_send&#039;][&#039;handlerfile&#039;]);&lt;br /&gt;
          call_user_func($handlers[&#039;message_send&#039;][&#039;handlerfunction&#039;], $eventdata);&lt;br /&gt;
&lt;br /&gt;
Any code can hook into any events this way.&lt;br /&gt;
&lt;br /&gt;
The handler function accepts one parameter (the event data object) and should return a boolean.  Returning false indicates that there was an error and the event will be left in the event queue.&lt;br /&gt;
&lt;br /&gt;
    function message_send_handler($eventdata) {&lt;br /&gt;
        // handle event &lt;br /&gt;
        // ...&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Database structure==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===events_handlers===&lt;br /&gt;
&lt;br /&gt;
This table is for storing which components requests what type of event, and the location of the responsible handler functions.&lt;br /&gt;
&lt;br /&gt;
These entries are created by parsing events.php files in all the modules, and can be rebuilt any time (during an upgrade, say).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventname&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|name of the event, e.g. &#039;message_send&#039;&lt;br /&gt;
|-&lt;br /&gt;
|handlermodule&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|e.g. moodle, mod/forum, block/rss_client&lt;br /&gt;
|-&lt;br /&gt;
|handlerfile&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|path to the file of the function, eg /lib/messagelib.php&lt;br /&gt;
|-&lt;br /&gt;
|handlerfunction&lt;br /&gt;
|text&lt;br /&gt;
|serialized string or array describing function, suitable to be passed to &#039;&#039;&#039;call_user_func()&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|schedule 	&lt;br /&gt;
|varchar(255) 	&lt;br /&gt;
|&#039;cron&#039; or &#039;instant&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue===&lt;br /&gt;
&lt;br /&gt;
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 events_queue_handlers table.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventdata 	&lt;br /&gt;
|longtext 	&lt;br /&gt;
|serialized version of the data object passed to the event handler.&lt;br /&gt;
|-&lt;br /&gt;
|stackdump&lt;br /&gt;
|text&lt;br /&gt;
|serialized debug_backtrace showing where the event was fired from&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|int(10)&lt;br /&gt;
|$USER-&amp;gt;id when the event was fired&lt;br /&gt;
|-&lt;br /&gt;
|timecreated&lt;br /&gt;
|int(10) 	&lt;br /&gt;
|time stamp of the first time this was added&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue_handlers===&lt;br /&gt;
&lt;br /&gt;
This is the list of queued handlers for processing. The event object is retrieved from the events_queue table. When no further reference is made to the events_queue table, the corresponding entry in the events_queue table should be deleted. Entry should get deleted (?) after a successful event processing by the specified handler.  The status field keeps track of failures, after it gets to a certain number (eg 10?) it should trigger an &amp;quot;event failed&amp;quot; event (that could result in admin being emailed etc, or perhaps even the originating module taking care of it or rolling something back etc).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|queuedeventid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_queues table&lt;br /&gt;
|-&lt;br /&gt;
|handlerid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_handlers table&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|-&lt;br /&gt;
|errormessage&lt;br /&gt;
|text&lt;br /&gt;
|if an error happened last time we tried to process this event, record it here.&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int(10)&lt;br /&gt;
|time stamp of the last attempt to run this from the queue&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Standards for naming events==&lt;br /&gt;
&lt;br /&gt;
All event names should follow a consistent naming pattern, such as modulename_noun_verb&lt;br /&gt;
&lt;br /&gt;
If the event is being fired after the action has taken place (as in most cases) then use the past tense for the verb (created / deleted / updated / sent).&lt;br /&gt;
&lt;br /&gt;
If the event &#039;&#039;&#039;is&#039;&#039;&#039; the action, then use the present tense (create / delete / update / send).&lt;br /&gt;
&lt;br /&gt;
==Events which exist==&lt;br /&gt;
&lt;br /&gt;
When we add new events to core we should always add them here too.&lt;br /&gt;
&lt;br /&gt;
Under each event, list the data sent as part of the event.&lt;br /&gt;
&lt;br /&gt;
===Users===&lt;br /&gt;
* user_created&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_deleted&lt;br /&gt;
** record from &#039;user&#039; table before marked as deleted&lt;br /&gt;
* user_updated&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_enrolled&lt;br /&gt;
** full user enrolment record (TBC)&lt;br /&gt;
* user_logout&lt;br /&gt;
** params TBC&lt;br /&gt;
* user_unenrol_modified&lt;br /&gt;
** full user enrolment record (TBC)&lt;br /&gt;
* user_unenrolled&lt;br /&gt;
** full user enrolment record (TBC)&lt;br /&gt;
&lt;br /&gt;
===Roles===&lt;br /&gt;
* role_assigned&lt;br /&gt;
** full new record from &#039;role_assignments&#039; table&lt;br /&gt;
* role_unassigned&lt;br /&gt;
** record from &#039;role_assignments&#039;, course context only&lt;br /&gt;
&lt;br /&gt;
===Courses===&lt;br /&gt;
* course_created&lt;br /&gt;
** full course record&lt;br /&gt;
* course_updated&lt;br /&gt;
** full course record&lt;br /&gt;
* course_deleted&lt;br /&gt;
** full course record&lt;br /&gt;
* course_category_deleted&lt;br /&gt;
** full category record&lt;br /&gt;
* course_content_removed&lt;br /&gt;
** full course record&lt;br /&gt;
&lt;br /&gt;
===Groups===&lt;br /&gt;
* groups_member_added&lt;br /&gt;
** groupid, userid&lt;br /&gt;
* groups_member_removed&lt;br /&gt;
** groupid, userid&lt;br /&gt;
* groups_group_created&lt;br /&gt;
** id, courseid, name, description, timecreated, timemodified, picture&lt;br /&gt;
* groups_group_updated&lt;br /&gt;
** id, courseid, name, description, timecreated, timemodified, picture&lt;br /&gt;
* groups_group_deleted&lt;br /&gt;
** id, courseid, name, description, timecreated, timemodified, picture&lt;br /&gt;
* groups_grouping_created&lt;br /&gt;
** id, courseid, name, timecreated, timemodified&lt;br /&gt;
* groups_grouping_updated&lt;br /&gt;
** id, courseid, name, timecreated, timemodified&lt;br /&gt;
* groups_grouping_deleted&lt;br /&gt;
** id, courseid, name, timecreated, timemodified&lt;br /&gt;
* groups_members_removed &#039;&#039;(user deleted from all groups in a course)&#039;&#039;&lt;br /&gt;
** courseid, userid&lt;br /&gt;
* groups_groupings_groups_removed &#039;&#039;(remove all groups from all groupings in a course)&#039;&#039;&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groups_deleted &#039;&#039;(delete all groups in a course)&#039;&#039;&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groupings_deleted &#039;&#039;(delete all groupings in a course)&#039;&#039;&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
&lt;br /&gt;
===Cohorts===&lt;br /&gt;
* cohort_added&lt;br /&gt;
** full cohort record (TBC)&lt;br /&gt;
* cohort_deleted&lt;br /&gt;
** full cohort record (TBC)&lt;br /&gt;
* cohort_member_added&lt;br /&gt;
** cohort ID, user ID (TBC)&lt;br /&gt;
* cohort_member_removed&lt;br /&gt;
** cohort ID, user ID (TBC)&lt;br /&gt;
* cohort_updated&lt;br /&gt;
** full cohort record (TBC)&lt;br /&gt;
&lt;br /&gt;
===Messaging===&lt;br /&gt;
* message_send&lt;br /&gt;
** component = &#039;mod/forum&#039;: path in Moodle&lt;br /&gt;
** name = &#039;posts&#039;: type of message from that module (as module defines it)&lt;br /&gt;
** userfrom = $userfrom: a user object to send from&lt;br /&gt;
** userto = $userto: a user object to send to&lt;br /&gt;
** subject = &#039;subject line&#039;: a short text line&lt;br /&gt;
** fullmessage = &#039;full plain text&#039;: raw text as entered by user&lt;br /&gt;
** fullmessageformat = FORMAT_PLAIN|FORMAT_HTML|FORMAT_MOODLE|FORMAT_MARKDOWN: the format of this text&lt;br /&gt;
** fullmessagehtml = &#039;long html text&#039;; html rendered version (optional)&lt;br /&gt;
** smallmessage = &#039;short text&#039;: useful for plugins like sms or twitter (optional)&lt;br /&gt;
&lt;br /&gt;
===Portfolio===&lt;br /&gt;
* portfolio_send&lt;br /&gt;
** id : recordid in portfolio_tempdata table, used for itemid in file storage&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
* assessable_file_uploaded&lt;br /&gt;
* assessable_files_done&lt;br /&gt;
* mod_created&lt;br /&gt;
* mod_deleted&lt;br /&gt;
* mod_updated&lt;br /&gt;
* quiz_attempt_processed&lt;br /&gt;
* quiz_attempt_started&lt;br /&gt;
&lt;br /&gt;
==Events wishlist==&lt;br /&gt;
&lt;br /&gt;
List of events which it would be nice to have.  Please add to this list if what you want is not shown here.&lt;br /&gt;
&lt;br /&gt;
* mform_print_form -- this for all types of form e.g. admin settings, user profile, module updating, + some sort of standard way of discriminiating between them e.g. if ($form-&amp;gt;name == &#039;user_profile&#039;) {}. This would be better triggered at the end of the form generation process so that new bits can be inserted at any point, or existing bits could be removed.&lt;br /&gt;
* module_installed &#039;&#039;(= mod_created in v2?)&#039;&#039;&lt;br /&gt;
* module_removed &#039;&#039;(= mod_deleted in v2?)&#039;&#039;&lt;br /&gt;
* grade_update &#039;&#039;(= quiz_attempt_processed in v2?)&#039;&#039;&lt;br /&gt;
* assignment_submitted&lt;br /&gt;
* course completed&lt;br /&gt;
* course module completion state changed (completed / not completed)&lt;br /&gt;
&lt;br /&gt;
Provide event trigger hooks for the modules, similar to what is done for the cron service which checks the LOCAL directory for a cron file. It is already possible to define an event trigger but the core/module code must be modified to actually make use of it.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=69103 General Developer Forum thread for discussing this proposal]. &lt;br /&gt;
* [[Messaging_2.0]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Events]]&lt;br /&gt;
[[Category:Grades]]&lt;/div&gt;</summary>
		<author><name>Neogic</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24372</id>
		<title>Old Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24372"/>
		<updated>2011-06-07T00:51:15Z</updated>

		<summary type="html">&lt;p&gt;Neogic: /* Events wishlist */  note events which may already be available&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The Events API is a core system in Moodle to allow communication between modules.  &lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;&#039;event&#039;&#039;&#039; is when something &amp;quot;interesting&amp;quot; happens in Moodle that is worth alerting the system about.&lt;br /&gt;
&lt;br /&gt;
Any Moodle modules can &#039;&#039;&#039;trigger&#039;&#039;&#039; new events (with attached data), and other modules can elect to &#039;&#039;&#039;handle&#039;&#039;&#039; those events with custom functions that operate on the given data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s look at an example of how events are used to implement Messaging in Moodle 2.0.  In the messaging system, textual messages are generated for users by different modules, and the user can decide how certain types of messages are displayed.&lt;br /&gt;
&lt;br /&gt;
===Triggering an event===&lt;br /&gt;
&lt;br /&gt;
When a messaging event occurs, the module should trigger a &amp;quot;message_send&amp;quot; event.   In this example let&#039;s pretend someone just posted to a forum.&lt;br /&gt;
&lt;br /&gt;
The forum module needs to create an object with the data that this event needs.  This may vary completely for different types of events, it&#039;s just a data object.&lt;br /&gt;
&lt;br /&gt;
 $eventdata = new object();&lt;br /&gt;
 $eventdata-&amp;gt;component         = &#039;mod/forum&#039;;    // path in Moodle&lt;br /&gt;
 $eventdata-&amp;gt;name              = &#039;posts&#039;;        // type of message from that module (as module defines it)&lt;br /&gt;
 $eventdata-&amp;gt;userfrom          = $userfrom;      // user object&lt;br /&gt;
 $eventdata-&amp;gt;userto            = $userto;        // user object&lt;br /&gt;
 $eventdata-&amp;gt;subject           = &amp;quot;Hi there&amp;quot;;     // short one-line subject&lt;br /&gt;
 $eventdata-&amp;gt;fullmessage       = &amp;quot;Here is the full message&amp;quot;;      // raw text&lt;br /&gt;
 $eventdata-&amp;gt;fullmessageformat = FORMAT_PLAIN;   // text format&lt;br /&gt;
 $eventdata-&amp;gt;fullmessagehtml   = &amp;quot;Here is the &amp;amp;lt;b&amp;gt;full&amp;amp;lt;/b&amp;gt; message&amp;quot;;    // html rendered version   (optional)&lt;br /&gt;
 $eventdata-&amp;gt;smallmessage      = &amp;quot;Here is the truncated message&amp;quot;;      // useful for plugins like sms or twitter  (optional)&lt;br /&gt;
&lt;br /&gt;
Then we post the object as an event and forget about it:&lt;br /&gt;
&lt;br /&gt;
 events_trigger(&#039;message_send&#039;, $eventdata);&lt;br /&gt;
&lt;br /&gt;
===Handling an event===&lt;br /&gt;
&lt;br /&gt;
Modules or core code can define an events.php in the db directory which defines events they want to be notified about, and describes which of their functions or class methods should be notified.  For this case, there is this definition of a handler in lib/db/events.php&lt;br /&gt;
&lt;br /&gt;
 $handlers = array (&lt;br /&gt;
     &#039;message_send&#039; =&amp;gt; array (&lt;br /&gt;
          &#039;handlerfile&#039;      =&amp;gt; &#039;/lib/messagelib.php&#039;,&lt;br /&gt;
          &#039;handlerfunction&#039;  =&amp;gt; &#039;message_send_handler&#039;,&lt;br /&gt;
          &#039;schedule&#039;         =&amp;gt; &#039;instant&#039;&lt;br /&gt;
      )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
These events.php files are parsed during install / upgrade and stored in a simple database table.&lt;br /&gt;
&lt;br /&gt;
Now, when a &#039;&#039;&#039;message_send&#039;&#039;&#039; event happens, all the registered handlers functions for that event will be called something like this (but with more error handling):&lt;br /&gt;
&lt;br /&gt;
          include_once($CFG-&amp;gt;dirroot.$handlers[&#039;message_send&#039;][&#039;handlerfile&#039;]);&lt;br /&gt;
          call_user_func($handlers[&#039;message_send&#039;][&#039;handlerfunction&#039;], $eventdata);&lt;br /&gt;
&lt;br /&gt;
Any code can hook into any events this way.&lt;br /&gt;
&lt;br /&gt;
The handler function accepts one parameter (the event data object) and should return a boolean.  Returning false indicates that there was an error and the event will be left in the event queue.&lt;br /&gt;
&lt;br /&gt;
    function message_send_handler($eventdata) {&lt;br /&gt;
        // handle event &lt;br /&gt;
        // ...&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Database structure==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===events_handlers===&lt;br /&gt;
&lt;br /&gt;
This table is for storing which components requests what type of event, and the location of the responsible handler functions.&lt;br /&gt;
&lt;br /&gt;
These entries are created by parsing events.php files in all the modules, and can be rebuilt any time (during an upgrade, say).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventname&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|name of the event, e.g. &#039;message_send&#039;&lt;br /&gt;
|-&lt;br /&gt;
|handlermodule&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|e.g. moodle, mod/forum, block/rss_client&lt;br /&gt;
|-&lt;br /&gt;
|handlerfile&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|path to the file of the function, eg /lib/messagelib.php&lt;br /&gt;
|-&lt;br /&gt;
|handlerfunction&lt;br /&gt;
|text&lt;br /&gt;
|serialized string or array describing function, suitable to be passed to &#039;&#039;&#039;call_user_func()&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|schedule 	&lt;br /&gt;
|varchar(255) 	&lt;br /&gt;
|&#039;cron&#039; or &#039;instant&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue===&lt;br /&gt;
&lt;br /&gt;
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 events_queue_handlers table.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventdata 	&lt;br /&gt;
|longtext 	&lt;br /&gt;
|serialized version of the data object passed to the event handler.&lt;br /&gt;
|-&lt;br /&gt;
|stackdump&lt;br /&gt;
|text&lt;br /&gt;
|serialized debug_backtrace showing where the event was fired from&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|int(10)&lt;br /&gt;
|$USER-&amp;gt;id when the event was fired&lt;br /&gt;
|-&lt;br /&gt;
|timecreated&lt;br /&gt;
|int(10) 	&lt;br /&gt;
|time stamp of the first time this was added&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue_handlers===&lt;br /&gt;
&lt;br /&gt;
This is the list of queued handlers for processing. The event object is retrieved from the events_queue table. When no further reference is made to the events_queue table, the corresponding entry in the events_queue table should be deleted. Entry should get deleted (?) after a successful event processing by the specified handler.  The status field keeps track of failures, after it gets to a certain number (eg 10?) it should trigger an &amp;quot;event failed&amp;quot; event (that could result in admin being emailed etc, or perhaps even the originating module taking care of it or rolling something back etc).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|queuedeventid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_queues table&lt;br /&gt;
|-&lt;br /&gt;
|handlerid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_handlers table&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|-&lt;br /&gt;
|errormessage&lt;br /&gt;
|text&lt;br /&gt;
|if an error happened last time we tried to process this event, record it here.&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int(10)&lt;br /&gt;
|time stamp of the last attempt to run this from the queue&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Standards for naming events==&lt;br /&gt;
&lt;br /&gt;
All event names should follow a consistent naming pattern, such as modulename_noun_verb&lt;br /&gt;
&lt;br /&gt;
If the event is being fired after the action has taken place (as in most cases) then use the past tense for the verb (created / deleted / updated / sent).&lt;br /&gt;
&lt;br /&gt;
If the event &#039;&#039;&#039;is&#039;&#039;&#039; the action, then use the present tense (create / delete / update / send).&lt;br /&gt;
&lt;br /&gt;
==Events which exist==&lt;br /&gt;
&lt;br /&gt;
When we add new events to core we should always add them here too.&lt;br /&gt;
&lt;br /&gt;
Under each event, list the data sent as part of the event.&lt;br /&gt;
&lt;br /&gt;
===Users===&lt;br /&gt;
* user_created&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_deleted&lt;br /&gt;
** record from &#039;user&#039; table before marked as deleted&lt;br /&gt;
* user_updated&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_enrolled&lt;br /&gt;
** full user enrolment record (TBC)&lt;br /&gt;
* user_logout&lt;br /&gt;
** params TBC&lt;br /&gt;
* user_unenrol_modified&lt;br /&gt;
** full user enrolment record (TBC)&lt;br /&gt;
* user_unenrolled&lt;br /&gt;
** full user enrolment record (TBC)&lt;br /&gt;
&lt;br /&gt;
===Roles===&lt;br /&gt;
* role_assigned&lt;br /&gt;
** full new record from &#039;role_assignments&#039; table&lt;br /&gt;
* role_unassigned&lt;br /&gt;
** record from &#039;role_assignments&#039;, course context only&lt;br /&gt;
&lt;br /&gt;
===Courses===&lt;br /&gt;
* course_created&lt;br /&gt;
** full course record&lt;br /&gt;
* course_updated&lt;br /&gt;
** full course record&lt;br /&gt;
* course_deleted&lt;br /&gt;
** full course record&lt;br /&gt;
* course_category_deleted&lt;br /&gt;
** full category record&lt;br /&gt;
* course_content_removed&lt;br /&gt;
** full course record&lt;br /&gt;
&lt;br /&gt;
===Groups===&lt;br /&gt;
* groups_member_added&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_member_removed&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_group_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_grouping_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_members_removed (user deleted from all groups in a course)&lt;br /&gt;
** courseid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_groupings_groups_removed (remove all groups from all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groups_deleted (delete all groups in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groupings_deleted (delete all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
&lt;br /&gt;
===Cohorts===&lt;br /&gt;
* cohort_added&lt;br /&gt;
** full cohort record (TBC)&lt;br /&gt;
* cohort_deleted&lt;br /&gt;
** full cohort record (TBC)&lt;br /&gt;
* cohort_member_added&lt;br /&gt;
** cohort ID, user ID (TBC)&lt;br /&gt;
* cohort_member_removed&lt;br /&gt;
** cohort ID, user ID (TBC)&lt;br /&gt;
* cohort_updated&lt;br /&gt;
** full cohort record (TBC)&lt;br /&gt;
&lt;br /&gt;
===Messaging===&lt;br /&gt;
* message_send&lt;br /&gt;
** component = &#039;mod/forum&#039;: path in Moodle&lt;br /&gt;
** name = &#039;posts&#039;: type of message from that module (as module defines it)&lt;br /&gt;
** userfrom = $userfrom: a user object to send from&lt;br /&gt;
** userto = $userto: a user object to send to&lt;br /&gt;
** subject = &#039;subject line&#039;: a short text line&lt;br /&gt;
** fullmessage = &#039;full plain text&#039;: raw text as entered by user&lt;br /&gt;
** fullmessageformat = FORMAT_PLAIN|FORMAT_HTML|FORMAT_MOODLE|FORMAT_MARKDOWN: the format of this text&lt;br /&gt;
** fullmessagehtml = &#039;long html text&#039;; html rendered version (optional)&lt;br /&gt;
** smallmessage = &#039;short text&#039;: useful for plugins like sms or twitter (optional)&lt;br /&gt;
&lt;br /&gt;
===Portfolio===&lt;br /&gt;
* portfolio_send&lt;br /&gt;
** id : recordid in portfolio_tempdata table, used for itemid in file storage&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
* assessable_file_uploaded&lt;br /&gt;
* assessable_files_done&lt;br /&gt;
* mod_created&lt;br /&gt;
* mod_deleted&lt;br /&gt;
* mod_updated&lt;br /&gt;
* quiz_attempt_processed&lt;br /&gt;
* quiz_attempt_started&lt;br /&gt;
&lt;br /&gt;
==Events wishlist==&lt;br /&gt;
&lt;br /&gt;
List of events which it would be nice to have.  Please add to this list if what you want is not shown here.&lt;br /&gt;
&lt;br /&gt;
* mform_print_form -- this for all types of form e.g. admin settings, user profile, module updating, + some sort of standard way of discriminiating between them e.g. if ($form-&amp;gt;name == &#039;user_profile&#039;) {}. This would be better triggered at the end of the form generation process so that new bits can be inserted at any point, or existing bits could be removed.&lt;br /&gt;
* module_installed &#039;&#039;(= mod_created in v2?)&#039;&#039;&lt;br /&gt;
* module_removed &#039;&#039;(= mod_deleted in v2?)&#039;&#039;&lt;br /&gt;
* grade_update &#039;&#039;(= quiz_attempt_processed in v2?)&#039;&#039;&lt;br /&gt;
* assignment_submitted&lt;br /&gt;
* course completed&lt;br /&gt;
* course module completion state changed (completed / not completed)&lt;br /&gt;
&lt;br /&gt;
Provide event trigger hooks for the modules, similar to what is done for the cron service which checks the LOCAL directory for a cron file. It is already possible to define an event trigger but the core/module code must be modified to actually make use of it.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=69103 General Developer Forum thread for discussing this proposal]. &lt;br /&gt;
* [[Messaging_2.0]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Events]]&lt;br /&gt;
[[Category:Grades]]&lt;/div&gt;</summary>
		<author><name>Neogic</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24371</id>
		<title>Old Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24371"/>
		<updated>2011-06-07T00:44:16Z</updated>

		<summary type="html">&lt;p&gt;Neogic: /* Events which exist */  added missing events (found in v2.0.2 code)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The Events API is a core system in Moodle to allow communication between modules.  &lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;&#039;event&#039;&#039;&#039; is when something &amp;quot;interesting&amp;quot; happens in Moodle that is worth alerting the system about.&lt;br /&gt;
&lt;br /&gt;
Any Moodle modules can &#039;&#039;&#039;trigger&#039;&#039;&#039; new events (with attached data), and other modules can elect to &#039;&#039;&#039;handle&#039;&#039;&#039; those events with custom functions that operate on the given data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s look at an example of how events are used to implement Messaging in Moodle 2.0.  In the messaging system, textual messages are generated for users by different modules, and the user can decide how certain types of messages are displayed.&lt;br /&gt;
&lt;br /&gt;
===Triggering an event===&lt;br /&gt;
&lt;br /&gt;
When a messaging event occurs, the module should trigger a &amp;quot;message_send&amp;quot; event.   In this example let&#039;s pretend someone just posted to a forum.&lt;br /&gt;
&lt;br /&gt;
The forum module needs to create an object with the data that this event needs.  This may vary completely for different types of events, it&#039;s just a data object.&lt;br /&gt;
&lt;br /&gt;
 $eventdata = new object();&lt;br /&gt;
 $eventdata-&amp;gt;component         = &#039;mod/forum&#039;;    // path in Moodle&lt;br /&gt;
 $eventdata-&amp;gt;name              = &#039;posts&#039;;        // type of message from that module (as module defines it)&lt;br /&gt;
 $eventdata-&amp;gt;userfrom          = $userfrom;      // user object&lt;br /&gt;
 $eventdata-&amp;gt;userto            = $userto;        // user object&lt;br /&gt;
 $eventdata-&amp;gt;subject           = &amp;quot;Hi there&amp;quot;;     // short one-line subject&lt;br /&gt;
 $eventdata-&amp;gt;fullmessage       = &amp;quot;Here is the full message&amp;quot;;      // raw text&lt;br /&gt;
 $eventdata-&amp;gt;fullmessageformat = FORMAT_PLAIN;   // text format&lt;br /&gt;
 $eventdata-&amp;gt;fullmessagehtml   = &amp;quot;Here is the &amp;amp;lt;b&amp;gt;full&amp;amp;lt;/b&amp;gt; message&amp;quot;;    // html rendered version   (optional)&lt;br /&gt;
 $eventdata-&amp;gt;smallmessage      = &amp;quot;Here is the truncated message&amp;quot;;      // useful for plugins like sms or twitter  (optional)&lt;br /&gt;
&lt;br /&gt;
Then we post the object as an event and forget about it:&lt;br /&gt;
&lt;br /&gt;
 events_trigger(&#039;message_send&#039;, $eventdata);&lt;br /&gt;
&lt;br /&gt;
===Handling an event===&lt;br /&gt;
&lt;br /&gt;
Modules or core code can define an events.php in the db directory which defines events they want to be notified about, and describes which of their functions or class methods should be notified.  For this case, there is this definition of a handler in lib/db/events.php&lt;br /&gt;
&lt;br /&gt;
 $handlers = array (&lt;br /&gt;
     &#039;message_send&#039; =&amp;gt; array (&lt;br /&gt;
          &#039;handlerfile&#039;      =&amp;gt; &#039;/lib/messagelib.php&#039;,&lt;br /&gt;
          &#039;handlerfunction&#039;  =&amp;gt; &#039;message_send_handler&#039;,&lt;br /&gt;
          &#039;schedule&#039;         =&amp;gt; &#039;instant&#039;&lt;br /&gt;
      )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
These events.php files are parsed during install / upgrade and stored in a simple database table.&lt;br /&gt;
&lt;br /&gt;
Now, when a &#039;&#039;&#039;message_send&#039;&#039;&#039; event happens, all the registered handlers functions for that event will be called something like this (but with more error handling):&lt;br /&gt;
&lt;br /&gt;
          include_once($CFG-&amp;gt;dirroot.$handlers[&#039;message_send&#039;][&#039;handlerfile&#039;]);&lt;br /&gt;
          call_user_func($handlers[&#039;message_send&#039;][&#039;handlerfunction&#039;], $eventdata);&lt;br /&gt;
&lt;br /&gt;
Any code can hook into any events this way.&lt;br /&gt;
&lt;br /&gt;
The handler function accepts one parameter (the event data object) and should return a boolean.  Returning false indicates that there was an error and the event will be left in the event queue.&lt;br /&gt;
&lt;br /&gt;
    function message_send_handler($eventdata) {&lt;br /&gt;
        // handle event &lt;br /&gt;
        // ...&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Database structure==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===events_handlers===&lt;br /&gt;
&lt;br /&gt;
This table is for storing which components requests what type of event, and the location of the responsible handler functions.&lt;br /&gt;
&lt;br /&gt;
These entries are created by parsing events.php files in all the modules, and can be rebuilt any time (during an upgrade, say).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventname&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|name of the event, e.g. &#039;message_send&#039;&lt;br /&gt;
|-&lt;br /&gt;
|handlermodule&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|e.g. moodle, mod/forum, block/rss_client&lt;br /&gt;
|-&lt;br /&gt;
|handlerfile&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|path to the file of the function, eg /lib/messagelib.php&lt;br /&gt;
|-&lt;br /&gt;
|handlerfunction&lt;br /&gt;
|text&lt;br /&gt;
|serialized string or array describing function, suitable to be passed to &#039;&#039;&#039;call_user_func()&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|schedule 	&lt;br /&gt;
|varchar(255) 	&lt;br /&gt;
|&#039;cron&#039; or &#039;instant&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue===&lt;br /&gt;
&lt;br /&gt;
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 events_queue_handlers table.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventdata 	&lt;br /&gt;
|longtext 	&lt;br /&gt;
|serialized version of the data object passed to the event handler.&lt;br /&gt;
|-&lt;br /&gt;
|stackdump&lt;br /&gt;
|text&lt;br /&gt;
|serialized debug_backtrace showing where the event was fired from&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|int(10)&lt;br /&gt;
|$USER-&amp;gt;id when the event was fired&lt;br /&gt;
|-&lt;br /&gt;
|timecreated&lt;br /&gt;
|int(10) 	&lt;br /&gt;
|time stamp of the first time this was added&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue_handlers===&lt;br /&gt;
&lt;br /&gt;
This is the list of queued handlers for processing. The event object is retrieved from the events_queue table. When no further reference is made to the events_queue table, the corresponding entry in the events_queue table should be deleted. Entry should get deleted (?) after a successful event processing by the specified handler.  The status field keeps track of failures, after it gets to a certain number (eg 10?) it should trigger an &amp;quot;event failed&amp;quot; event (that could result in admin being emailed etc, or perhaps even the originating module taking care of it or rolling something back etc).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|queuedeventid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_queues table&lt;br /&gt;
|-&lt;br /&gt;
|handlerid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_handlers table&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|-&lt;br /&gt;
|errormessage&lt;br /&gt;
|text&lt;br /&gt;
|if an error happened last time we tried to process this event, record it here.&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int(10)&lt;br /&gt;
|time stamp of the last attempt to run this from the queue&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Standards for naming events==&lt;br /&gt;
&lt;br /&gt;
All event names should follow a consistent naming pattern, such as modulename_noun_verb&lt;br /&gt;
&lt;br /&gt;
If the event is being fired after the action has taken place (as in most cases) then use the past tense for the verb (created / deleted / updated / sent).&lt;br /&gt;
&lt;br /&gt;
If the event &#039;&#039;&#039;is&#039;&#039;&#039; the action, then use the present tense (create / delete / update / send).&lt;br /&gt;
&lt;br /&gt;
==Events which exist==&lt;br /&gt;
&lt;br /&gt;
When we add new events to core we should always add them here too.&lt;br /&gt;
&lt;br /&gt;
Under each event, list the data sent as part of the event.&lt;br /&gt;
&lt;br /&gt;
===Users===&lt;br /&gt;
* user_created&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_deleted&lt;br /&gt;
** record from &#039;user&#039; table before marked as deleted&lt;br /&gt;
* user_updated&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_enrolled&lt;br /&gt;
** full user enrolment record (TBC)&lt;br /&gt;
* user_logout&lt;br /&gt;
** params TBC&lt;br /&gt;
* user_unenrol_modified&lt;br /&gt;
** full user enrolment record (TBC)&lt;br /&gt;
* user_unenrolled&lt;br /&gt;
** full user enrolment record (TBC)&lt;br /&gt;
&lt;br /&gt;
===Roles===&lt;br /&gt;
* role_assigned&lt;br /&gt;
** full new record from &#039;role_assignments&#039; table&lt;br /&gt;
* role_unassigned&lt;br /&gt;
** record from &#039;role_assignments&#039;, course context only&lt;br /&gt;
&lt;br /&gt;
===Courses===&lt;br /&gt;
* course_created&lt;br /&gt;
** full course record&lt;br /&gt;
* course_updated&lt;br /&gt;
** full course record&lt;br /&gt;
* course_deleted&lt;br /&gt;
** full course record&lt;br /&gt;
* course_category_deleted&lt;br /&gt;
** full category record&lt;br /&gt;
* course_content_removed&lt;br /&gt;
** full course record&lt;br /&gt;
&lt;br /&gt;
===Groups===&lt;br /&gt;
* groups_member_added&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_member_removed&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_group_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_grouping_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_members_removed (user deleted from all groups in a course)&lt;br /&gt;
** courseid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_groupings_groups_removed (remove all groups from all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groups_deleted (delete all groups in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groupings_deleted (delete all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
&lt;br /&gt;
===Cohorts===&lt;br /&gt;
* cohort_added&lt;br /&gt;
** full cohort record (TBC)&lt;br /&gt;
* cohort_deleted&lt;br /&gt;
** full cohort record (TBC)&lt;br /&gt;
* cohort_member_added&lt;br /&gt;
** cohort ID, user ID (TBC)&lt;br /&gt;
* cohort_member_removed&lt;br /&gt;
** cohort ID, user ID (TBC)&lt;br /&gt;
* cohort_updated&lt;br /&gt;
** full cohort record (TBC)&lt;br /&gt;
&lt;br /&gt;
===Messaging===&lt;br /&gt;
* message_send&lt;br /&gt;
** component = &#039;mod/forum&#039;: path in Moodle&lt;br /&gt;
** name = &#039;posts&#039;: type of message from that module (as module defines it)&lt;br /&gt;
** userfrom = $userfrom: a user object to send from&lt;br /&gt;
** userto = $userto: a user object to send to&lt;br /&gt;
** subject = &#039;subject line&#039;: a short text line&lt;br /&gt;
** fullmessage = &#039;full plain text&#039;: raw text as entered by user&lt;br /&gt;
** fullmessageformat = FORMAT_PLAIN|FORMAT_HTML|FORMAT_MOODLE|FORMAT_MARKDOWN: the format of this text&lt;br /&gt;
** fullmessagehtml = &#039;long html text&#039;; html rendered version (optional)&lt;br /&gt;
** smallmessage = &#039;short text&#039;: useful for plugins like sms or twitter (optional)&lt;br /&gt;
&lt;br /&gt;
===Portfolio===&lt;br /&gt;
* portfolio_send&lt;br /&gt;
** id : recordid in portfolio_tempdata table, used for itemid in file storage&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
* assessable_file_uploaded&lt;br /&gt;
* assessable_files_done&lt;br /&gt;
* mod_created&lt;br /&gt;
* mod_deleted&lt;br /&gt;
* mod_updated&lt;br /&gt;
* quiz_attempt_processed&lt;br /&gt;
* quiz_attempt_started&lt;br /&gt;
&lt;br /&gt;
==Events wishlist==&lt;br /&gt;
&lt;br /&gt;
List of events which it would be nice to have.  Please add to this list if what you want is not shown here.&lt;br /&gt;
&lt;br /&gt;
* mform_print_form -- this for all types of form e.g. admin settings, user profile, module updating, + some sort of standard way of discriminiating between them e.g. if ($form-&amp;gt;name == &#039;user_profile&#039;) {}. This would be better triggered at the end of the form generation process so that new bits can be inserted at any point, or existing bits could be removed.&lt;br /&gt;
* module_installed&lt;br /&gt;
* module_removed&lt;br /&gt;
* grade_update&lt;br /&gt;
* assignment_submitted&lt;br /&gt;
* course completed&lt;br /&gt;
* course module completion state changed (completed / not completed)&lt;br /&gt;
&lt;br /&gt;
Provide event trigger hooks for the modules, similar to what is done for the cron service which checks the LOCAL directory for a cron file. It is already possible to define an event trigger but the core/module code must be modified to actually make use of it.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=69103 General Developer Forum thread for discussing this proposal]. &lt;br /&gt;
* [[Messaging_2.0]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Events]]&lt;br /&gt;
[[Category:Grades]]&lt;/div&gt;</summary>
		<author><name>Neogic</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24370</id>
		<title>Old Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24370"/>
		<updated>2011-06-07T00:31:16Z</updated>

		<summary type="html">&lt;p&gt;Neogic: /* Courses */  add missing event&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The Events API is a core system in Moodle to allow communication between modules.  &lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;&#039;event&#039;&#039;&#039; is when something &amp;quot;interesting&amp;quot; happens in Moodle that is worth alerting the system about.&lt;br /&gt;
&lt;br /&gt;
Any Moodle modules can &#039;&#039;&#039;trigger&#039;&#039;&#039; new events (with attached data), and other modules can elect to &#039;&#039;&#039;handle&#039;&#039;&#039; those events with custom functions that operate on the given data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s look at an example of how events are used to implement Messaging in Moodle 2.0.  In the messaging system, textual messages are generated for users by different modules, and the user can decide how certain types of messages are displayed.&lt;br /&gt;
&lt;br /&gt;
===Triggering an event===&lt;br /&gt;
&lt;br /&gt;
When a messaging event occurs, the module should trigger a &amp;quot;message_send&amp;quot; event.   In this example let&#039;s pretend someone just posted to a forum.&lt;br /&gt;
&lt;br /&gt;
The forum module needs to create an object with the data that this event needs.  This may vary completely for different types of events, it&#039;s just a data object.&lt;br /&gt;
&lt;br /&gt;
 $eventdata = new object();&lt;br /&gt;
 $eventdata-&amp;gt;component         = &#039;mod/forum&#039;;    // path in Moodle&lt;br /&gt;
 $eventdata-&amp;gt;name              = &#039;posts&#039;;        // type of message from that module (as module defines it)&lt;br /&gt;
 $eventdata-&amp;gt;userfrom          = $userfrom;      // user object&lt;br /&gt;
 $eventdata-&amp;gt;userto            = $userto;        // user object&lt;br /&gt;
 $eventdata-&amp;gt;subject           = &amp;quot;Hi there&amp;quot;;     // short one-line subject&lt;br /&gt;
 $eventdata-&amp;gt;fullmessage       = &amp;quot;Here is the full message&amp;quot;;      // raw text&lt;br /&gt;
 $eventdata-&amp;gt;fullmessageformat = FORMAT_PLAIN;   // text format&lt;br /&gt;
 $eventdata-&amp;gt;fullmessagehtml   = &amp;quot;Here is the &amp;amp;lt;b&amp;gt;full&amp;amp;lt;/b&amp;gt; message&amp;quot;;    // html rendered version   (optional)&lt;br /&gt;
 $eventdata-&amp;gt;smallmessage      = &amp;quot;Here is the truncated message&amp;quot;;      // useful for plugins like sms or twitter  (optional)&lt;br /&gt;
&lt;br /&gt;
Then we post the object as an event and forget about it:&lt;br /&gt;
&lt;br /&gt;
 events_trigger(&#039;message_send&#039;, $eventdata);&lt;br /&gt;
&lt;br /&gt;
===Handling an event===&lt;br /&gt;
&lt;br /&gt;
Modules or core code can define an events.php in the db directory which defines events they want to be notified about, and describes which of their functions or class methods should be notified.  For this case, there is this definition of a handler in lib/db/events.php&lt;br /&gt;
&lt;br /&gt;
 $handlers = array (&lt;br /&gt;
     &#039;message_send&#039; =&amp;gt; array (&lt;br /&gt;
          &#039;handlerfile&#039;      =&amp;gt; &#039;/lib/messagelib.php&#039;,&lt;br /&gt;
          &#039;handlerfunction&#039;  =&amp;gt; &#039;message_send_handler&#039;,&lt;br /&gt;
          &#039;schedule&#039;         =&amp;gt; &#039;instant&#039;&lt;br /&gt;
      )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
These events.php files are parsed during install / upgrade and stored in a simple database table.&lt;br /&gt;
&lt;br /&gt;
Now, when a &#039;&#039;&#039;message_send&#039;&#039;&#039; event happens, all the registered handlers functions for that event will be called something like this (but with more error handling):&lt;br /&gt;
&lt;br /&gt;
          include_once($CFG-&amp;gt;dirroot.$handlers[&#039;message_send&#039;][&#039;handlerfile&#039;]);&lt;br /&gt;
          call_user_func($handlers[&#039;message_send&#039;][&#039;handlerfunction&#039;], $eventdata);&lt;br /&gt;
&lt;br /&gt;
Any code can hook into any events this way.&lt;br /&gt;
&lt;br /&gt;
The handler function accepts one parameter (the event data object) and should return a boolean.  Returning false indicates that there was an error and the event will be left in the event queue.&lt;br /&gt;
&lt;br /&gt;
    function message_send_handler($eventdata) {&lt;br /&gt;
        // handle event &lt;br /&gt;
        // ...&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Database structure==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===events_handlers===&lt;br /&gt;
&lt;br /&gt;
This table is for storing which components requests what type of event, and the location of the responsible handler functions.&lt;br /&gt;
&lt;br /&gt;
These entries are created by parsing events.php files in all the modules, and can be rebuilt any time (during an upgrade, say).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventname&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|name of the event, e.g. &#039;message_send&#039;&lt;br /&gt;
|-&lt;br /&gt;
|handlermodule&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|e.g. moodle, mod/forum, block/rss_client&lt;br /&gt;
|-&lt;br /&gt;
|handlerfile&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|path to the file of the function, eg /lib/messagelib.php&lt;br /&gt;
|-&lt;br /&gt;
|handlerfunction&lt;br /&gt;
|text&lt;br /&gt;
|serialized string or array describing function, suitable to be passed to &#039;&#039;&#039;call_user_func()&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|schedule 	&lt;br /&gt;
|varchar(255) 	&lt;br /&gt;
|&#039;cron&#039; or &#039;instant&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue===&lt;br /&gt;
&lt;br /&gt;
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 events_queue_handlers table.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventdata 	&lt;br /&gt;
|longtext 	&lt;br /&gt;
|serialized version of the data object passed to the event handler.&lt;br /&gt;
|-&lt;br /&gt;
|stackdump&lt;br /&gt;
|text&lt;br /&gt;
|serialized debug_backtrace showing where the event was fired from&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|int(10)&lt;br /&gt;
|$USER-&amp;gt;id when the event was fired&lt;br /&gt;
|-&lt;br /&gt;
|timecreated&lt;br /&gt;
|int(10) 	&lt;br /&gt;
|time stamp of the first time this was added&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue_handlers===&lt;br /&gt;
&lt;br /&gt;
This is the list of queued handlers for processing. The event object is retrieved from the events_queue table. When no further reference is made to the events_queue table, the corresponding entry in the events_queue table should be deleted. Entry should get deleted (?) after a successful event processing by the specified handler.  The status field keeps track of failures, after it gets to a certain number (eg 10?) it should trigger an &amp;quot;event failed&amp;quot; event (that could result in admin being emailed etc, or perhaps even the originating module taking care of it or rolling something back etc).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|queuedeventid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_queues table&lt;br /&gt;
|-&lt;br /&gt;
|handlerid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_handlers table&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|-&lt;br /&gt;
|errormessage&lt;br /&gt;
|text&lt;br /&gt;
|if an error happened last time we tried to process this event, record it here.&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int(10)&lt;br /&gt;
|time stamp of the last attempt to run this from the queue&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Standards for naming events==&lt;br /&gt;
&lt;br /&gt;
All event names should follow a consistent naming pattern, such as modulename_noun_verb&lt;br /&gt;
&lt;br /&gt;
If the event is being fired after the action has taken place (as in most cases) then use the past tense for the verb (created / deleted / updated / sent).&lt;br /&gt;
&lt;br /&gt;
If the event &#039;&#039;&#039;is&#039;&#039;&#039; the action, then use the present tense (create / delete / update / send).&lt;br /&gt;
&lt;br /&gt;
==Events which exist==&lt;br /&gt;
&lt;br /&gt;
When we add new events to core we should always add them here too.&lt;br /&gt;
&lt;br /&gt;
Under each event, list the data sent as part of the event.&lt;br /&gt;
&lt;br /&gt;
===Users===&lt;br /&gt;
* user_created&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_deleted&lt;br /&gt;
** record from &#039;user&#039; table before marked as deleted&lt;br /&gt;
* user_updated&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_enrolled - &#039;&#039;params TBC&#039;&#039;&lt;br /&gt;
* user_logout - &#039;&#039;params TBC&#039;&#039;&lt;br /&gt;
* user_unenrol_modified - &#039;&#039;params TBC&#039;&#039;&lt;br /&gt;
* user_unenrolled - &#039;&#039;params TBC&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Roles===&lt;br /&gt;
* role_assigned (full new record from &#039;role_assignments&#039; table)&lt;br /&gt;
* role_unassigned (record from &#039;role_assignments&#039;, course context only)&lt;br /&gt;
&lt;br /&gt;
===Courses===&lt;br /&gt;
* course_created&lt;br /&gt;
** full course record&lt;br /&gt;
* course_updated&lt;br /&gt;
** full course record&lt;br /&gt;
* course_deleted&lt;br /&gt;
** full course record&lt;br /&gt;
* course_category_deleted&lt;br /&gt;
** full category record&lt;br /&gt;
* course_content_removed&lt;br /&gt;
** full course record&lt;br /&gt;
&lt;br /&gt;
===Groups===&lt;br /&gt;
* groups_member_added&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_member_removed&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_group_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_grouping_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_members_removed (user deleted from all groups in a course)&lt;br /&gt;
** courseid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_groupings_groups_removed (remove all groups from all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groups_deleted (delete all groups in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groupings_deleted (delete all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
&lt;br /&gt;
===Messaging===&lt;br /&gt;
* message_send&lt;br /&gt;
** component = &#039;mod/forum&#039;: path in Moodle&lt;br /&gt;
** name = &#039;posts&#039;: type of message from that module (as module defines it)&lt;br /&gt;
** userfrom = $userfrom: a user object to send from&lt;br /&gt;
** userto = $userto: a user object to send to&lt;br /&gt;
** subject = &#039;subject line&#039;: a short text line&lt;br /&gt;
** fullmessage = &#039;full plain text&#039;: raw text as entered by user&lt;br /&gt;
** fullmessageformat = FORMAT_PLAIN|FORMAT_HTML|FORMAT_MOODLE|FORMAT_MARKDOWN: the format of this text&lt;br /&gt;
** fullmessagehtml = &#039;long html text&#039;; html rendered version (optional)&lt;br /&gt;
** smallmessage = &#039;short text&#039;: useful for plugins like sms or twitter (optional)&lt;br /&gt;
&lt;br /&gt;
===Portfolio===&lt;br /&gt;
* portfolio_send&lt;br /&gt;
** id : recordid in portfolio_tempdata table, used for itemid in file storage&lt;br /&gt;
&lt;br /&gt;
==Events wishlist==&lt;br /&gt;
&lt;br /&gt;
List of events which it would be nice to have.  Please add to this list if what you want is not shown here.&lt;br /&gt;
&lt;br /&gt;
* mform_print_form -- this for all types of form e.g. admin settings, user profile, module updating, + some sort of standard way of discriminiating between them e.g. if ($form-&amp;gt;name == &#039;user_profile&#039;) {}. This would be better triggered at the end of the form generation process so that new bits can be inserted at any point, or existing bits could be removed.&lt;br /&gt;
* module_installed&lt;br /&gt;
* module_removed&lt;br /&gt;
* grade_update&lt;br /&gt;
* assignment_submitted&lt;br /&gt;
* course completed&lt;br /&gt;
* course module completion state changed (completed / not completed)&lt;br /&gt;
&lt;br /&gt;
Provide event trigger hooks for the modules, similar to what is done for the cron service which checks the LOCAL directory for a cron file. It is already possible to define an event trigger but the core/module code must be modified to actually make use of it.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=69103 General Developer Forum thread for discussing this proposal]. &lt;br /&gt;
* [[Messaging_2.0]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Events]]&lt;br /&gt;
[[Category:Grades]]&lt;/div&gt;</summary>
		<author><name>Neogic</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24369</id>
		<title>Old Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24369"/>
		<updated>2011-06-07T00:28:20Z</updated>

		<summary type="html">&lt;p&gt;Neogic: /* Users */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The Events API is a core system in Moodle to allow communication between modules.  &lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;&#039;event&#039;&#039;&#039; is when something &amp;quot;interesting&amp;quot; happens in Moodle that is worth alerting the system about.&lt;br /&gt;
&lt;br /&gt;
Any Moodle modules can &#039;&#039;&#039;trigger&#039;&#039;&#039; new events (with attached data), and other modules can elect to &#039;&#039;&#039;handle&#039;&#039;&#039; those events with custom functions that operate on the given data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s look at an example of how events are used to implement Messaging in Moodle 2.0.  In the messaging system, textual messages are generated for users by different modules, and the user can decide how certain types of messages are displayed.&lt;br /&gt;
&lt;br /&gt;
===Triggering an event===&lt;br /&gt;
&lt;br /&gt;
When a messaging event occurs, the module should trigger a &amp;quot;message_send&amp;quot; event.   In this example let&#039;s pretend someone just posted to a forum.&lt;br /&gt;
&lt;br /&gt;
The forum module needs to create an object with the data that this event needs.  This may vary completely for different types of events, it&#039;s just a data object.&lt;br /&gt;
&lt;br /&gt;
 $eventdata = new object();&lt;br /&gt;
 $eventdata-&amp;gt;component         = &#039;mod/forum&#039;;    // path in Moodle&lt;br /&gt;
 $eventdata-&amp;gt;name              = &#039;posts&#039;;        // type of message from that module (as module defines it)&lt;br /&gt;
 $eventdata-&amp;gt;userfrom          = $userfrom;      // user object&lt;br /&gt;
 $eventdata-&amp;gt;userto            = $userto;        // user object&lt;br /&gt;
 $eventdata-&amp;gt;subject           = &amp;quot;Hi there&amp;quot;;     // short one-line subject&lt;br /&gt;
 $eventdata-&amp;gt;fullmessage       = &amp;quot;Here is the full message&amp;quot;;      // raw text&lt;br /&gt;
 $eventdata-&amp;gt;fullmessageformat = FORMAT_PLAIN;   // text format&lt;br /&gt;
 $eventdata-&amp;gt;fullmessagehtml   = &amp;quot;Here is the &amp;amp;lt;b&amp;gt;full&amp;amp;lt;/b&amp;gt; message&amp;quot;;    // html rendered version   (optional)&lt;br /&gt;
 $eventdata-&amp;gt;smallmessage      = &amp;quot;Here is the truncated message&amp;quot;;      // useful for plugins like sms or twitter  (optional)&lt;br /&gt;
&lt;br /&gt;
Then we post the object as an event and forget about it:&lt;br /&gt;
&lt;br /&gt;
 events_trigger(&#039;message_send&#039;, $eventdata);&lt;br /&gt;
&lt;br /&gt;
===Handling an event===&lt;br /&gt;
&lt;br /&gt;
Modules or core code can define an events.php in the db directory which defines events they want to be notified about, and describes which of their functions or class methods should be notified.  For this case, there is this definition of a handler in lib/db/events.php&lt;br /&gt;
&lt;br /&gt;
 $handlers = array (&lt;br /&gt;
     &#039;message_send&#039; =&amp;gt; array (&lt;br /&gt;
          &#039;handlerfile&#039;      =&amp;gt; &#039;/lib/messagelib.php&#039;,&lt;br /&gt;
          &#039;handlerfunction&#039;  =&amp;gt; &#039;message_send_handler&#039;,&lt;br /&gt;
          &#039;schedule&#039;         =&amp;gt; &#039;instant&#039;&lt;br /&gt;
      )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
These events.php files are parsed during install / upgrade and stored in a simple database table.&lt;br /&gt;
&lt;br /&gt;
Now, when a &#039;&#039;&#039;message_send&#039;&#039;&#039; event happens, all the registered handlers functions for that event will be called something like this (but with more error handling):&lt;br /&gt;
&lt;br /&gt;
          include_once($CFG-&amp;gt;dirroot.$handlers[&#039;message_send&#039;][&#039;handlerfile&#039;]);&lt;br /&gt;
          call_user_func($handlers[&#039;message_send&#039;][&#039;handlerfunction&#039;], $eventdata);&lt;br /&gt;
&lt;br /&gt;
Any code can hook into any events this way.&lt;br /&gt;
&lt;br /&gt;
The handler function accepts one parameter (the event data object) and should return a boolean.  Returning false indicates that there was an error and the event will be left in the event queue.&lt;br /&gt;
&lt;br /&gt;
    function message_send_handler($eventdata) {&lt;br /&gt;
        // handle event &lt;br /&gt;
        // ...&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Database structure==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===events_handlers===&lt;br /&gt;
&lt;br /&gt;
This table is for storing which components requests what type of event, and the location of the responsible handler functions.&lt;br /&gt;
&lt;br /&gt;
These entries are created by parsing events.php files in all the modules, and can be rebuilt any time (during an upgrade, say).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventname&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|name of the event, e.g. &#039;message_send&#039;&lt;br /&gt;
|-&lt;br /&gt;
|handlermodule&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|e.g. moodle, mod/forum, block/rss_client&lt;br /&gt;
|-&lt;br /&gt;
|handlerfile&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|path to the file of the function, eg /lib/messagelib.php&lt;br /&gt;
|-&lt;br /&gt;
|handlerfunction&lt;br /&gt;
|text&lt;br /&gt;
|serialized string or array describing function, suitable to be passed to &#039;&#039;&#039;call_user_func()&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|schedule 	&lt;br /&gt;
|varchar(255) 	&lt;br /&gt;
|&#039;cron&#039; or &#039;instant&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue===&lt;br /&gt;
&lt;br /&gt;
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 events_queue_handlers table.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventdata 	&lt;br /&gt;
|longtext 	&lt;br /&gt;
|serialized version of the data object passed to the event handler.&lt;br /&gt;
|-&lt;br /&gt;
|stackdump&lt;br /&gt;
|text&lt;br /&gt;
|serialized debug_backtrace showing where the event was fired from&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|int(10)&lt;br /&gt;
|$USER-&amp;gt;id when the event was fired&lt;br /&gt;
|-&lt;br /&gt;
|timecreated&lt;br /&gt;
|int(10) 	&lt;br /&gt;
|time stamp of the first time this was added&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue_handlers===&lt;br /&gt;
&lt;br /&gt;
This is the list of queued handlers for processing. The event object is retrieved from the events_queue table. When no further reference is made to the events_queue table, the corresponding entry in the events_queue table should be deleted. Entry should get deleted (?) after a successful event processing by the specified handler.  The status field keeps track of failures, after it gets to a certain number (eg 10?) it should trigger an &amp;quot;event failed&amp;quot; event (that could result in admin being emailed etc, or perhaps even the originating module taking care of it or rolling something back etc).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|queuedeventid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_queues table&lt;br /&gt;
|-&lt;br /&gt;
|handlerid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_handlers table&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|-&lt;br /&gt;
|errormessage&lt;br /&gt;
|text&lt;br /&gt;
|if an error happened last time we tried to process this event, record it here.&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int(10)&lt;br /&gt;
|time stamp of the last attempt to run this from the queue&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Standards for naming events==&lt;br /&gt;
&lt;br /&gt;
All event names should follow a consistent naming pattern, such as modulename_noun_verb&lt;br /&gt;
&lt;br /&gt;
If the event is being fired after the action has taken place (as in most cases) then use the past tense for the verb (created / deleted / updated / sent).&lt;br /&gt;
&lt;br /&gt;
If the event &#039;&#039;&#039;is&#039;&#039;&#039; the action, then use the present tense (create / delete / update / send).&lt;br /&gt;
&lt;br /&gt;
==Events which exist==&lt;br /&gt;
&lt;br /&gt;
When we add new events to core we should always add them here too.&lt;br /&gt;
&lt;br /&gt;
Under each event, list the data sent as part of the event.&lt;br /&gt;
&lt;br /&gt;
===Users===&lt;br /&gt;
* user_created&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_deleted&lt;br /&gt;
** record from &#039;user&#039; table before marked as deleted&lt;br /&gt;
* user_updated&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_enrolled - &#039;&#039;params TBC&#039;&#039;&lt;br /&gt;
* user_logout - &#039;&#039;params TBC&#039;&#039;&lt;br /&gt;
* user_unenrol_modified - &#039;&#039;params TBC&#039;&#039;&lt;br /&gt;
* user_unenrolled - &#039;&#039;params TBC&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Roles===&lt;br /&gt;
* role_assigned (full new record from &#039;role_assignments&#039; table)&lt;br /&gt;
* role_unassigned (record from &#039;role_assignments&#039;, course context only)&lt;br /&gt;
&lt;br /&gt;
===Courses===&lt;br /&gt;
* course_created&lt;br /&gt;
** full course record&lt;br /&gt;
* course_updated&lt;br /&gt;
** full course record&lt;br /&gt;
* course_deleted&lt;br /&gt;
** full course record&lt;br /&gt;
* course_category_deleted&lt;br /&gt;
** full category record&lt;br /&gt;
&lt;br /&gt;
===Groups===&lt;br /&gt;
* groups_member_added&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_member_removed&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_group_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_grouping_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_members_removed (user deleted from all groups in a course)&lt;br /&gt;
** courseid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_groupings_groups_removed (remove all groups from all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groups_deleted (delete all groups in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groupings_deleted (delete all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
&lt;br /&gt;
===Messaging===&lt;br /&gt;
* message_send&lt;br /&gt;
** component = &#039;mod/forum&#039;: path in Moodle&lt;br /&gt;
** name = &#039;posts&#039;: type of message from that module (as module defines it)&lt;br /&gt;
** userfrom = $userfrom: a user object to send from&lt;br /&gt;
** userto = $userto: a user object to send to&lt;br /&gt;
** subject = &#039;subject line&#039;: a short text line&lt;br /&gt;
** fullmessage = &#039;full plain text&#039;: raw text as entered by user&lt;br /&gt;
** fullmessageformat = FORMAT_PLAIN|FORMAT_HTML|FORMAT_MOODLE|FORMAT_MARKDOWN: the format of this text&lt;br /&gt;
** fullmessagehtml = &#039;long html text&#039;; html rendered version (optional)&lt;br /&gt;
** smallmessage = &#039;short text&#039;: useful for plugins like sms or twitter (optional)&lt;br /&gt;
&lt;br /&gt;
===Portfolio===&lt;br /&gt;
* portfolio_send&lt;br /&gt;
** id : recordid in portfolio_tempdata table, used for itemid in file storage&lt;br /&gt;
&lt;br /&gt;
==Events wishlist==&lt;br /&gt;
&lt;br /&gt;
List of events which it would be nice to have.  Please add to this list if what you want is not shown here.&lt;br /&gt;
&lt;br /&gt;
* mform_print_form -- this for all types of form e.g. admin settings, user profile, module updating, + some sort of standard way of discriminiating between them e.g. if ($form-&amp;gt;name == &#039;user_profile&#039;) {}. This would be better triggered at the end of the form generation process so that new bits can be inserted at any point, or existing bits could be removed.&lt;br /&gt;
* module_installed&lt;br /&gt;
* module_removed&lt;br /&gt;
* grade_update&lt;br /&gt;
* assignment_submitted&lt;br /&gt;
* course completed&lt;br /&gt;
* course module completion state changed (completed / not completed)&lt;br /&gt;
&lt;br /&gt;
Provide event trigger hooks for the modules, similar to what is done for the cron service which checks the LOCAL directory for a cron file. It is already possible to define an event trigger but the core/module code must be modified to actually make use of it.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=69103 General Developer Forum thread for discussing this proposal]. &lt;br /&gt;
* [[Messaging_2.0]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Events]]&lt;br /&gt;
[[Category:Grades]]&lt;/div&gt;</summary>
		<author><name>Neogic</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24368</id>
		<title>Old Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Old_Events_API&amp;diff=24368"/>
		<updated>2011-06-07T00:24:58Z</updated>

		<summary type="html">&lt;p&gt;Neogic: /* Users */  add missing v2 events&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The Events API is a core system in Moodle to allow communication between modules.  &lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;&#039;event&#039;&#039;&#039; is when something &amp;quot;interesting&amp;quot; happens in Moodle that is worth alerting the system about.&lt;br /&gt;
&lt;br /&gt;
Any Moodle modules can &#039;&#039;&#039;trigger&#039;&#039;&#039; new events (with attached data), and other modules can elect to &#039;&#039;&#039;handle&#039;&#039;&#039; those events with custom functions that operate on the given data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s look at an example of how events are used to implement Messaging in Moodle 2.0.  In the messaging system, textual messages are generated for users by different modules, and the user can decide how certain types of messages are displayed.&lt;br /&gt;
&lt;br /&gt;
===Triggering an event===&lt;br /&gt;
&lt;br /&gt;
When a messaging event occurs, the module should trigger a &amp;quot;message_send&amp;quot; event.   In this example let&#039;s pretend someone just posted to a forum.&lt;br /&gt;
&lt;br /&gt;
The forum module needs to create an object with the data that this event needs.  This may vary completely for different types of events, it&#039;s just a data object.&lt;br /&gt;
&lt;br /&gt;
 $eventdata = new object();&lt;br /&gt;
 $eventdata-&amp;gt;component         = &#039;mod/forum&#039;;    // path in Moodle&lt;br /&gt;
 $eventdata-&amp;gt;name              = &#039;posts&#039;;        // type of message from that module (as module defines it)&lt;br /&gt;
 $eventdata-&amp;gt;userfrom          = $userfrom;      // user object&lt;br /&gt;
 $eventdata-&amp;gt;userto            = $userto;        // user object&lt;br /&gt;
 $eventdata-&amp;gt;subject           = &amp;quot;Hi there&amp;quot;;     // short one-line subject&lt;br /&gt;
 $eventdata-&amp;gt;fullmessage       = &amp;quot;Here is the full message&amp;quot;;      // raw text&lt;br /&gt;
 $eventdata-&amp;gt;fullmessageformat = FORMAT_PLAIN;   // text format&lt;br /&gt;
 $eventdata-&amp;gt;fullmessagehtml   = &amp;quot;Here is the &amp;amp;lt;b&amp;gt;full&amp;amp;lt;/b&amp;gt; message&amp;quot;;    // html rendered version   (optional)&lt;br /&gt;
 $eventdata-&amp;gt;smallmessage      = &amp;quot;Here is the truncated message&amp;quot;;      // useful for plugins like sms or twitter  (optional)&lt;br /&gt;
&lt;br /&gt;
Then we post the object as an event and forget about it:&lt;br /&gt;
&lt;br /&gt;
 events_trigger(&#039;message_send&#039;, $eventdata);&lt;br /&gt;
&lt;br /&gt;
===Handling an event===&lt;br /&gt;
&lt;br /&gt;
Modules or core code can define an events.php in the db directory which defines events they want to be notified about, and describes which of their functions or class methods should be notified.  For this case, there is this definition of a handler in lib/db/events.php&lt;br /&gt;
&lt;br /&gt;
 $handlers = array (&lt;br /&gt;
     &#039;message_send&#039; =&amp;gt; array (&lt;br /&gt;
          &#039;handlerfile&#039;      =&amp;gt; &#039;/lib/messagelib.php&#039;,&lt;br /&gt;
          &#039;handlerfunction&#039;  =&amp;gt; &#039;message_send_handler&#039;,&lt;br /&gt;
          &#039;schedule&#039;         =&amp;gt; &#039;instant&#039;&lt;br /&gt;
      )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
These events.php files are parsed during install / upgrade and stored in a simple database table.&lt;br /&gt;
&lt;br /&gt;
Now, when a &#039;&#039;&#039;message_send&#039;&#039;&#039; event happens, all the registered handlers functions for that event will be called something like this (but with more error handling):&lt;br /&gt;
&lt;br /&gt;
          include_once($CFG-&amp;gt;dirroot.$handlers[&#039;message_send&#039;][&#039;handlerfile&#039;]);&lt;br /&gt;
          call_user_func($handlers[&#039;message_send&#039;][&#039;handlerfunction&#039;], $eventdata);&lt;br /&gt;
&lt;br /&gt;
Any code can hook into any events this way.&lt;br /&gt;
&lt;br /&gt;
The handler function accepts one parameter (the event data object) and should return a boolean.  Returning false indicates that there was an error and the event will be left in the event queue.&lt;br /&gt;
&lt;br /&gt;
    function message_send_handler($eventdata) {&lt;br /&gt;
        // handle event &lt;br /&gt;
        // ...&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
==Database structure==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===events_handlers===&lt;br /&gt;
&lt;br /&gt;
This table is for storing which components requests what type of event, and the location of the responsible handler functions.&lt;br /&gt;
&lt;br /&gt;
These entries are created by parsing events.php files in all the modules, and can be rebuilt any time (during an upgrade, say).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventname&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|name of the event, e.g. &#039;message_send&#039;&lt;br /&gt;
|-&lt;br /&gt;
|handlermodule&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|e.g. moodle, mod/forum, block/rss_client&lt;br /&gt;
|-&lt;br /&gt;
|handlerfile&lt;br /&gt;
|varchar(255)&lt;br /&gt;
|path to the file of the function, eg /lib/messagelib.php&lt;br /&gt;
|-&lt;br /&gt;
|handlerfunction&lt;br /&gt;
|text&lt;br /&gt;
|serialized string or array describing function, suitable to be passed to &#039;&#039;&#039;call_user_func()&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|schedule 	&lt;br /&gt;
|varchar(255) 	&lt;br /&gt;
|&#039;cron&#039; or &#039;instant&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue===&lt;br /&gt;
&lt;br /&gt;
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 events_queue_handlers table.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|eventdata 	&lt;br /&gt;
|longtext 	&lt;br /&gt;
|serialized version of the data object passed to the event handler.&lt;br /&gt;
|-&lt;br /&gt;
|stackdump&lt;br /&gt;
|text&lt;br /&gt;
|serialized debug_backtrace showing where the event was fired from&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|int(10)&lt;br /&gt;
|$USER-&amp;gt;id when the event was fired&lt;br /&gt;
|-&lt;br /&gt;
|timecreated&lt;br /&gt;
|int(10) 	&lt;br /&gt;
|time stamp of the first time this was added&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===events_queue_handlers===&lt;br /&gt;
&lt;br /&gt;
This is the list of queued handlers for processing. The event object is retrieved from the events_queue table. When no further reference is made to the events_queue table, the corresponding entry in the events_queue table should be deleted. Entry should get deleted (?) after a successful event processing by the specified handler.  The status field keeps track of failures, after it gets to a certain number (eg 10?) it should trigger an &amp;quot;event failed&amp;quot; event (that could result in admin being emailed etc, or perhaps even the originating module taking care of it or rolling something back etc).&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Type&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Info&#039;&#039;&#039;&lt;br /&gt;
|- &lt;br /&gt;
|id&lt;br /&gt;
|int(10)&lt;br /&gt;
|auto increment identifier&lt;br /&gt;
|-&lt;br /&gt;
|queuedeventid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_queues table&lt;br /&gt;
|-&lt;br /&gt;
|handlerid&lt;br /&gt;
|int(10)&lt;br /&gt;
|foreign key id corresponding to the id of the event_handlers table&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|int(10)&lt;br /&gt;
|number of failed attempts to process this handler&lt;br /&gt;
|-&lt;br /&gt;
|errormessage&lt;br /&gt;
|text&lt;br /&gt;
|if an error happened last time we tried to process this event, record it here.&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int(10)&lt;br /&gt;
|time stamp of the last attempt to run this from the queue&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Standards for naming events==&lt;br /&gt;
&lt;br /&gt;
All event names should follow a consistent naming pattern, such as modulename_noun_verb&lt;br /&gt;
&lt;br /&gt;
If the event is being fired after the action has taken place (as in most cases) then use the past tense for the verb (created / deleted / updated / sent).&lt;br /&gt;
&lt;br /&gt;
If the event &#039;&#039;&#039;is&#039;&#039;&#039; the action, then use the present tense (create / delete / update / send).&lt;br /&gt;
&lt;br /&gt;
==Events which exist==&lt;br /&gt;
&lt;br /&gt;
When we add new events to core we should always add them here too.&lt;br /&gt;
&lt;br /&gt;
Under each event, list the data sent as part of the event.&lt;br /&gt;
&lt;br /&gt;
===Users===&lt;br /&gt;
* user_created&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_deleted&lt;br /&gt;
** record from &#039;user&#039; table before marked as deleted&lt;br /&gt;
* user_updated&lt;br /&gt;
** full new record from &#039;user&#039; table&lt;br /&gt;
* user_enrolled (new in v2 - params TBC)&lt;br /&gt;
* user_logout (new in v2 - params TBC)&lt;br /&gt;
* user_unenrol_modified (new in v2 - params TBC)&lt;br /&gt;
* user_unenrolled (new in v2 - params TBC)&lt;br /&gt;
&lt;br /&gt;
===Roles===&lt;br /&gt;
* role_assigned (full new record from &#039;role_assignments&#039; table)&lt;br /&gt;
* role_unassigned (record from &#039;role_assignments&#039;, course context only)&lt;br /&gt;
&lt;br /&gt;
===Courses===&lt;br /&gt;
* course_created&lt;br /&gt;
** full course record&lt;br /&gt;
* course_updated&lt;br /&gt;
** full course record&lt;br /&gt;
* course_deleted&lt;br /&gt;
** full course record&lt;br /&gt;
* course_category_deleted&lt;br /&gt;
** full category record&lt;br /&gt;
&lt;br /&gt;
===Groups===&lt;br /&gt;
* groups_member_added&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_member_removed&lt;br /&gt;
** groupid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_group_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_group_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** description&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
** picture&lt;br /&gt;
* groups_grouping_created&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_updated&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_grouping_deleted&lt;br /&gt;
** id&lt;br /&gt;
** courseid&lt;br /&gt;
** name&lt;br /&gt;
** timecreated&lt;br /&gt;
** timemodified&lt;br /&gt;
* groups_members_removed (user deleted from all groups in a course)&lt;br /&gt;
** courseid&lt;br /&gt;
** userid&lt;br /&gt;
* groups_groupings_groups_removed (remove all groups from all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groups_deleted (delete all groups in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
* groups_groupings_deleted (delete all groupings in a course)&lt;br /&gt;
** courseid (as plain integer, not object)&lt;br /&gt;
&lt;br /&gt;
===Messaging===&lt;br /&gt;
* message_send&lt;br /&gt;
** component = &#039;mod/forum&#039;: path in Moodle&lt;br /&gt;
** name = &#039;posts&#039;: type of message from that module (as module defines it)&lt;br /&gt;
** userfrom = $userfrom: a user object to send from&lt;br /&gt;
** userto = $userto: a user object to send to&lt;br /&gt;
** subject = &#039;subject line&#039;: a short text line&lt;br /&gt;
** fullmessage = &#039;full plain text&#039;: raw text as entered by user&lt;br /&gt;
** fullmessageformat = FORMAT_PLAIN|FORMAT_HTML|FORMAT_MOODLE|FORMAT_MARKDOWN: the format of this text&lt;br /&gt;
** fullmessagehtml = &#039;long html text&#039;; html rendered version (optional)&lt;br /&gt;
** smallmessage = &#039;short text&#039;: useful for plugins like sms or twitter (optional)&lt;br /&gt;
&lt;br /&gt;
===Portfolio===&lt;br /&gt;
* portfolio_send&lt;br /&gt;
** id : recordid in portfolio_tempdata table, used for itemid in file storage&lt;br /&gt;
&lt;br /&gt;
==Events wishlist==&lt;br /&gt;
&lt;br /&gt;
List of events which it would be nice to have.  Please add to this list if what you want is not shown here.&lt;br /&gt;
&lt;br /&gt;
* mform_print_form -- this for all types of form e.g. admin settings, user profile, module updating, + some sort of standard way of discriminiating between them e.g. if ($form-&amp;gt;name == &#039;user_profile&#039;) {}. This would be better triggered at the end of the form generation process so that new bits can be inserted at any point, or existing bits could be removed.&lt;br /&gt;
* module_installed&lt;br /&gt;
* module_removed&lt;br /&gt;
* grade_update&lt;br /&gt;
* assignment_submitted&lt;br /&gt;
* course completed&lt;br /&gt;
* course module completion state changed (completed / not completed)&lt;br /&gt;
&lt;br /&gt;
Provide event trigger hooks for the modules, similar to what is done for the cron service which checks the LOCAL directory for a cron file. It is already possible to define an event trigger but the core/module code must be modified to actually make use of it.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=69103 General Developer Forum thread for discussing this proposal]. &lt;br /&gt;
* [[Messaging_2.0]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Events]]&lt;br /&gt;
[[Category:Grades]]&lt;/div&gt;</summary>
		<author><name>Neogic</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Old_Events_API&amp;diff=24367</id>
		<title>Talk:Old Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Old_Events_API&amp;diff=24367"/>
		<updated>2011-06-07T00:19:08Z</updated>

		<summary type="html">&lt;p&gt;Neogic: Created page with &amp;quot;* Gah! Already updated the &amp;quot;Events which exist&amp;quot; list a few weeks ago, but my changes appear to have been lost (and don&amp;#039;t appear in the history). Was the page reset during the Moo...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Gah! Already updated the &amp;quot;Events which exist&amp;quot; list a few weeks ago, but my changes appear to have been lost (and don&#039;t appear in the history). Was the page reset during the MoodleDocs maintenance?&lt;br /&gt;
* Any how .. here&#039;s complete list of events (with raw-ish params used in code) triggered by v2.0.2, according to a code search for &amp;quot;trigger_event&amp;quot;:&amp;lt;br /&amp;gt;&lt;br /&gt;
** assessable_file_uploaded  -  $eventdata&lt;br /&gt;
** assessable_files_done  -  $eventdata&lt;br /&gt;
** cohort_added  -  $cohort&lt;br /&gt;
** cohort_deleted  -  $cohort&lt;br /&gt;
** cohort_member_added  -  {$cohortid, $userid}&lt;br /&gt;
** cohort_member_removed  -  {$cohortid, $userid}&lt;br /&gt;
** cohort_updated  -  $cohort&lt;br /&gt;
** course_category_deleted  -  $category&lt;br /&gt;
** course_content_removed  -  $course&lt;br /&gt;
** course_created  -  $course&lt;br /&gt;
** course_deleted  -  $course&lt;br /&gt;
** course_updated  -  $course&lt;br /&gt;
** groups_group_created  -  $group&lt;br /&gt;
** groups_group_deleted  -  $group&lt;br /&gt;
** groups_group_updated  -  $group&lt;br /&gt;
** groups_grouping_created  -  $data&lt;br /&gt;
** groups_grouping_deleted  -  $grouping&lt;br /&gt;
** groups_grouping_updated  -  $data&lt;br /&gt;
** groups_groupings_deleted  -  $courseid&lt;br /&gt;
** groups_groupings_groups_removed  -  $courseid&lt;br /&gt;
** groups_groups_deleted  -  $courseid&lt;br /&gt;
** groups_member_added  -  $eventdata&lt;br /&gt;
** groups_member_removed  -  $eventdata&lt;br /&gt;
** groups_members_removed  -  $eventdata&lt;br /&gt;
** mod_created  -  $eventdata&lt;br /&gt;
** mod_deleted  -  $eventdata&lt;br /&gt;
** mod_updated  -  $eventdata&lt;br /&gt;
** portfolio_send  -  $this-&amp;gt;id&lt;br /&gt;
** quiz_attempt_processed  -  $eventdata&lt;br /&gt;
** quiz_attempt_started  -  $eventdata&lt;br /&gt;
** role_assigned  -  $ra&lt;br /&gt;
** role_unassigned  -  $ra&lt;br /&gt;
** user_created  -  $user&lt;br /&gt;
** user_deleted  -  $user&lt;br /&gt;
** user_enrolled  -  $ue&lt;br /&gt;
** user_logout  -  $params&lt;br /&gt;
** user_unenrol_modified  -  $ue&lt;br /&gt;
** user_unenrolled  -  $ue&lt;br /&gt;
** user_updated  -  $user&lt;br /&gt;
&lt;br /&gt;
--[[User:B Johnson|B Johnson]] 08:19, 7 June 2011 (WST)&lt;/div&gt;</summary>
		<author><name>Neogic</name></author>
	</entry>
</feed>