====== DokuWiki Event Handlers ====== DokuWiki users can create and trigger their own events and they can register to be notified of events triggered by DokuWiki. This documentation looks at how to use and write handlers for the events which are triggered by DokuWiki and are described in the DokuWiki [[events list]]. ===== The Event Loop ===== To begin with, it's helpful to understand how events are processed. To be notified of an event, your code must register to receive the notification. Registering places your request for notification on a list of requests for the event. The list is a first-come, first-served array; that is, it's treated as a stack where each next request is pushed on the end of the list. This means it's possible to implement more than one handler for the same event. When more handlers are registered, these will have a unknown, random order. When DokuWiki processes an action that has an associated event, it does not perform this action immediately. Instead, it triggers an event for this action. For instance, when DokuWiki goes to write a wiki page, it triggers an [[devel:event:IO_WIKIPAGE_WRITE]] event, which initiates the event notification process. There are actually two lists: one for before and one for after DokuWiki performs its own action. These are designated by the ''BEFORE'' and ''AFTER'' keywords, used when registering for an event. Before processing its own action, DokuWiki loops through all the ''BEFORE'' requests, making its own action the last to be processed. This gives your code the opportunity to act on this event before DokuWiki gets to it. In the case of [[devel:event:IO_WIKIPAGE_WRITE]], for instance, you can make changes to the page content before it gets sent to the browser. After performing its own action, DokuWiki loops through all the ''AFTER'' requests. In the case of the [[devel:event:TPL_ACT_RENDER]] event, for instance, it's possible to append content to the wiki page.((Similarly, using ''BEFORE'', you can prepend content.)) DokuWiki's action is the __default__. But during the ''BEFORE'' phase of some events, it's also possible to stop the default from taking place. Similarly, an event handler can short-circuit the event loop and prevent any handlers remaining on the stack from being executed. In simplified pseudo code, the event process would look like this: var $process_event = true; var $default_stopped = false; loop_through_BEFORE_List() { return if $process_event == false; } do_DokuWiki_Action() { return if $default_stopped; } var $process_event = true; loop_through_AFTER_List(){ return if $process_event == false; } ===== Registering an Event ===== Event handlers are registered using the [[xref>register_hook()]] function of the [[xref>EventHandler]] class, the specifications for which are found on Dokuwiki's [[events#registering_to_receive_an_event|events page]]. The function definition for ''register_hook()'' is as follows: void register_hook(string $event, string $advise, object $obj, string $method, mixed $param = null, int $seq = 0) * ''$event'' is the name of the event, for instance [[devel:event:IO_WIKIPAGE_WRITE]] * ''$advise'' is either ''BEFORE'' or ''AFTER'' * ''$obj'' is either a reference, which in a plugin would be the ''$this'' variable, or else it is NULL, in which case the callback function must be in the global scope * ''$method'' is the name of the callback function which will handle the event * ''$param'' is an optional container for any data which the callback might require * ''$seq'' is an optional sequence number used to control the order in which hooks are executed (since release 2014-05-05 "Ponder Stibbons"). ==== Global Scope ==== To call ''register_hook()'' from the global scope, you set ''$obj'' to null and use the global variable [[xref>$EVENT_HANDLER]]: $EVENT_HANDLER->register_hook( ... ) ''$EVENT_HANDLER'' is a reference to ''dokuwiki\Extension\EventHandler''. It controls the execution of all events, both user-defined and DokuWiki-defined. ==== Action plugins ==== [[devel:Action plugins]] do not need direct access to the global ''$EVENT_HANDLER''. They are specifically designed for adding handles to DokuWiki events, and typically you would be calling ''register_hook()'' from an action plugin. In action plugins, event handlers are registered in the ''register()'' method, which all action plugins must implement. It takes one parameter, ''$controller'', which is in effect an alias for ''$EVENT_HANDLER'' and which is used to register event handlers: use dokuwiki\Extension\EventHandler; ... public function register(EventHandler $controller) { $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'templateRender'); } * The event is [[devel:event:TPL_ACT_RENDER]], which is activated in ''[[xref>inc/template.php]]'' by the function which dispatches the page to be formatted and printed. * The event handler is ''templateRender()'', which will be found in the plugin object. * The ''$this'' parameter, which points to the plugin object, will give DokuWiki's event module access to the handler. * Finally, the handler is to be called **after** DokuWiki formats the page content. ===== The Event Handler ===== The handler has this basic form: use dokuwiki\Extension\Event; ... /** * @param Event $event the Event object * @param mixed $param value provided as fifth argument to register_hook() */ public function handler (Event $event, $param) { // handler code } When EventHandler calls the handler function, it passes in two parameters, the current ''$event'' object and ''$param''. which is designed to hold any additional data relevant to the event. ''$param'' is the ''$param'' that is passed through as the fifth parameter in [[event_handlers#registering_an_event|register_hook()]]. ((DokuWiki's own events don't seem to use ''$param'', but it is available if needed in user-designed events.)) ==== The Event Object ==== The authoritative specification for the event object [[xref>Event]] is found on the [[events#event_object|event page]] and should be consulted. The ''$event'' object has six fields: * ''name'': Event Name; * ''data'': Specific to each event, data may include, page content, headers, meta data, objects, the current action (e.g. edit, index), whatever is needed of for the execution of the event; it may also hold no data, and it has no fixed structure: it may be a string, array, multidimensional array, object. * ''result'': First it holds the return value from the default handler, which can then be consulted by an ''AFTER'' handler. It can then be modified by an ''AFTER'' handler, in which case it might be information for any subsequent ''AFTER'' handlers. Ultimately, it will be returned to the [[#methods|Event::createAndTrigger()]] function. In most case this value is either ''true'', if the default action has taken place, or ''null'' if it hasn't. * ''canPreventDefault'': ''true'' or ''false'', indicating whether or not the default action for this event can be stopped; this information is available from DokuWiki's [[events list]]. * protected ''runDefault'': ''true'' or ''false'', indicating whether the default action for this event should be enabled; its default value is true but can be set to false by calling ''$event%%->%%preventDefault()''. * protected ''mayContinue'': This value defaults to ''true''. If ''$event%%->%%stopPropagation()'' is called, it is set to false, stopping any further processing of the event ''BEFORE'' or ''AFTER'' handlers registered for this event, but this function does not prevent the default action taking place. ==== Methods ==== - ''$event%%->%%[[xref>preventDefault()]]'' * Calling this method from a ''BEFORE'' handler prevents the default action taking from place; it has no effect if called from an ''AFTER'' handler. It sets ''$event%%->%%runDefault'' to ''false''. Being able to prevent the default action has considerable utility. It can stop a page from being cached when used with the [[devel:event:PARSER_CACHE_USE]] event. It can also prevent a page from being sent to the browser at various stages of the rendering and output process, each of which is represented by an event. One enticing idea is preventing the [[devel:event:TPL_ACT_UNKNOWN]] default to set up your own action in response to an unrecognized action request. However, this idea would not work because it is blocked the by ''action_clean()'' method in inc/action.php. See the [[events list]] on the DokuWiki site for details and possibilities. - ''$event%%->%%[[xref>stopPropagation()]]''. * Calling this method sets ''$event%%->%%mayContinue'' to ''false'' and stops any further processing of the event by event handlers; it does not prevent the default action taking place. It comes into play where you have set more than one handler for the same event. If you have registered an event for both ''BEFORE'' and ''AFTER'' execution, canceling the ''BEFORE'' does not stop propagation of the ''AFTER'' events. (See the above section on the [[#the_event_loop|Event Loop]]). - ''mixed [[xref>Event::createAndTrigger|Event::createAndTrigger(string $name, mixed &$data, callable $action=null, bool $canPreventDefault=true)]]'' * This is a global function. Calling this function enables the triggering of a user-defined event. Its parameters are as follows: * ''$name'': This is the name of the event. If you implement your own event, then this is the name of that event. * ''$data'': Whatever is required for your data * ''$action'': This is the default action, most probably a function in the global scope. * ''$canPreventDefault'': ''true'' or ''false'', to indicate whether or not the default action can be stopped. In user-defined events, this can be left at the default value of ''true''. * mixed return value: This is whatever is stored in the event's property ''$event%%->%%result''. * It's possible to use this function to trigger a standard DokuWiki event, but this would require careful coding and a knowledge of when and how the DokuWiki event is processed. Moreover, triggering a standard event doesn't prevent it from being triggered by DokuWiki. It would also have to be an event which doesn't have a default action((For an example see DokuWiki's [[events#examples|events]] page.)), since using this function replaces the event's default action with the ''$action'' parameter of ''Event::createAndTrigger()''. =====Examples===== See [[event handlers code]] samples. =====See also ===== * The [[Events|Event system]] * [[Events List]] with existing events. * Use [[Action plugins]] to register handlers on events.