DokuWiki

It's better when it's simple

User Tools

Site Tools


Sidebar

Translations of this page?:

Learn about DokuWiki

Advanced Use

Corporate Use

Our Community


Follow us on Facebook, Twitter and other social networks.

devel:event_handlers

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 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 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 TPL_ACT_RENDER event, for instance, it's possible to append content to the wiki page.1)

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 register_hook() function of the EVENT_HANDLER class, the specifications for which are found on Dokuwiki's events page. The function definition for register_hook() is as follows:

void register_hook(string $event, string $advise,
    mixed &$obj, string $method, mixed $param = null, int $seq = 0) 
  • $event is the name of the event, for instance 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 $EVENT_HANDLER:

$EVENT_HANDLER->register_hook( ... )

$EVENT_HANDLER is a reference to Doku_Event_Handler. It controls the execution of all events, both user-defined and DokuWiki-defined.

Action plugins

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:

public function register(Doku_Event_Handler $controller) {
    $controller->register_hook('TPL_ACT_RENDER','AFTER',$this,'tpl_render');    
}
  • The event is TPL_ACT_RENDER, which is activated in inc/template.php by the function which dispatches the page to be formatted and printed.
  • The event handler is tpl_render(), 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:

/**
 * @param Doku_Event $event the Doku_Event object
 * @param mixed      $param value provided as fifth argument to register_hook()
 */ 
function handler (Doku_Event $event, $param) {
    // handler code
}

When Doku_Event_Handler 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 register_hook(). 2)

The Event Object

The authoritative specification for the event object Doku_Event is found on the 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 trigger_event() 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.
  • _default: 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().
  • _continue: This value defaults to true. If $event->stopPropagation() is called, it is set to false, stopping “any further processing of the event by event handlers” but “this function does not prevent the default action taking place”.3)

Methods

    • 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->_default to false. Being able to prevent the default action has considerable utility. It can stop a page from being cached when used with the 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 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.
    • Calling this method sets $event->_continue 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 Event Loop).
    • This is a global function, not a method of the Doku_Event class. 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 action4), since using this function replaces the event's default action with the $action parameter of trigger_event().

Examples

See event handlers code samples.

See also

1)
Similarly, using BEFORE, you can prepend content.
2)
DokuWiki's own events don't seem to use $param, but it is available if needed in user-designed events.
3)
Comment from inc/events.php
4)
For an example see DokuWiki's events page.
devel/event_handlers.txt · Last modified: 2015-12-17 01:53 by samwilson