Object Level Callbacks

Most MT::Object operations can trigger callbacks to plugin code. Some notable uses of this feature are:

  • to be notified when a database record is modified
  • to pre- or post-process the data being flowing to the database

To add a callback, invoke the add_callback method of the MT::Object subclass, as follows:

MT::Foo->add_callback( "pre_save", <priority>, 
                     <plugin object>, \&callback_function);

The first argument is the name of the hook point. Any MT::Object subclass has a pre_ and a post_ hook point for each of the following operations:

  • load
  • save
  • remove
  • remove_all

  • load_iter operations will call the load callbacks

The second argument priority, is the relative order in which the callback should be called. The value should be between 1 and 10, inclusive. Callbacks with priority 1 will be called before those with 2, 2 before 3, and so on.

Plugins which know they need to run first or last can use the priority values 0 and 11. A callback with priority 0 will run before all others, and if two callbacks try to use that value, an error will result. Likewise priority 11 is exclusive, and runs last.

Need a tip on how to remember which callback priorities are special? As you know, most guitar amps have a volume knob that goes from 1 to 10. But, like that of certain rock stars, our amp goes up to 11. A callback with priority 11 is the "loudest" or most powerful callback, as it will be called just before the object is saved to the database (in the case of a 'pre' callback), or just before the object is returned (in the case of a 'post' callback). A callback with priority 0 is the "quietest" callback, as following callbacks can completely overwhelm it. This may be a good choice for your plugin, as you may want your plugin to work well with other plugins. Determining the correct priority is a matter of thinking about your plugin in relation to others, and adjusting the priority based on experience so that users get the best use out of the plugin.

The plugin object is an object of type MT::Plugin which gives some information about the plugin. This is used to include the plugin's name in any error messages.

<callback function> is a code referense for a subroutine that will be called. The arguments to this function vary by operation (see MT::Callback for details), but in each case the first parameter is the MT::Callback object itself:

sub my_callback {
    my ($cb, ...) = @_;
    if ( <error condition> ) {
        return $cb->error("Error message");
    }
}

Strictly speaking, the return value of a callback is ignored. Calling the error() method of the MT::Callback object ($cb in this case) propagates the error message up to the MT activity log.

Another way to handle errors is to call die. If a callback dies, MT will warn the error to the activity log, but will continue processing the MT::Object operation: so other callbacks will still run, and the database operation should still occur.

Global Object Callbacks

If you add a callback to the MT class with a hook point that begins with *::, such as:

MT->add_callback('*::post_save', 7, $my_plugin, \&code_ref);

then it will be called whenever post_save callbacks are called. "Any-class" callbacks are called after all class-specific callbacks. Note that add_callback must be called on the MT class, not on a subclass of MT::Object.

$obj->set_callback_routine()

This method just calls the setcallbackroutine as defined by the MT::ObjectDriver set with the set_driver method.

This page was last updated on 2008-01-16, 12:51.  

3 Notes

Again, complete example of using object callbacks would be very useful here (from registration to example function, etc.) Explaining each of the hook points would be good too. Also, for each type of callback (hook point), a different list of parameters gets passed to the callback function, listing and explaining each of them (with examples) would help.

Also, I notice that you are using the old 3.3-style registration method for these object callbacks? Is there a reason that you didn't use the registry method? Is the method described above the "best practice" for object callbacks? If using the registry method, is it possible to specify priority, and if so, how?

I would also find a complete list of callback methods and some broader examples very useful.

It works fine when I add a postxxx callbacks but I have some problems with the prexxx callbacks. It seems that they are not invoked even the callback functions just try to insert some log messages. Could you please give me some suggestion?

Leave a note

Have a question, please use the MT Forums. Notes sumbitted here should pertain to tips & hints regarding documentation.