Skip to content

DevGuide IntroCallbacks

Violet edited this page Nov 2, 2010 · 2 revisions

MDG: Introduction to Events and Callbacks

Melody exposes to developers a number of different "hooks" during the life-cycle of a request that a developer can attach their code to. In a sense, these hooks give plugins the opportunity to inject code and operations into the core of Melody's application logic. This allows plugins to perform more advanced operations than Melody might otherwise perform on its own, while preventing developers from having to hack Melody's source code directly.

This section will discuss in detail how to listen for these events, how to attach callbacks for those events, and how to trigger events of your own.

What is an event?

For those unfamiliar with the concepts of an event, let's have a brief primer on the concept.

The most basic definition of an event could be, "a occurrence within a system that may be of relevance to applications extending it." The most common form of an event can be found in your own operating system: a mouse click.

When you click your mouse, the operating system "fires" an event. All applications are then notified of that event, and if they are "listening" for it (determined by the application having registered a "listener" or "callback" for it), they will be given the opportunity to take action in response to it. In the meantime they will be given important details about the event (did they double click, where did they click, etc) to facilitate the creation of the desired response.

Events in Melody

As Melody runs it is constantly firing events. Often these events get fired off into the ether because no plugin has registered a callback for it. When a callback has been registered, this is what happens:

  1. Melody encounters a point in its operation where it needs to notify plugins than an event of interest to them occurred.

  2. If multiple callbacks are listening for that event, they are sorted in priority order.

  3. One-by-one, each callback is executed in priority order.

  4. Melody blocks while each callback runs. In other words, Melody does not invoke the next callback, or continue normal operation until the callback being invoked is finished running.

  5. Once all the callbacks are finished running, Melody resumes normal operations until it encounters another points in its operation where it needs to fire an event.

Event Categories

There are type primary different types of events in Melody:

  • Application-level Events
  • Object-level Events

Application-level Events

Application events occur at specific points during the life cycle of the Melody. Application callbacks include those that are fired during publishing, during backup and restore operations, in our Atom and XML-RPC APIs and more.

For a complete listing of Application Callbacks, consult Appendix B: Melody Callbacks Reference.

Object-level Events

Object-level events are automatically associated with every single object type in Melody and are fired just prior to and after that object is modified in the database. For example, all objects expose the following standard subroutines:

  • save
  • load
  • load_iter
  • remove
  • remove_all

Events are fired for each of the above operations just prior and immediately following them being called by a developer. Developers can register callbacks for the following events, which hopefully will correlate logically to their corresponding events:

  • MT::ObjectName::pre_save
  • MT::ObjectName::post_save
  • MT::ObjectName::pre_load
  • MT::ObjectName::post_load
  • MT::ObjectName::pre_remove
  • MT::ObjectName::pre_remove_all
  • MT::ObjectName::post_remove_all

A couple of notes:

  • pre_load and post_load callbacks are invoked for each object when a developer invokes the load_iter method on an object

  • no event is fired for post_remove

You will need to replace "MT::ObjectName" with the package name for the object in question. For example, the pre_save event for the MT::Entry object is: MT::Entry::pre_save.

Note: Developers creating their own object types do not need to create or fire these events. That is handled for you by Melody's data abstraction layer.

Registering Callbacks

To register a callback for an event in Melody, you will need to make changes to your config.yaml. You will need to have on hand two things:

  • the name of the event you are listening for
  • the package name and subroutine name to be invoked when the event occurs

For example, to register a callback for the MT::Entry pre_save event, use the following config.yaml:

name: Example Plugin for Melody
id: Example
description: This plugin is an example plugin for Melody.
version: 1.0
callbacks:
    MT::Entry::pre_save: $Example::Example::Plugin::entry_pre_save

You will then need to add an event handler or callback function to your Plugin.pm file.

Tip: Registering Any-Class Object-level Callbacks

Developers can also register callbacks for all pre_save events by using a wildcard like so:

name: Example Plugin for Melody
id: Example
description: This plugin is an example plugin for Melody.
version: 1.0
callbacks:
    '*::pre_save': $Example::Example::Plugin::entry_pre_save

"Any-class" callbacks are called after all class-specific callbacks.

Event Handlers

Once you have registered a callback in your config.yaml file you will need to implement the callback in your Plugin.pm file.

One very important thing to note is that the inputs into your callback handler will vary greatly depending upon the event being fired. Consult Appendix B: Melody Callbacks Reference for a complete list of events and their callback signatures.

Here is a code sample corresponding to the config.yaml above:

package Example::Plugin;
use strict;
sub pre_save_filter {
    my ($cb, $obj) = @_;
    # $cb - holds a reference to the callback object
    # $obj - holds a reference to the object about to be saved
    #        do your thing
}

Error Handling

Strictly speaking, the result returned by a callback is ignored by Melody, unless of course an error is returned. In which case the error returned is logged in Melody's Activity Log to assist in debugging. Here is a code sample illustrating how to properly return an error:

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

Another way to handle errors is to call the perl function die. If a callback dies, Melody 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.

Creating Your Own Callbacks

In some circumstance a developer may wish to fire off an event of their own so that another part of their application can respond accordingly. To fire an event call run_callbacks on the primary Melody instance. Pass to run_callbacks the name of the event people can register callbacks for, and any additional parameters that will be passed to the callback as arguments.

This is how you would fire an event:

package Example::Plugin;
use strict;

sub do_something {
    # the plugin is doing something
    my $result = MT->run_callbacks('CallbackName', $arg1, $arg2);
    # the plugin keeps doing something
}

And here is the registry entry for this callback:

callbacks:
    Example::Plugin::CallbackName: $Example::Example::Plugin::handler

And finally the event handler itself:

sub handler {
    my ($cb, $arg1, $arg2) = @_;
    # handle the event
}

What an application does in response to an event is completely up to the developer.

Continue Reading

 


Questions, comments, can't find something? Let us know at our community outpost on Get Satisfaction.

Credits

  • Author: Byrne Reese
  • Edited by: Violet Bliss Dietz
Clone this wiki locally