events.rst 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. Events and Plugin Hooks
  2. #######################
  3. .. contents:: Contents
  4. :local:
  5. :depth: 2
  6. Overview
  7. ========
  8. Elgg has an event system that can be used to replace or extend core
  9. functionality.
  10. Plugins influence the system by creating handlers (`callables <http://php.net/manual/en/language.types.callable.php>`_
  11. such as functions and methods) and registering them to handle
  12. two types of events: `Elgg Events`_ and `Plugin Hooks`_.
  13. When an event is triggered, a set of handlers is executed in order
  14. of priority. Each handler is passed arguments
  15. and has a chance to influence the process. After execution, the "trigger"
  16. function returns a value based on the behavior of the handlers.
  17. Elgg Events vs. Plugin Hooks
  18. ----------------------------
  19. The main differences between `Elgg Events`_ and `Plugin Hooks`_ are:
  20. #. Most Elgg events can be cancelled; unless the event is an "after" event,
  21. a handler that returns `false` can cancel the event, and no more handlers
  22. are called.
  23. #. Plugin hooks cannot be cancelled; all handlers are always called.
  24. #. Plugin hooks pass an arbitrary value through the handlers, giving each
  25. a chance to alter along the way.
  26. Elgg Events
  27. ===========
  28. Elgg Events are triggered when an Elgg object is created, updated, or
  29. deleted; and at important milestones while the Elgg framework is
  30. loading. Examples: a blog post being created or a user logging in.
  31. Unlike `Plugin Hooks`_, *most Elgg events can be cancelled*, halting the
  32. execution of the handlers, and possibly cancelling an some
  33. action in the Elgg core.
  34. Each Elgg event has a name and an object type (system, user, object,
  35. relationship name, annotation, group) describing the type of object
  36. passed to the handlers.
  37. Before and After Events
  38. -----------------------
  39. Some events are split into "before" and "after". This avoids confusion
  40. around the state of the system while in flux. E.g. Is the user
  41. logged in during the [login, user] event?
  42. Before Events have names ending in ":before" and are triggered before
  43. something happens. Like traditional events, handlers can cancel the
  44. event by returning `false`.
  45. After Events, with names ending in ":after", are triggered after
  46. something happens. Unlike traditional events, handlers *cannot* cancel
  47. these events; all handlers will always be called.
  48. Where before and after events are available, developers are encouraged
  49. to transition to them, though older events will be supported for
  50. backwards compatibility.
  51. Elgg Event Handlers
  52. -------------------
  53. Elgg event handlers should have the following prototype:
  54. .. code:: php
  55. /**
  56. * @param string $event The name of the event
  57. * @param string $object_type The type of $object (e.g. "user", "group")
  58. * @param mixed $object The object of the event
  59. *
  60. * @return bool if false, the handler is requesting to cancel the event
  61. */
  62. function event_handler($event, $object_type, $object) {
  63. ...
  64. }
  65. If the handler returns `false`, the event is cancelled, preventing
  66. execution of the other handlers. All other return values are ignored.
  67. Register to handle an Elgg Event
  68. --------------------------------
  69. Register your handler to an event using ``elgg_register_event_handler``:
  70. .. code:: php
  71. elgg_register_event_handler($event, $object_type, $handler, $priority);
  72. Parameters:
  73. - **$event** The event name.
  74. - **$object_type** The object type (e.g. "user" or "object") or 'all' for
  75. all types on which the event is fired.
  76. - **$handler** The callback of the handler function.
  77. - **$priority** The priority - 0 is first and the default is 500.
  78. **Object** here does not refer to an ``ElggObject`` but rather a string describing any object
  79. in the framework: system, user, object, relationship, annotation, group.
  80. Example:
  81. .. code:: php
  82. // Register the function myPlugin_handle_login() to handle the
  83. // user login event with priority 400.
  84. elgg_register_event_handler('login', 'user', 'myPlugin_handle_login', 400);
  85. Trigger an Elgg Event
  86. ---------------------
  87. You can trigger a custom Elgg event using ``elgg_trigger_event``:
  88. .. code:: php
  89. if (elgg_trigger_event($event, $object_type, $object)) {
  90. // Proceed with doing something.
  91. } else {
  92. // Event was cancelled. Roll back any progress made before the event.
  93. }
  94. For events with ambiguous states, like logging in a user, you should use `Before and After Events`_
  95. by calling ``elgg_trigger_before_event`` or ``elgg_trigger_after_event``.
  96. This makes it clear for the event handler what state to expect and which events can be cancelled.
  97. .. code:: php
  98. // handlers for the user, login:before event know the user isn't logged in yet.
  99. if (!elgg_trigger_before_event('login', 'user', $user)) {
  100. return false;
  101. }
  102. // handlers for the user, login:after event know the user is logged in.
  103. elgg_trigger_after_event('login', 'user', $user);
  104. Parameters:
  105. - **$event** The event name.
  106. - **$object_type** The object type (e.g. "user" or "object").
  107. - **$object** The object (e.g. an instance of ``ElggUser`` or ``ElggGroup``)
  108. The function will return ``false`` if any of the selected handlers returned
  109. ``false`` and the event is stoppable, otherwise it will return ``true``.
  110. .. _design/events#plugin-hooks:
  111. Plugin Hooks
  112. ============
  113. Plugin Hooks provide a way for plugins to collaboratively determine or alter
  114. a value. For example, to decide whether a user has permission to edit an entity
  115. or to add additional configuration options to a plugin.
  116. A plugin hook has a value passed into the trigger function, and each handler
  117. has an opportunity to alter the value before it's passed to the next handler.
  118. After the last handler has completed, the final value is returned by the
  119. trigger.
  120. Plugin Hook Handlers
  121. --------------------
  122. Plugin hook handlers should have the following prototype:
  123. .. code:: php
  124. /**
  125. * @param string $hook The name of the plugin hook
  126. * @param string $type The type of the plugin hook
  127. * @param mixed $value The current value of the plugin hook
  128. * @param mixed $params Data passed from the trigger
  129. *
  130. * @return mixed if not null, this will be the new value of the plugin hook
  131. */
  132. function plugin_hook_handler($hook, $type, $value, $params) {
  133. ...
  134. }
  135. If the handler returns no value (or `null` explicitly), the plugin hook value
  136. is not altered. Otherwise the return value becomes the new value of the plugin
  137. hook. It will then be passed to the next handler as `$value`.
  138. Register to handle a Plugin Hook
  139. --------------------------------
  140. Register your handler to a plugin hook using ``elgg_register_plugin_hook_handler``:
  141. .. code:: php
  142. elgg_register_plugin_hook_handler($hook, $type, $handler, $priority);
  143. Parameters:
  144. - **$hook** The name of the plugin hook.
  145. - **$type** The type of the hook or 'all' for all types.
  146. - **$handler** The callback of the handler function.
  147. - **$priority** The priority - 0 is first and the default is 500.
  148. **Type** can vary in meaning. It may mean an Elgg entity type or something
  149. specific to the plugin hook name.
  150. Example:
  151. .. code:: php
  152. // Register the function myPlugin_hourly_job() to be called with priority 400.
  153. elgg_register_plugin_hook_handler('cron', 'hourly', 'myPlugin_hourly_job', 400);
  154. Trigger a Plugin Hook
  155. ---------------------
  156. You can trigger a custom plugin hook using ``elgg_trigger_plugin_hook``:
  157. .. code:: php
  158. // filter $value through the handlers
  159. $value = elgg_trigger_plugin_hook($hook, $type, $params, $value);
  160. Parameters:
  161. - **$hook** The name of the plugin hook.
  162. - **$type** The type of the hook or 'all' for all types.
  163. - **$params** Arbitrary data passed from the trigger to the handlers.
  164. - **$value** The initial value of the plugin hook.
  165. .. warning:: The `$params` and `$value` arguments are reversed between the plugin hook handlers and trigger functions!
  166. Unregister Event/Hook Handlers
  167. ------------------------------
  168. The functions ``elgg_unregister_event_handler`` and ``elgg_unregister_plugin_hook_handler`` can be used to remove
  169. handlers already registered by another plugin or Elgg core. The parameters are in the same order as the registration
  170. functions, except there's no priority parameter.
  171. .. code:: php
  172. elgg_unregister_event_handler('login', 'user', 'myPlugin_handle_login');
  173. Anonymous functions or invokable objects cannot be unregistered, but dynamic method callbacks can be unregistered
  174. by giving the static version of the callback:
  175. .. code:: php
  176. $obj = new MyPlugin\Handlers();
  177. elgg_register_plugin_hook_handler('foo', 'bar', [$obj, 'handleFoo']);
  178. // ... elsewhere
  179. elgg_unregister_plugin_hook_handler('foo', 'bar', 'MyPlugin\Handlers::handleFoo');
  180. Even though the event handler references a dynamic method call, the code above will successfully
  181. remove the handler.