Hooks class

From Apibot
Jump to: navigation, search

A bot operator typically would not need to check or modify the parameters and/or data flow inside the bot internals. In some rare cases, however, it might be needed. And programmers who would like to modify or extend the bot functionality, typically by writing extensions, might find this ability very useful.

Apibot 0.40.8 introduces a Hooks object, as a part of the Core module, as the property $hooks. It allows programmers to attach their own callbacks inside the bot code, and to possibly modify the parameters and data, or the flow itself in-transit. Using these callbacks assumes some knowledge of the internal structure of Apibot.

Apibot 0.40.10 changed the Hooks module a lot. Should you need a description of the old way the module worked, it can be found in a previous revision of this page.

Mechanism

Some classes have methods that are hookable - you can replace their original functionality with your own callback. The function that does the replacing will return the callback to the original functionality - if you need to use it, preserve it and call it from your code.

If the method has already been hooked to, you will get the hooking callback instead. In this way, a hook can be attached to by many external callbacks, one after another. Should you need them hooked in a specific order, you can ensure that by listing them explicitly in the desired order in the extensions/extensions.php file (create one if it doesn't exist). Otherwise they will hook in the alphabetical order of their subdirectories in the extensions directory.

The hooking callback may be any callback recognized by PHP. It must have the same parameters as the function being hooked, with the addition of a $hook_object as a first one. For example, if you want to hook the method Exchanger_API::set_params(), which is defined as:

set_params ( $params )

you must define a callback with the following profile:

my_callback ( $hook_object, $params )

Hook names typically (but not mandatorily) consist of the class name and the hookable method name, eg. "Action_Query::xfer". Apibot will often use more than one object of the same class at the same time, so trying to establish different hooks for the different objects from the same class is a recipe for problems. Should you need that, store somewhere an Object ID for the object that you want to hook, and check inside the hook code if the call comes from the same object. (You can obtain a decent Object ID eg. by the PHP function spl_object_hash().)

A list of the hookable methods in every class will be provided in the class documentation page here.

Creating

Creating an object of the Hooks class requires one parameter - the object settings (part of the bot settings).

Public functions

Externally available

get ( $hookname )

This function returns the hook specified:

  • $hookname is the name of the hook to use.

set ( $hookname, $hook )

This function sets a hook at the specified hookname. The current hook there (original or externally set) will be returned by the function.

  • $hookname is the name of the hook to use.
  • $hook is the callback you want to hook at this place.

del ( $hookname )

This function deletes the hook at the specified hookname, reverting it to the original default Apibot hook. Returns the deleted hook, or NULL if there is none.

  • $hookname is the name of the hook to delete.

Internally used

The following functions are internally used by Apibot. Do not use them unless you really know what you are doing.

call ( $hookname, $default_hook, $hook_object, $p1 = NULL, $p2 = NULL... )

Apibot uses this function to call the hook for this hookname inside the hookable function. It is passed a mandatory default hook (the original for Apibot), hook object (the object with the hookable function) and up to ten parameters. Returns the return value of the callback.

call_default ( $hook_object, $p1 = NULL, $p2 = NULL... )

This function will play the role of default hook (original callback) when a hook is called. It merely passes the control to the function given to call() as $default_hook and temporarily remembered by the Hooks object.

An example of hooking

Suppose that you want to hook to the Action_Query set_params() function, in order to append or modify the params being set. Here is one way to do it.

class Xfer_Hook
{
  public $original_callback;

  public function set_params_hook_callback ( $hook_object, $params )
  {
    // modify here $params as you need
    return call_user_func ( $this->original_callback, $hook_object, $params );
  }

  public function capture_hook ( $core )
  {
    $this->original_callback = $core->hooks->set (
      "Action_Query::set_params",
      array ( $this, "set_params_hook_callback" )
    );
  }

}

global $xferhook;
$xferhook = new Xfer_Hook;
$xferhook->capture_hook ( $core );

You define a class that has a hook callback, a function that sets the callback to the hook needed, and a variable to hold the callback that was previously there. Then define a global variable to hold an object of your class (it should exist for the time Apibot runs). Create the object and assign it to the variable. Finally, you capture the hook to it. Now your hook will be called every time Action_Query->set_params() is called.