You are here

workflow_admin_ui.module in Workflow 7

Provides administrative UI for workflow. Why it's own module? Lower code footprint and better performance. Additional credit to gcassie ( http://drupal.org/user/80260 ) for the initial push to split UI out of core workflow. We're moving workflow in a API direction, so UI and the like - out.

File

workflow_admin_ui/workflow_admin_ui.module
View source
<?php

/**
 * @file
 * Provides administrative UI for workflow.
 * Why it's own module? Lower code footprint and better performance.
 * Additional credit to gcassie ( http://drupal.org/user/80260 ) for
 * the initial push to split UI out of core workflow.
 * We're moving workflow in a API direction, so UI and the like - out.
 */
define('WORKFLOW_ARROW', '&#8594;');

/**
 * Implements hook_help().
 */
function workflow_admin_ui_help($path, $arg) {
  switch ($path) {
    case 'admin/config/workflow/workflow/edit/%':
      return t('You are currently viewing the possible transitions to and from workflow states. The state is shown in the left column; ' . 'the state to be moved to is to the right. For each transition, check the box next to the role(s) that may initiate the transition. ' . 'For example, if only the "production editor" role may move a node from Review state to the Published state, check the box next to ' . '"production editor". The author role is built in and refers to the user who authored the node.');
    case 'admin/config/workflow/workflow/add':
      return t('To get started, provide a name for your workflow. This name will be used as a label when the workflow status is shown ' . 'during node editing.');
  }
}

/**
 * Implements hook_permission().
 */
