You are here

state_flow.module in State Machine 6

A base implementation of the state machine class and its relationship to revisions

File

modules/state_flow/state_flow.module
View source
<?php

/**
 * @file
 * A base implementation of the state machine class and its relationship to revisions
 */

/**
 * Implementation of hook_menu().
 *
 */
function state_flow_menu() {
  $items = array();
  $items['node/%node/events'] = array(
    'title' => 'Events',
    'description' => 'The available events',
    'type' => MENU_LOCAL_TASK,
    'page callback' => 'state_flow_events',
    'page arguments' => array(
      1,
    ),
    'access callback' => TRUE,
    'weight' => 10,
  );
  return $items;
}

/**
 * Implementation of hook_menu_alter
 * Change the edit link so the most recent revision is always edited
 *
 * @param array $items
 */
function state_flow_menu_alter(&$items) {
  $items['node/%node/edit']['page callback'] = 'state_flow_node_page_edit';
}

/**
 * Implementation of hook_theme()
 *
 * @return array
 */
function state_flow_theme() {
  return array(
    'state_flow_states' => array(
      'arguments' => array(
        'states' => NULL,
      ),
    ),
  );
}

/**
 * Theme function to show states of a node
 *
 * @param array $states
 * @return string
 */
function theme_state_flow_states($states) {
  $header = array(
    t('Vid'),
    t('Nid'),
    t('State'),
    t('Timestamp'),
  );
  $rows = array();
  foreach ($states as $state) {
    $rows[] = array(
      $state->vid,
      $state->nid,
      $state->state,
      $state->timestamp,
    );
  }
  return theme('table', $header, $rows);
}

/**
 * Show the states as a node tab
 *
 * @param object $node
 * @return array
 */
function state_flow_events($node) {
  $states = state_flow_get_history($node->nid);
  $state_flow = state_flow_load_state_machine($node);
  drupal_set_title('Events');
  $events = $state_flow
    ->get_available_events();
  $output = !empty($events) ? drupal_get_form('state_flow_events_form', $state_flow) : t('No events to fire');
  $output .= theme('state_flow_states', $states);
  return $output;
}

/**
 * Retrieve the states history for a node.
 *
 * @param int $nid
 * @return array
 */
function state_flow_get_history($nid) {
  $query = "SELECT * FROM {node_revision_states} WHERE nid = %d AND status = 1";
  $result = db_query($query, $nid);
  $history = array();
  while ($record = db_fetch_object($result)) {
    $history[] = $record;
  }
  return $history;
}

/**
 * Custom form to show the events that are available
 *
 * @param array $form_state
 * @param object $node
 * @return array
 */
function state_flow_events_form(&$form_state, $state_flow) {
  $form = array();
  $events = $state_flow
    ->get_available_events();
  $form['events'] = array(
    '#type' => 'radios',
    '#title' => t('Fire event'),
    '#options' => drupal_map_assoc($events),
  );
  $form['state_flow'] = array(
    '#type' => 'value',
    '#value' => $state_flow,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Update'),
  );
  return $form;
}

/**
 * Implementation of hook_form_submit
 *
 * @param array $form
 * @param array $form_state
 */
function state_flow_events_form_submit($form, &$form_state) {
  $event = $form_state['values']['events'];
  $state_flow = $form_state['values']['state_flow'];
  $state_flow
    ->fire_event($event);
  $state = $state_flow
    ->get_current_state();
  drupal_set_message(t('Node transitioned to @state state.', array(
    '@state' => $state,
  )));
}

/**
 * Load the state_flow state_machine for the given node.
 */
function state_flow_load_state_machine($node) {
  static $object = array();
  if (!isset($object[$node->vid])) {
    ctools_include('plugins');
    $machine_type = variable_get('state_flow_' . $node->type, 'state_flow');
    $plugin = ctools_get_plugins('state_flow', 'plugins', $machine_type);
    if (!empty($plugin)) {
      $class = ctools_plugin_get_class($plugin, 'handler');
      $object[$node->vid] = new $class($node);
    }
  }
  return $object[$node->vid];
}

/**
 * Implementation of hook_ctools_plugin_plugins().
 */
function state_flow_ctools_plugin_plugins() {
  return array(
    'cache' => TRUE,
    'use hooks' => TRUE,
  );
}

/**
 * Implementation of hook_state_flow_plugins().
 */
