2. Adding new events

Last modified: June 20, 2009 - 20:52

Modules may add further events, on which actions and conditions may be configured by either the UI or modules.

To do so, you need to implement hook_event_info().
Let's have a look at a example. Consider the buddylist module supports workflow-ng. It could introduce a new event: "User1 adds user2 to his buddylist".

<?php
/*
* Implementation of hook_event_info()
*/
function yourmodule_event_info() {
  return array(
   
'buddy_add' => array(
     
'#label' => t('UserA adds userB to his buddylist'),
     
'#module' => t('Buddylist'),
     
'#arguments' => array(
       
'userA' => array('#entity' => 'user', '#label' => t('UserA, which adds userB.')),
       
'userB' => array('#entity' => 'user', '#label' => t('UserB, which is added to UserA\'s list.')),
      ),
     
'#redirect' => TRUE,
    ),
  );
}
?>

So 'buddy_add' is the machine readable event name.

Then, the module could invoke the event, when it occurs, by calling:

<?php
  workflow_ng_invoke_event
('buddy_add', $userA, $userB);
?>

That's it. Have a look at the event info reference for more details on the available properties.

Another example with dynamic loaded arguments

It's possible to specify further arguments, which are not yet available, but could be loaded with some extra code.
Consider workflow-ng's event "Comment has been updated". It would be useful to have the associated content node as argument, but loading the node regardless if it is used would be overhead. So it's possible to specify a #handler, which is used by workflow-ng to load the argument as soon as it is needed.

<?php
/*
* Implementation of hook_event_info()
*/
function yourmodule_event_info() {
  return array(
   
'comment_update' => array(
     
'#label' => t('Comment has been updated'),
     
'#module' => t('Comment'),
     
'#arguments' => workflow_ng_events_hook_comment_arguments('updated comment'),
    ),
   
'comment_insert' => ...
  );
}

/*
* Returns some arguments suitable for hook comment
*/
function workflow_ng_events_hook_comment_arguments($comment_label) {
  return array(
   
'comment' => array('#entity' => 'comment', '#label' => t($comment_label)),
   
'comment_author' => array('#entity' => 'user', '#label' => t("$comment_label author"), '#handler' => 'workflow_ng_events_argument_comment_author'),
   
'node' => array('#entity' => 'node', '#label' => t('commented content'), '#handler' => 'workflow_ng_events_argument_comment_node'),
   
'node_author' => array('#entity' => 'user', '#label' => t('commented content author'), '#handler' => 'workflow_ng_events_argument_comment_node_author'),
   
'user' => array('#entity' => 'user', '#label' => t('acting user'), '#handler' => 'workflow_ng_events_argument_global_user'),
  );
}

/*
* Gets the author of the comment
*/
function workflow_ng_events_argument_comment_author($comment) {
  global
$user;
  return
$user->uid != $comment->uid ? user_load(array('uid' => $comment->uid)) : drupal_clone($user);
}

/*
* Gets the comment's node
*/
function workflow_ng_events_argument_comment_node($comment) {
  return
node_load($comment->nid);
}

/*
* Gets the comment's node's author
*/
function workflow_ng_events_argument_comment_node_author($comment) {
  return
workflow_ng_events_argument_node_author(workflow_ng_events_argument_comment_node($comment));
}

/*
* Implementation of hook_comment
*/
function workflow_ng_comment($comment, $op) {
  if (
in_array($op, array('insert', 'update', 'delete'))) {
    if (
is_array($comment)) {
     
$comment = (object)$comment;
    }
   
workflow_ng_invoke_event('comment_'. $op, $comment);
  }
}
?>

So if one configures an action or a condition, which makes use of the content node, workflow-ng calls workflow_ng_events_argument_comment_node($comment) to load the node. Note that workflow-ng will pass all already available arguments to the handler.

Passing arguments by reference

Sometimes it's useful to pass arguments by reference, so that changes made by actions also apply to the entity of the calling code. To make this possible, workflow-ng supports passing arguments to workflow-ng in a array.

So the above example

<?php
  workflow_ng_invoke_event
('buddy_add', $userA, $userB);
?>

could be also written as

<?php
  workflow_ng_invoke_event
('buddy_add', array('userA' => $userA, 'userB' => $userB));
?>

Both versions are equal.
Now, if we want to pass entities by reference we just have to add the & in front of the variable:

<?php
  workflow_ng_invoke_event
('buddy_add', array('userA' => $userA, 'userB' => &$userB));
?>

In this example userB is passed by reference.

Although objects are always passed by reference in php5 be sure to use this method, so that the entity is also passed by reference for php4 users. Furthermore this can also be used for passing Arrays by reference.

Jacob Singh has done a nice blog post, which shows how to add events with workflow-ng.

 
 

Drupal is a registered trademark of Dries Buytaert.