function workflow_admin_ui_permission() {
  return array(
    'administer workflow' => array(
      'title' => t('Administer workflow'),
      'description' => t('Administer workflow configurations.'),
    ),
    'participate in workflow' => array(
      'title' => t('Participate in workflow'),
      'description' => t('Role is shown on workflow admin pages.'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function workflow_admin_ui_menu() {
  $items['admin/config/workflow/workflow'] = array(
    'title' => 'Workflow',
    'file' => 'workflow_admin_ui.pages.inc',
    'access arguments' => array(
      'administer workflow',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'workflow_admin_ui_type_map_form',
    ),
    'description' => 'Allows the creation and assignment of arbitrary workflows to node types.',
  );
  $items['admin/config/workflow/workflow/%workflow'] = array(
    'file' => 'workflow_admin_ui.pages.inc',
    'access arguments' => array(
      'administer workflow',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'workflow_admin_ui_overview_form',
      4,
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/workflow/workflow/add'] = array(
    'file' => 'workflow_admin_ui.pages.inc',
    'access arguments' => array(
      'administer workflow',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'workflow_admin_ui_add_form',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/workflow/workflow/edit/%workflow'] = array(
    'title' => 'Edit',
    'file' => 'workflow_admin_ui.pages.inc',
    'access arguments' => array(
      'administer workflow',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'workflow_admin_ui_edit_form',
      5,
    ),
    'type' => MENU_CALLBACK,
  );
  $items["admin/config/workflow/workflow/delete/%workflow"] = array(
    'title' => 'Delete',
    'file' => 'workflow_admin_ui.pages.inc',
    'access arguments' => array(
      'administer workflow',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'workflow_admin_ui_delete_form',
      5,
    ),
    'type' => MENU_CALLBACK,
  );
  $items["admin/config/workflow/workflow/transitions/%workflow"] = array(
    'title' => 'Transitions',
    'file' => 'workflow_admin_ui.pages.inc',
    'access arguments' => array(
      'administer workflow',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'workflow_admin_ui_transitions_form',
      5,
    ),
    'type' => MENU_CALLBACK,
  );
  $items["admin/config/workflow/workflow/perm_summary/%workflow"] = array(
    'title' => 'Permission Summary',
    'file' => 'workflow_admin_ui.pages.inc',
    'access arguments' => array(
      'administer workflow',
    ),
    'page callback' => 'workflow_admin_ui_view_permissions_form',
    'page arguments' => array(
      5,
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_theme().
 */
function workflow_admin_ui_theme() {
  return array(
    'workflow_admin_ui_transitions_form' => array(
      'render element' => 'form',
    ),
    'workflow_admin_ui_edit_form' => array(
      'render element' => 'form',
    ),
    'workflow_admin_ui_type_map_form' => array(
      'render element' => 'form',
    ),
    'workflow_admin_ui_overview_form' => array(
      'render element' => 'form',
    ),
  );
}

/**
 * Implements hook_user_role_insert().
 * Make sure new roles are allowed to participate in workflows by default.
 */
function workflow_admin_ui_user_role_insert($role) {
  user_role_change_permissions($role->rid, array(
    'participate in workflow' => 1,
  ));
}

/**
 * Helper function. Create breadcrumbs.
 *
 * @param $workflow
 *   The workflow object.
 * @param $extra (optional)
 *   The link to the extra item to add to the end of the breadcrumbs.
 * @return
 *   none.
 */
function workflow_admin_ui_breadcrumbs($workflow, $extra = NULL) {
  $bc = array(
    l(t('Home'), '<front>'),
  );
  $bc[] = l(t('Configuration'), 'admin/config');
  $bc[] = l(t('Workflow'), 'admin/config/workflow');
  $bc[] = l(t('Workflow'), 'admin/config/workflow/workflow');
  $bc[] = l($workflow
    ->label(), "admin/config/workflow/workflow/{$workflow->wid}");
  if ($extra) {
    $bc[] = $extra;
  }
  drupal_set_breadcrumb($bc);
}

/**
 * Menu callback. Edit a workflow's properties.
 *
 * @param $wid
 *   The workflow object..
 * @return
 *   HTML form and permissions table.
 */

/**
 * Implements hook_workflow_operations().
 * Might as well eat our own cooking.
 */
function workflow_admin_ui_workflow_operations($op, $workflow = NULL, $state = NULL) {
  switch ($op) {
    case 'top_actions':

      // Build a link to each workflow.
      $alt = t('Add a new workflow');
      $actions = array(
        'add-workflow' => array(
          'title' => t('Add workflow'),
          // @TODO: It might be more sane to go to the "settings" page.
          'href' => 'admin/config/workflow/workflow/add',
          'attributes' => array(
            'alt' => $alt,
            'title' => $alt,
          ),
        ),
      );
      foreach (Workflow::getWorkflows() as $workflow) {
        $name = $workflow
          ->getName();
        $wid = $workflow->wid;
        $alt = t('Work with @wf', array(
          '@wf' => $name,
        ));
        $actions[drupal_html_class($name)] = array(
          'title' => $workflow
            ->label(),
          'href' => "admin/config/workflow/workflow/{$wid}",
          'attributes' => array(
            'alt' => $alt,
            'title' => $alt,
          ),
        );
      }
      return $actions;
    case 'workflow':
      $name = $workflow
        ->getName();
      $wid = $workflow->wid;
      $actions = array(
        'workflow_settings' => array(
          'title' => t('Settings'),
          'href' => "admin/config/workflow/workflow/edit/{$wid}",
          'attributes' => array(
            'alt' => t('Edit the @wf settings', array(
              '@wf' => $name,
            )),
          ),
        ),
        'workflow_transitions' => array(
          'title' => t('Transitions'),
          'href' => "admin/config/workflow/workflow/transitions/{$wid}",
          'attributes' => array(
            'alt' => t('Edit the @wf transitions', array(
              '@wf' => $name,
            )),
          ),
        ),
        'workflow_permission_summary' => array(
          'title' => t('Summary'),
          'href' => "admin/config/workflow/workflow/perm_summary/{$wid}",
          'attributes' => array(
            'alt' => t('See a summary of the @wf transitions', array(
              '@wf' => $name,
            )),
          ),
        ),
        'workflow_overview_delete' => array(
          'title' => t('Delete'),
          'href' => "admin/config/workflow/workflow/delete/{$wid}",
          'attributes' => array(
            'alt' => t('Delete the @wf workflow', array(
              '@wf' => $name,
            )),
          ),
        ),
      );
      foreach ($actions as $name => $link) {
        $actions[$name]['attributes']['title'] = $actions[$name]['attributes']['alt'];
      }
      return $actions;
  }
}

/**
 * Get a list of roles.
 *
 * @return
 *   Array of role names keyed by role ID, including the 'author' role.
 */
function workflow_admin_ui_get_roles() {
  static $roles = NULL;
  if (!$roles) {
    $roles = array(
      'author' => 'author',
    );
    $list = user_roles(FALSE, 'participate in workflow');
    foreach ($list as $rid => $name) {
      $roles[$rid] = check_plain($name);
    }
  }
  return $roles;
}

/**
 * Save mapping of workflow to node type. E.g., the story node type is using the Foo workflow.
 *
 * @param $form_state['values']
 */
function workflow_admin_ui_types_save($form_values) {

  // Empty the table so that types no longer under workflow go away.
  workflow_delete_workflow_type_map_all();
  $node_types = node_type_get_names();
  foreach ($node_types as $type => $name) {
    $data = array(
      'type' => $type,
      'wid' => $form_values[$type]['workflow'],
    );
    workflow_insert_workflow_type_map($data);
    variable_set('workflow_' . $type, array_keys(array_filter($form_values[$type]['placement'])));

    // If this type uses workflow, make sure pre-existing nodes are set
    // to the workflow's creation state.
    if ($form_values[$type]['workflow']) {
      _workflow_node_initialize_nodes($type, $name);
    }
  }
}

/**
 * Initialize all pre-existing nodes of a type to their first state.
 * @todo: adjust _workflow_node_initialize_nodes() to handle Workflow Field.
 *
 * @param $type - node type
 * @param $name - node type name
 */
function _workflow_node_initialize_nodes($type, $name) {

  // Build the select query.
  // We want all published nodes of this type that don't already have a workflow state.
  $query = db_select('node', 'n');
  $query
    ->leftJoin('workflow_node', 'wn', 'wn.nid = n.nid');

  // Add the fields.
  $query
    ->addField('n', 'nid');

  // Add conditions.
  $query
    ->condition('n.type', $type);
  $query
    ->condition('n.status', 1);
  $query
    ->isNull('wn.sid');
  $nids = $query
    ->execute()
    ->fetchCol();
  $how_many = count($nids);
  if ($how_many == 0) {
    return;
  }
  $comment = t('Pre-existing content set to initial state.');

  // Get the initial state for this content type.
  $first_state = db_query("SELECT s.sid " . "FROM {workflow_type_map} m " . "INNER JOIN {workflow_states} s ON s.wid = m.wid " . "WHERE m.type = :type AND s.sysid <> :creation " . "ORDER BY s.weight ASC ", array(
    ':type' => $type,
    ':creation' => WORKFLOW_CREATION,
  ))
    ->fetchField(0);

  // Load them all up.
  $nodes = node_load_multiple($nids);
  foreach ($nodes as $node) {

    // Force it to transition to the first state and get a history record.
    workflow_execute_transition($node, $first_state, $comment, TRUE);
  }
  return;
  drupal_set_message(t('!count @type nodes have been initialized.', array(
    '@type' => $name,
    '!count' => $how_many,
  )));
}

/**
 * Update the transitions for a workflow.
 *
 * @param array $transitions from values.
 *   Transitions, for example:
 *     18 => array(
 *       20 => array(
 *         'author' => 1,
 *         1        => 0,
 *         2        => 1,
 *       )
 *     )
 *   means the transition from state 18 to state 20 can be executed by
 *   the node author or a user in role 2. The $transitions array should
 *   contain ALL transitions for the workflow.
 */
function _workflow_admin_ui_update_configured_transitions($transitions = array()) {

  // Empty string is sometimes passed in instead of an array.
  if (!$transitions) {
    return;
  }
  foreach ($transitions as $from => $to_data) {
    foreach ($to_data as $to => $role_data) {
      foreach ($role_data as $role => $can_do) {
        if ($can_do) {
          $transition = array(
            'sid' => $from,
            'target_sid' => $to,
            'roles' => $role,
          );
          workflow_update_workflow_transitions($transition);
        }
        else {
          $roles = array();
          if ($transition = workflow_get_workflow_transitions_by_sid_target_sid($from, $to)) {
            $roles = explode(',', $transition->roles);
            $tid = $transition->tid;
            if (($i = array_search($role, $roles)) !== FALSE) {
              unset($roles[$i]);
              workflow_update_workflow_transitions_roles($tid, $roles);
            }
          }
        }
      }
    }
  }
  workflow_delete_workflow_transitions_by_roles('');
}

Functions

Namesort descending Description
workflow_admin_ui_breadcrumbs Helper function. Create breadcrumbs.
workflow_admin_ui_get_roles Get a list of roles.
workflow_admin_ui_help Implements hook_help().
workflow_admin_ui_menu Implements hook_menu().
workflow_admin_ui_permission Implements hook_permission().
workflow_admin_ui_theme Implements hook_theme().
workflow_admin_ui_types_save Save mapping of workflow to node type. E.g., the story node type is using the Foo workflow.
workflow_admin_ui_user_role_insert Implements hook_user_role_insert(). Make sure new roles are allowed to participate in workflows by default.
workflow_admin_ui_workflow_operations Implements hook_workflow_operations(). Might as well eat our own cooking.
_workflow_admin_ui_update_configured_transitions Update the transitions for a workflow.
_workflow_node_initialize_nodes Initialize all pre-existing nodes of a type to their first state. @todo: adjust _workflow_node_initialize_nodes() to handle Workflow Field.

Constants

Namesort descending Description
WORKFLOW_ARROW @file Provides administrative UI for workflow. Why it's own module? Lower code footprint and better performance. Additional credit to gcassie ( http://drupal.org/user/80260 ) for the initial push to split UI out of core workflow. We're…