function state_flow_state_flow_plugins() {
  $info = array();
  $path = drupal_get_path('module', 'state_flow') . '/plugins';
  $info['state_flow'] = array(
    'handler' => array(
      'class' => 'StateFlow',
      'file' => 'state_flow.inc',
      'path' => $path,
    ),
  );
  return $info;
}

/**
 * Implementation of hook_nodeapi().
 */
function state_flow_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {

  // Use Drupal 7 style node hooks.
  switch ($op) {
    case 'delete revision':
      $node_hook = 'state_flow_node_revision_delete';
      break;
    default:
      $node_hook = 'state_flow_node_' . $op;
      break;
  }
  if (function_exists($node_hook)) {
    return $node_hook($node, $a3, $a4);
  }
}

/**
 * Implementation of hook_node_presave()
 *
 * @param object $node
 */
function state_flow_node_presave(&$node) {
  $state_flow = state_flow_load_state_machine($node);
  $state = $state_flow
    ->get_current_state();
  if ($state == 'published') {

    //force revision
    $node->revision = TRUE;
  }
}

/**
 * Implementation of hook_node_insert().
 */
function state_flow_node_insert(&$node) {
  $state_flow = state_flow_load_state_machine($node);
  $state_flow
    ->persist();
}

/**
 * Implementation of hook_node_update().
 */
function state_flow_node_update(&$node) {
  $state_flow = state_flow_load_state_machine($node);
  $state_flow
    ->persist();
  state_flow_prevent_live_revision($node->nid);
}

/**
 * Implementation of hook_node_delete().
 */
function state_flow_node_delete(&$node) {
  db_query('DELETE FROM {node_revision_states} WHERE nid = %d', $node->nid);
}

/**
 * Implementation of hook_node_revision_delete().
 */
function state_flow_node_revision_delete(&$node) {
  db_query('DELETE FROM {node_revision_states} WHERE vid = %d', $node->vid);
}

/**
 * Helper function to to load the lastest revision on node edit
 *
 * @param object $node
 */
function state_flow_node_page_edit($node) {
  $state_flow = state_flow_load_state_machine($node);
  $vid = $state_flow
    ->get_latest_revision($node->nid);

  //Load the latest revision if it doesn't match what is part of the node
  if ($node->vid != $vid) {
    $node = node_load($node->nid, $vid);
  }
  return node_page_edit($node);
}
function state_flow_prevent_live_revision($nid) {
  $revision_state = state_flow_live_revision($nid);
  if ($revision_state != NULL) {
    $live_version = state_flow_revision_info($revision_state['vid']);
    db_query("UPDATE {node} SET vid = %d, changed = '%s', title = '%s', status = 1 WHERE nid = %d", $live_version->vid, $live_version->timestamp, $live_version->title, $nid);
  }
}
function state_flow_live_revision($nid) {
  $state = 'published';
  $query = "SELECT *\n            FROM {node_revision_states}\n            WHERE nid = %d AND state = '%s'\n            ORDER BY timestamp\n            DESC\n            LIMIT 1";
  $revision_state = db_fetch_array(db_query($query, $nid, $state));
  return $revision_state;
}
function state_flow_revision_info($vid) {
  $result = db_query('SELECT * FROM {node_revisions} WHERE vid = %d', $vid);
  return db_fetch_object($result);
}

Functions

Namesort descending Description
state_flow_ctools_plugin_plugins Implementation of hook_ctools_plugin_plugins().
state_flow_events Show the states as a node tab
state_flow_events_form Custom form to show the events that are available
state_flow_events_form_submit Implementation of hook_form_submit
state_flow_get_history Retrieve the states history for a node.
state_flow_live_revision
state_flow_load_state_machine Load the state_flow state_machine for the given node.
state_flow_menu Implementation of hook_menu().
state_flow_menu_alter Implementation of hook_menu_alter Change the edit link so the most recent revision is always edited
state_flow_nodeapi Implementation of hook_nodeapi().
state_flow_node_delete Implementation of hook_node_delete().
state_flow_node_insert Implementation of hook_node_insert().
state_flow_node_page_edit Helper function to to load the lastest revision on node edit
state_flow_node_presave Implementation of hook_node_presave()
state_flow_node_revision_delete Implementation of hook_node_revision_delete().
state_flow_node_update Implementation of hook_node_update().
state_flow_prevent_live_revision
state_flow_revision_info
state_flow_state_flow_plugins Implementation of hook_state_flow_plugins().
state_flow_theme Implementation of hook_theme()
theme_state_flow_states Theme function to show states of a node