May 2nd, 2008

Workflow-ng is godly or flagging a dead content

As many people know, I’m really into workflow-ng.

I’ve integrated a few modules with it, and it allows for a killer amount of functionality and good (although probably complex) administrative interfaces for admins to do their own customization.

Simply put: this is my favorite module after CCK, Views and Panels, and it should be yours too..

More after the jump

I want others to embrace this fantastic module, so I thought I’d share one of my recent integrations:

Flag Content

Unfortunately, I did this for the witness project (hub.witness.org) which uses a heavily customized version of flag_content to allow for jquery forms and some additional info on the flag. If I have time to contribute this back against a clean version, I’ll give it a go. (Please comment here if that is interesting to you! It inspires me to do it).

Even so, here is the code. To get started, it’s easiest to be lazy, so I cut and paste mainly from the comment workflow-ng mod and the user one. I recommend this when you are getting started. I’m going to walk through the steps to create your own configuration:



/**
 * Implementation of hook_event_info()
 */
function flag_content_event_info() {
  return array(
    'node_flagged' => array(
      '#label' => t('node has been flagged'),
      '#module' => t('Flag Content'),
      '#arguments' => workflow_ng_events_hook_flag_arguments(),
      '#redirect' => TRUE,
    ),

    /*** @TODO: Not yet implemented
      'flag_update' => array(
      '#label' => t('flag has been updated'),
      '#module' => t('flag'),
      '#arguments' => workflow_ng_events_hook_flag_arguments('updated flag'),
      '#redirect' => TRUE,
    ),
    'flag_delete' => array(
      '#label' => t('flag has been deleted'),
      '#module' => t('flag'),
      '#arguments' => workflow_ng_events_hook_flag_arguments('deleted flag'),
      '#redirect' => TRUE,
    ),*/
  );
}


Not that hard, this just let’s workflow-ng know that we are exposing an event, the event is called “node has been flagged” and its system name is node_flagged.

An event in workflow-ng is just something that can happen. Examples of other events are “node has been updated, comment has been added, node has been published, user has been created, etc”

The important part to recognize here is that Events have arguments. Think of events like a function call. You’re saying, when this thing happens, call the event “node_flagged” and pass in the arguments from ‘#arguments’ => workflow_ng_events_hook_flag_arguments(’Flagged content’).


/*
 * Returns some arguments suitable for hook flag
 */
function workflow_ng_events_hook_flag_arguments() {
  return array(
    'flag' => array('#entity' => 'flag', '#label' => t("Flag")),
    'flag_author' => array('#entity' => 'user', '#label' => t("User creating Flag")),
    'node' => array('#entity' => 'node', '#label' => t('Flaged content')),
    'node_author' => array('#entity' => 'user', '#label' => t('Flaged content author'), '#handler' => 'workflow_ng_events_argument_flag_node_author'),
  ) + workflow_ng_events_global_user_argument();
}


Okay, not too scary, this is a list of arguments. Let’s just go through them:


 'flag' => array('#entity' => 'flag', '#label' => t("Flag")),

This is a custom entity corresponding to a “flag”, that is an entry in the flag_content table


'flag_author' => array('#entity' => 'user', '#label' => t("User creating Flag")),
    'node' => array('#entity' => 'node', '#label' => t('Flaged content')),
    'node_author' => array('#entity' => 'user', '#label' => t('Flaged content author'), '#handler' => 'workflow_ng_events_argument_flag_node_author'),


These are entities you know and love/hate. Old friends like node and user.

Workflow NG knows what these entities are, the fields they contain, and the actions they can perform, you just have to provide the data at the right time - we’re getting to that.



/*
 * Implementation of hook_flag_content
 */
function flag_content_flag_content($type,$fid,$entity,$user,$flag_option,$time) {

  $flag = new stdClass();
  $flag->fid = $fid;
  $flag->flag_option = $flag_option;
  $flag->time_flagged = $time;
  switch ($type) {
      case FLAG_CONTENT_TYPE_NODE :
        workflow_ng_invoke_event('node_flagged', $flag, $user, $entity);
        break;
      case FLAG_CONTENT_TYPE_USER :
        break;
      case FLAG_CONTENT_TYPE_COMMENT :
        break;
    }
}


Events need to be invoked. Workflow-ng doesn’t magically know when they happen. So as part of our hackery of flag_content, we added a simple module_invoke_all, so that when content is flagged, other mods get a chance to do something. here is an implementation of the hook, in the module itself.

Basically, I’m just saying, if you are flagging a node, run this:

workflow_ng_invoke_event('node_flagged', $flag, $user, $entity);

Okay, so remember our arguments above? They are mapped in order, so the first argument was the “flag”, which as you can see, we built above the invocation. The second argument is the user who did the flagging (known as flag_author), and the third argument is the node which was flagged.

BUT WAIT! you specified a 4th arg!!! The “node_author” the person being accused of flaggy content production! They must be notified of the charge against them!

For that, I chose to use a handler (in part for demonstration, but it also has performance benefits. Let’s see how that works



 'node_author' => array('#entity' => 'user', '#label' => t('Flaged content author'), '#handler' => 'workflow_ng_events_argument_flag_node_author'),


Remember this from the arguments section above? The handler is workflow_ng_events_argument_flag_node_author. What this means is that this argument is not being passed in directly by workflow_ng_invoke_event, but will be generated only if the argument is used in the workflow_ng configuration. This saves us a few precious cycles. See how the handler is written below:



/*
 * Gets the flag's node's author
 */
function workflow_ng_events_argument_flag_node_author($flag,$node,$user) {
  return user_load(array('uid' => $node->uid));
}

That’s pretty obvious right? It takes the arguments in the same order they are passed to the invocation. We just get the node’s author and return it

Come back next week, when I get off my ass and make a nice screen cast of this module in action!

One Response to “Workflow-ng is godly or flagging a dead content”

  1. Adrian Russell-Falla says:

    +1 for your cleaned-up contribution plea count!

    this is very cool, and would clearly be extremely useful in many projects.

    best,

    Adrian Russell-Falla

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

How To find me

Telephone: +1 510.277.0891 | Email: jacobsingh at gmail daht calm

Solution Graphics