2. Adding new events
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.
