You are here

workflow_admin_ui.pages.inc 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.pages.inc
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.
 */

/**
 * Form builder. Create the form for adding/editing a workflow.
 *
 * @param $name
 *   Name of the workflow if editing.
 * @param $add
 *   Boolean, if true edit workflow name.
 *
 * @return
 *   HTML form.
 */
function workflow_admin_ui_add_form($form, &$form_state, $name = NULL) {
  $form = array();
  $form['wf_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Workflow Name'),
    '#maxlength' => '254',
    '#required' => TRUE,
    '#default_value' => $name,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Add Workflow'),
  );
  return $form;
}

/**
 * Validate the workflow add form.
 *
 * @see workflow_add_form()
 */
function workflow_admin_ui_add_form_validate($form, &$form_state) {
  $name = $form_state['values']['wf_name'];

  // Make sure workflow name is not a duplicate.
  foreach (Workflow::getWorkflows() as $workflow) {
    if ($name == check_plain($workflow
      ->getName())) {
      form_set_error('wf_name', t('A workflow with the name %name already exists. Please enter another name for your new workflow.', array(
        '%name' => $name,
      )));
      break;
    }
  }
}

/**
 * Submit handler for the workflow add form.
 *
 * @see workflow_add_form()
 */
function workflow_admin_ui_add_form_submit($form, &$form_state) {
  $name = $form_state['values']['wf_name'];
  $workflow = Workflow::create($name);
  $workflow
    ->save();
  $args = array(
    '%name' => $name,
  );
  watchdog('workflow', 'Created workflow %name', $args);
  drupal_set_message(t('The workflow %name was created. You should set the options for your workflow.', $args), 'status');

  // The workflow ID is now generated upon save().
  $wid = $workflow->wid;
  $form_state['redirect'] = 'admin/config/workflow/workflow/' . $wid;
}

/**
 * Form builder. Create form for confirmation of workflow deletion.
 *
 * @param $wid
 *   The workflow object to delete.
 * @return
 *   Form definition array.
 *
 */
function workflow_admin_ui_delete_form($form, &$form_state, $workflow) {

  // If we don't have a workflow that goes with this, return to the admin page.
  if (!$workflow) {
    drupal_goto('admin/config/workflow/workflow');
  }
  else {

    // Let's add some breadcrumbs.
    workflow_admin_ui_breadcrumbs($workflow);
    $form = array();
    $form['workflow'] = array(
      '#type' => 'value',
      '#value' => $workflow,
    );
    return confirm_form($form, t('Are you sure you want to delete %title? All nodes and fields that have a workflow state associated with this workflow will ' . 'have those workflow states removed.', array(
      '%title' => $workflow
        ->getName(),
    )), !empty($_GET['destination']) ? $_GET['destination'] : 'admin/config/workflow/workflow', t('This action cannot be undone.'), t('Delete ' . $workflow
      ->getName()), t('Cancel'));
  }
}

/**
 * Submit handler for workflow deletion form.
 *
 * @see workflow_delete_form()
 */
function workflow_admin_ui_delete_form_submit($form, &$form_state) {
  $workflow = $form_state['values']['workflow'];
  if ($form_state['values']['confirm'] == 1 && ($workflow = Workflow::load($workflow->wid))) {
    $name = $workflow
      ->getName();
    $message = 'The workflow %name with all its states was deleted.';
    $workflow
      ->delete();
    watchdog('workflow', $message, array(
      '%name' => $name,
    ));
    drupal_set_message(t($message, array(
      '%name' => $name,
    )));
    $form_state['redirect'] = 'admin/config/workflow/workflow';
  }
}

/**
 * View workflow permissions by role
 *
 * @param $workflow
 *   The workflow object.
 */
function workflow_admin_ui_view_permissions_form($workflow) {

  // If we don't have a workflow at this point, go back to admin page.
  if ($workflow) {

    // Let's add some breadcrumbs.
    workflow_admin_ui_breadcrumbs($workflow);
    $name = $workflow
      ->getName();
    $all = array();
    $roles = workflow_admin_ui_get_roles();
    foreach ($roles as $role => $value) {
      $all[$role]['name'] = $value;
    }

    // TODO return to this, this looks similar to actions stuff (transitions) - should be it's own function.
    $result = db_query('SELECT t.roles, s1.state AS state_name, s2.state AS target_state_name ' . 'FROM {workflow_transitions} t ' . 'INNER JOIN {workflow_states} s1 ON s1.sid = t.sid ' . 'INNER JOIN {workflow_states} s2 ON s2.sid = t.target_sid ' . 'WHERE s1.wid = :wid ' . 'ORDER BY s1.weight ASC , s1.state ASC , s2.weight ASC , s2.state ASC', array(
      ':wid' => $workflow->wid,
    ));
    foreach ($result as $data) {
      foreach (explode(',', $data->roles) as $role) {
        $all[$role]['transitions'][] = array(
          check_plain(t($data->state_name)),
          WORKFLOW_ARROW,
          check_plain(t($data->target_state_name)),
        );
      }
    }
    $header = array(
      t('From'),
      '',
      t('To'),
    );
    $output = '';

    // TODO we should theme out the html here.
    foreach ($all as $role => $value) {
      if (!empty($value['name'])) {
        $output .= '<h3>' . t('%role may do these transitions:', array(
          '%role' => $value['name'],
        )) . '</h3>';
      }
      if (!empty($value['transitions'])) {
        $output .= theme('table', array(
          'header' => $header,
          'rows' => $value['transitions'],
        )) . '<p></p>';
      }
      else {
        $output .= '<table><tbody><tr class="odd"><td>' . t('None') . '</td><td></tr></tbody></table><p></p>';
      }
    }
    return $output;
  }
  else {
    drupal_goto('admin/config/workflow/workflow');
  }
}

/**
 * Theme the workflow permissions view.
 */
function theme_workflow_admin_ui_view_permissions_form($variables) {
  $header = $variables['header'];
  $all = $variables['all'];
  $output = '';
  foreach ($all as $role => $value) {
    if (!empty($value['name'])) {
      $output .= '<h3>' . t('%role may do these transitions:', array(
        '%role' => $value['name'],
      )) . '</h3>';
    }
    if (!empty($value['transitions'])) {
      $output .= theme('table', array(
        'header' => $header,
        'rows' => $value['transitions'],
      )) . '<p></p>';
    }
    else {
      $output .= '<table><tbody><tr class="odd"><td>' . t('None') . '</td><td></tr></tbody></table><p></p>';
    }
  }
  return $output;
}

/**
 * Menu callback. Edit a workflow's properties.
 *
 * @param $wid
 *   The workflow object.
 * @return
 *   HTML form and permissions table.
 */
function workflow_admin_ui_edit_form($form, $form_state, $workflow = NULL) {
  $noyes = array(
    t('No'),
    t('Yes'),
  );

  // If we don't have a workflow by this point, we need to go back
  // to creating one at admin/config/workflow/workflow/add
  // I think the menu loader won't allow this to happen.
  if (!$workflow) {
    drupal_goto('admin/config/workflow/workflow/add');
  }
  else {

    // Let's add some breadcrumbs.
    workflow_admin_ui_breadcrumbs($workflow);
    $form = array();
    $form['workflow'] = array(
      '#type' => 'value',
      '#value' => $workflow,
    );
    $form['basic'] = array(
      '#type' => 'fieldset',
      '#title' => t('Workflow information'),
    );
    $form['basic']['wf_name'] = array(
      '#type' => 'textfield',
      '#default_value' => $workflow
        ->getName(),
      '#title' => t('Workflow Name'),
      '#maxlength' => '254',
      '#required' => TRUE,
    );
    $form['basic']['name_as_title'] = array(
      '#type' => 'radios',
      '#options' => $noyes,
      '#attributes' => array(
        'class' => array(
          'container-inline',
        ),
      ),
      '#title' => t('Use the workflow name as the title of the workflow form?'),
      '#default_value' => isset($workflow->options['name_as_title']) ? $workflow->options['name_as_title'] : 0,
      '#description' => t('The workflow section of the editing form is in its own fieldset. Checking the box will add the workflow ' . 'name as the title of workflow section of the editing form.'),
    );
    $form['schedule'] = array(
      '#type' => 'fieldset',
      '#title' => t('Scheduling for Workflow'),
    );
    $form['schedule']['schedule'] = array(
      '#type' => 'radios',
      '#options' => $noyes,
      '#attributes' => array(
        'class' => array(
          'container-inline',
        ),
      ),
      '#title' => t('Allow scheduling of workflow transitions?'),
      '#default_value' => isset($workflow->options['schedule']) ? $workflow->options['schedule'] : 1,
      '#description' => t('Workflow transitions may be scheduled to a moment in the future. ' . 'Soon after the desired moment, the transition is executed by Cron.'),
    );
    $form['schedule']['schedule_timezone'] = array(
      '#type' => 'radios',
      '#options' => $noyes,
      '#attributes' => array(
        'class' => array(
          'container-inline',
        ),
      ),
      '#title' => t('Show a timezone when scheduling a transition?'),
      '#default_value' => isset($workflow->options['schedule_timezone']) ? $workflow->options['schedule_timezone'] : 1,
    );
    $form['comment'] = array(
      '#type' => 'fieldset',
      '#title' => t('Comment for Workflow Log'),
    );
    $form['comment']['comment_log_node'] = array(
      '#type' => 'radios',
      '#options' => $noyes,
      '#attributes' => array(
        'class' => array(
          'container-inline',
        ),
      ),
      '#title' => t('Show a comment field in the workflow section of the editing form?'),
      '#default_value' => isset($workflow->options['comment_log_node']) ? $workflow->options['comment_log_node'] : 0,
      '#description' => t('On the node editing form, a Comment form can be shown so that the person making the state change can record ' . 'reasons for doing so. The comment is then included in the node\'s workflow history.'),
    );
    $form['comment']['comment_log_tab'] = array(
      '#type' => 'radios',
      '#options' => $noyes,
      '#attributes' => array(
        'class' => array(
          'container-inline',
        ),
      ),
      '#title' => t('Show a comment field in the workflow section of the workflow tab form?'),
      '#default_value' => isset($workflow->options['comment_log_tab']) ? $workflow->options['comment_log_tab'] : 0,
      '#description' => t('On the workflow tab, a Comment form can be shown so that the person making the state change can record ' . 'reasons for doing so. The comment is then included in the node\'s workflow history.'),
    );
    $form['watchdog'] = array(
      '#type' => 'fieldset',
      '#title' => t('Watchdog Logging for Workflow'),
    );
    $form['watchdog']['watchdog_log'] = array(
      '#type' => 'radios',
      '#options' => $noyes,
      '#attributes' => array(
        'class' => array(
          'container-inline',
        ),
      ),
      '#title' => t('Log informational watchdog messages when a transition is executed (state of a node is changed)?'),
      '#default_value' => isset($workflow->options['watchdog_log']) ? $workflow->options['watchdog_log'] : 0,
      '#description' => t('Optionally log transition state changes to watchdog.'),
    );
    $form['tab'] = array(
      '#type' => 'fieldset',
      '#title' => t('Workflow tab permissions'),
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
    );
    $form['tab']['tab_roles'] = array(
      '#type' => 'checkboxes',
      '#options' => workflow_admin_ui_get_roles(),
      '#default_value' => explode(',', $workflow->tab_roles),
      '#description' => t('Select any roles that should have access to the workflow tab on nodes that have a workflow.'),
    );
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Save configuration'),
    );
    return $form;
  }
}

/**
 * Theme the workflow editing form.
 *
 * @see workflow_edit_form()
 */
function theme_workflow_admin_ui_edit_form($variables) {
  $output = '';
  $form = $variables['form'];
  $workflow = $variables['form']['workflow']['#value'];

  // If we don't have a workflow here, we need to go back to admin.
  if ($workflow) {
    drupal_set_title(t('Edit workflow %name', array(
      '%name' => $workflow
        ->getName(),
    )), PASS_THROUGH);
    $output .= drupal_render_children($form);
    return $output;
  }
  else {
    drupal_goto('admin/config/workflow/workflow');
  }
}

/**
 * Validate the workflow editing form.
 *
 * @see workflow_edit_form()
 * @todo: this duplicates code from workflow_admin_ui_add_form_validate()
 */
function workflow_admin_ui_edit_form_validate($form_id, $form_state) {
  $workflow = $form_state['values']['workflow'];
  $name = $form_state['values']['wf_name'];

  // Make sure workflow name is not a duplicate.
  foreach (Workflow::getWorkflows() as $stored_workflow) {
    if ($name == check_plain($stored_workflow
      ->getName()) && $workflow->wid != $stored_workflow->wid) {
      form_set_error('wf_name', t('A workflow with the name %name already exists. Please enter another name for this workflow.', array(
        '%name' => $name,
      )));
      break;
    }
  }
}

/**
 * Submit handler for the workflow editing form.
 *
 * @see workflow_edit_form()
 * @todo: this is only valid for Node API, not for Field API.
 *        Field API has 'Field settings'.
 */
function workflow_admin_ui_edit_form_submit($form, &$form_state) {
  if (isset($form_state['values']['transitions'])) {
    _workflow_admin_ui_update_configured_transitions($form_state['values']['transitions']);
  }
  $workflow = $form_state['values']['workflow'];
  $workflow->name = $form_state['values']['wf_name'];
  $workflow->tab_roles = array_filter($form_state['values']['tab_roles']);
  $workflow->options = array(
    'name_as_title' => $form_state['values']['name_as_title'],
    'schedule' => $form_state['values']['schedule'],
    'schedule_timezone' => $form_state['values']['schedule_timezone'],
    'comment_log_node' => $form_state['values']['comment_log_node'],
    'comment_log_tab' => $form_state['values']['comment_log_tab'],
    'watchdog_log' => $form_state['values']['watchdog_log'],
  );
  $workflow
    ->save();
  drupal_set_message(t('The workflow was updated.'));
  $form_state['redirect'] = 'admin/config/workflow/workflow/' . $workflow->wid;
}

/**
 * Menu callback. Edit a workflow's transitions.
 *
 * @param $wid
 *   The workflow object.
 * @return
 *   HTML form and permissions table.
 */
function workflow_admin_ui_transitions_form($form, $form_state, $workflow) {

  // Make sure we have a workflow.
  if ($workflow) {

    // Let's add some breadcrumbs.
    workflow_admin_ui_breadcrumbs($workflow);
    $form = array();
    $form['workflow'] = array(
      '#type' => 'value',
      '#value' => $workflow,
    );
    $form['transitions'] = _workflow_admin_ui_transition_grid_form($workflow);
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Save configuration'),
    );
    return $form;
  }
}

/**
 * Validate the workflow editing form.
 *
 * @see workflow_edit_form()
 */
function workflow_admin_ui_transitions_form_validate($form, $form_state) {
  $workflow = $form_state['values']['workflow'];
  $wid = $workflow->wid;

  // Make sure 'author' is checked for (creation) -> [something].
  $creation_state = $workflow
    ->getCreationState();
  $creation_sid = $creation_state->sid;
  if (isset($form_state['values']['transitions'][$creation_sid]) && is_array($form_state['values']['transitions'][$creation_sid])) {
    foreach ($form_state['values']['transitions'][$creation_sid] as $to => $roles) {
      if ($roles['author']) {
        $author_has_permission = TRUE;
        break;
      }
    }
  }
  $state_count = db_query('SELECT COUNT(sid) FROM {workflow_states} WHERE wid = :wid', array(
    ':wid' => $wid,
  ))
    ->fetchField();
  if (empty($author_has_permission) && $state_count > 1) {
    form_set_error('transitions', t('Please give the author permission to go from %creation to at least one state!', array(
      '%creation' => $creation_state
        ->label(),
    )));
  }
}

/**
 * Theme the workflow editing form.
 *
 * @see workflow_edit_form()
 */
function theme_workflow_admin_ui_transitions_form($variables) {
  $output = '';
  $form = $variables['form'];
  $workflow = $form['workflow']['#value'];
  $wid = $workflow->wid;
  $name = $workflow
    ->getName();

  // If we don't have a workflow here, we need to go back to admin.
  if ($workflow) {
    drupal_set_title(t('Edit workflow %name transitions', array(
      '%name' => $name,
    )), PASS_THROUGH);
    $states = $workflow
      ->getStates();
    if ($states) {
      $roles = workflow_admin_ui_get_roles();
      $header = array(
        array(
          'data' => t('From / To') . ' &nbsp;' . WORKFLOW_ARROW,
        ),
      );
      $rows = array();
      foreach ($states as $state) {
        $label = check_plain($state
          ->label());

        // Don't allow transition TO (creation).
        if (!$state
          ->isCreationState()) {
          $header[] = array(
            'data' => $label,
          );
        }
        $row = array(
          array(
            'data' => $label,
          ),
        );
        foreach ($states as $nested_state) {
          if ($nested_state
            ->isCreationState()) {

            // Don't allow transition TO (creation).
            continue;
          }
          if ($nested_state != $state) {

            // Need to render checkboxes for transition from $state to $nested_state.
            $from = $state->sid;
            $to = $nested_state->sid;
            $cell = '';
            foreach ($roles as $rid => $role_name) {
              $cell .= drupal_render($form['transitions'][$from][$to][$rid]);
            }
            $row[] = array(
              'data' => $cell,
            );
          }
          else {
            $row[] = array(
              'data' => '',
            );
          }
        }
        $rows[] = $row;
      }
      $output .= theme('table', array(
        'header' => $header,
        'rows' => $rows,
      ));
    }
    else {
      $output = t('There are no states defined for this workflow.');
    }
    $output .= drupal_render_children($form);
    return $output;
  }
}

/**
 * Submit handler for the workflow editing form.
 *
 * @see workflow_edit_form()
 */
function workflow_admin_ui_transitions_form_submit($form, &$form_state) {
  $workflow = $form['workflow']['#value'];
  $wid = $workflow->wid;
  $name = $workflow
    ->getName();
  if (isset($form_state['values']['transitions'])) {
    _workflow_admin_ui_update_configured_transitions($form_state['values']['transitions']);
  }
  drupal_set_message(t('The workflow was updated.'));
  $form_state['redirect'] = 'admin/config/workflow/workflow/' . $wid;
}

/**
 * Form builder. Build the grid of transitions for defining a workflow.
 *
 * @param int $wid
 *   The workflow object.
 */
function _workflow_admin_ui_transition_grid_form($workflow) {
  $form = array(
    '#tree' => TRUE,
  );
  $roles = workflow_admin_ui_get_roles();
  $states = $workflow
    ->getStates();
  if (!$states) {
    $form['error'] = array(
      '#type' => 'markup',
      '#value' => t('There are no states defined for this workflow.'),
    );
    return $form;
  }
  foreach ($states as $state1) {
    $state_id = $state1->sid;
    $name = $state1
      ->label();
    foreach ($states as $state2) {
      $nested_state_id = $state2->sid;
      $nested_name = $state2
        ->label();
      if ($state2
        ->isCreationState()) {

        // Don't allow transition TO (creation).
        continue;
      }
      if ($nested_state_id != $state_id) {

        // Need to generate checkboxes for transition from $state to $nested_state.
        $from = $state_id;
        $to = $nested_state_id;
        foreach ($roles as $rid => $role_name) {
          $checked = FALSE;
          if ($transition = workflow_get_workflow_transitions_by_sid_target_sid($from, $to)) {
            $checked = workflow_transition_allowed($transition->tid, $rid);
          }
          $form[$from][$to][$rid] = array(
            '#type' => 'checkbox',
            '#title' => check_plain($role_name),
            '#default_value' => $checked,
          );
        }
      }
    }
  }
  return $form;
}

/**
 * Menu callback. Create the main workflow page, which gives an overview
 * of workflows and workflow states.
 * Replaced by http://drupal.org/node/1367530.
 */
function workflow_admin_ui_overview_form($form, $form_state, $workflow) {

  // Let's add some breadcrumbs.
  $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');
  drupal_set_breadcrumb($bc);
  drupal_set_title(t('Workflow: ') . $workflow
    ->label());
  $form = array();
  $form['#tree'] = TRUE;
  $form['workflow'] = array(
    '#type' => 'value',
    '#value' => $workflow,
  );

  // Allow modules to insert their own workflow operations.
  $links = module_invoke_all('workflow_operations', 'workflow', $workflow);
  $links_args = array(
    'links' => $links,
    'attributes' => array(
      'class' => array(
        'inline',
        'action-links',
      ),
    ),
  );
  $form['action-links'] = array(
    '#type' => 'markup',
    '#markup' => theme('links', $links_args),
  );

  // Build select options for reassigning states.
  // We put a blank state first for validation.
  $state_list = array(
    '' => ' ',
  );
  $state_list += $workflow
    ->getOptions();

  // Is this the last state available?
  $form['#last_mohican'] = count($state_list) == 2;

  // Get the state objects as array ($sid => WorkflowState)
  $states = $workflow
    ->getStates($all = TRUE);

  // Dummy object for new state item.
  $dummy = WorkflowState::create($name = '', $wid = $workflow->wid);
  $dummy->weight = 99;
  $states[$dummy->sid] = $dummy;

  // Although the index is 0, the state is appended at the end of the list.
  foreach ($states as $state) {

    // Allow modules to insert state operations.
    $state_links = module_invoke_all('workflow_operations', 'state', $workflow, $state);
    $form['states'][$state->sid] = array(
      'state' => array(
        '#type' => 'textfield',
        '#size' => 30,
        '#maxlength' => 255,
        '#default_value' => $state
          ->label(),
      ),
      'weight' => array(
        '#type' => 'weight',
        '#delta' => 20,
        '#default_value' => $state->weight,
        '#title-display' => 'invisible',
        '#attributes' => array(
          'class' => array(
            'state-weight',
          ),
        ),
      ),
      'status' => array(
        '#type' => 'checkbox',
        '#default_value' => $state
          ->isActive(),
      ),
      // Save the original status for the validation handler.
      'orig_status' => array(
        '#type' => 'value',
        '#value' => $state
          ->isActive(),
      ),
      'reassign' => array(
        '#type' => 'select',
        '#options' => $state_list,
      ),
      'count' => array(
        '#type' => 'value',
        '#value' => count(workflow_get_workflow_node_by_sid($state->sid)),
      ),
      'ops' => array(
        '#type' => 'markup',
        '#markup' => theme('links', array(
          'links' => $state_links,
        )),
      ),
      'sysid' => array(
        '#type' => 'value',
        '#value' => $state
          ->isCreationState(),
      ),
    );

    // Don't let the creation state change weight or status or name.
    if ($state
      ->isCreationState()) {
      $form['states'][$state->sid]['weight']['#value'] = -50;
      $form['states'][$state->sid]['sysid']['#value'] = 1;
      $form['states'][$state->sid]['state']['#disabled'] = TRUE;
      $form['states'][$state->sid]['status']['#disabled'] = TRUE;
      $form['states'][$state->sid]['reassign']['#disabled'] = TRUE;
    }
  }
  $form['instructions'] = array(
    '#type' => 'markup',
    '#markup' => '<p>' . t('You may enter a new state name in the empty space.
      Check the "Active" box to make it effective. You may also drag it to the appropriate position.') . '</p>' . '<p>' . t('A state not marked as active will not be shown as available in the workflow settings.') . '</p>' . '<p>' . t('If you wish to inactivate a state that has content (i.e. count is not zero),
        then you need to select a state to which to reassign that content.') . '</p>',
  );
  $form['actions'] = array(
    '#type' => 'actions',
  );
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save Changes'),
  );
  return $form;
}
function theme_workflow_admin_ui_overview_form($variables) {
  $form = $variables['form'];
  $output = '';
  $table_id = 'workflow_admin_ui_overview';
  $table = array(
    'rows' => array(),
    'header' => array(
      t('State'),
      t('Weight'),
      t('Active'),
      t('Reassign'),
      t('Count'),
      array(
        'data' => t('Operations'),
        'class' => 'state-ops',
      ),
    ),
    'attributes' => array(
      'id' => $table_id,
      'style' => 'width: auto;',
    ),
  );

  // The output needs to have the action links at the top.
  $output .= drupal_render($form['action-links']);

  // Iterate over each element in our $form['states'] array
  foreach (element_children($form['states']) as $id) {

    // We are now ready to add each element of our $form data to the rows
    // array, so that they end up as individual table cells when rendered
    // in the final table.  We run each element through the drupal_render()
    // function to generate the final html markup for that element.
    $table['rows'][] = array(
      'data' => array(
        // Add our 'name' column
        array(
          'data' => drupal_render($form['states'][$id]['state']),
          'class' => 'state-name',
        ),
        // Add our 'weight' column
        drupal_render($form['states'][$id]['weight']),
        // Add our 'status' column
        array(
          'data' => drupal_render($form['states'][$id]['status']),
          'class' => 'state-status',
        ),
        // Add our 'reassign' column
        array(
          'data' => drupal_render($form['states'][$id]['reassign']),
          'class' => 'state-reassign',
        ),
        // Add our 'count' column
        array(
          'data' => $form['states'][$id]['count']['#value'],
          'class' => 'state-count',
        ),
        // Add our 'operations' column
        array(
          'data' => drupal_render($form['states'][$id]['ops']),
          'class' => 'state-ops',
        ),
        // Add our 'sysid' column
        drupal_render($form['states'][$id]['sysid']),
      ),
      // To support the tabledrag behavior, we need to assign each row of the
      // table a class attribute of 'draggable'. This will add the 'draggable'
      // class to the <tr> element for that row when the final table is
      // rendered.
      'class' => array(
        'draggable',
      ),
    );
  }
  $output .= theme('table', $table);

  // And then render any remaining form elements (such as our submit button)
  $output .= drupal_render_children($form);

  // We now call the drupal_add_tabledrag() function in order to add the
  // tabledrag.js goodness onto our page.
  //
  // For a basic sortable table, we need to pass it:
  //   - the $table_id of our <table> element,
  //   - the $action to be performed on our form items ('order'),
  //   - a string describing where $action should be applied ('siblings'),
  //   - and the class of the element containing our 'weight' element.
  drupal_add_tabledrag($table_id, 'order', 'sibling', 'state-weight');
  return $output;
}

/**
 * Validation handler for the state form.
 */
function workflow_admin_ui_overview_form_validate($form, &$form_state) {

  // Get the workflow id.
  $workflow = $form_state['values']['workflow'];
  $wid = $workflow->wid;

  // Because the form elements were keyed with the item ids from the database,
  // we can simply iterate through the submitted values.
  foreach ($form_state['values']['states'] as $sid => $item) {

    // Reload $state from db, in case the states were changed by anyone else. And it is just as fast.
    $state = WorkflowState::load($sid);

    // Does user want to deactivate the state (reassign current nodes)?
    if ($sid > 0 && $item['status'] == 0 && $state
      ->isActive()) {
      $args = array(
        '%state' => $state
          ->getName(),
      );

      // Does that state have nodes in it?
      if ($item['count'] > 0 && empty($item['reassign'])) {
        if ($form['#last_mohican']) {
          $message = 'Since you are deleting the last available workflow state
            in this workflow, all content items which are in that state will have their
            workflow state removed.';
          drupal_set_message(t($message, $args), 'warning');
        }
        else {
          $message = 'The %state state has content; you must reassign the content to another state.';
          form_set_error("states'][{$sid}]['reassign'", t($message, $args));
        }
      }
      if (module_exists('workflowfield')) {

        // @todo: Reassign states for Workflow Field.
        $message = 'Deactivating state %state for does not reassign Fields of type Workflow with this status.';
        drupal_set_message(t($message, $args), 'warning');
      }
    }
  }
}

/**
 * Submission handler for the state form.
 */
function workflow_admin_ui_overview_form_submit($form, &$form_state) {

  // Get the workflow id, then save it for the next round.
  $workflow = $form_state['values']['workflow'];
  $wid = $workflow->wid;

  // Because the form elements were keyed with the item ids from the database,
  // we can simply iterate through the submitted values.
  foreach ($form_state['values']['states'] as $sid => $item) {
    $item['sid'] = $sid;
    $item['wid'] = $wid;

    // Is there not a new state name?
    if (empty($item['state'])) {

      // No new state entered, so skip it.
      continue;
    }

    // Reload $state from db, in case the states were changed by anyone else. And it is just a s fast.
    $state = $sid ? WorkflowState::load($sid) : WorkflowState::create($name = '', $wid);

    // Does user want to deactivate the state (reassign current nodes)?
    if ($sid > 0 && $item['status'] == 0 && $state
      ->isActive()) {
      if ($item['count'] > 0) {
        $new_sid = $item['reassign'];
        $new_state = WorkflowState::load($new_sid);
        $args = array(
          '%workflow' => $workflow
            ->getName(),
          '%old_state' => $state
            ->getName(),
          '%new_state' => isset($new_state) ? $new_state
            ->getName() : '',
        );
        if ($form['#last_mohican']) {
          $new_sid = NULL;

          // Do not reassign to new state.
          $message = 'Removing workflow states from content in the %workflow.';
          drupal_set_message(t($message, $args));
        }
        else {

          // Prepare the state delete function.
          $message = 'Reassigning content from %old_state to %new_state.';
          drupal_set_message(t($message, $args));
        }

        // Delete the old state without orphaning nodes, move them to the new state.
        $state
          ->deactivate($new_sid);
        $message = 'Deactivated workflow state %old_state in %workflow.';
        watchdog('workflow', $message, $args);
        drupal_set_message(t($message, $args));
      }
    }
    $state
      ->setName($item['state']);
    $state->status = $item['status'];
    $state->weight = $item['weight'];
    $state
      ->save();
  }
  $form_state['redirect'] = "admin/config/workflow/workflow/{$wid}";
}

/**
 * Form builder. Allow administrator to map workflows to content types
 * and determine placement.
 */
function workflow_admin_ui_type_map_form($form) {
  $form = array();

  // Allow modules to insert their own action links.
  $links = module_invoke_all('workflow_operations', 'top_actions', NULL);
  $links_args = array(
    'links' => $links,
    'attributes' => array(
      'class' => array(
        'inline',
        'action-links',
      ),
    ),
  );
  $form['action-links'] = array(
    '#type' => 'markup',
    '#markup' => theme('links', $links_args),
  );

  // Create list of all Workflow types. Include an initial empty value.
  // Validate each workflow, and generate a message if not complete.
  $workflows[0] = t('None');
  foreach (Workflow::getWorkflows() as $workflow) {
    if ($isValid = $workflow
      ->validate()) {
      $workflows[$workflow->wid] = $workflow
        ->label();
    }
  }
  if (count($workflows) == 1) {
    drupal_set_message(t('You must create at least one workflow before content can be assigned to a workflow.'));
    return $form;
  }
  $type_map = workflow_get_workflow_type_map();
  $form['#tree'] = TRUE;
  $form['help'] = array(
    '#type' => 'item',
    '#title' => '<h3>' . t('Content Type Mapping') . '</h3>',
    '#markup' => t('Each content type may have a separate workflow. The form for changing workflow state can be ' . 'displayed when editing a node, editing a comment for a node, or both.'),
  );
  $placement_options = array(
    'node' => t('Post'),
    'comment' => t('Comment'),
  );
  foreach (node_type_get_names() as $type => $name) {
    $form[$type]['workflow'] = array(
      '#type' => 'select',
      '#options' => $workflows,
      '#default_value' => isset($type_map[$type]) ? $type_map[$type] : 0,
    );
    $form[$type]['placement'] = array(
      '#type' => 'checkboxes',
      '#options' => $placement_options,
      '#default_value' => variable_get('workflow_' . $type, array()),
    );
  }
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save workflow mapping'),
    '#weight' => 100,
  );
  return $form;
}

/**
 * Theme the workflow type mapping form.
 */
function theme_workflow_admin_ui_type_map_form($variables) {
  $output = '';
  $form = $variables['form'];

  // Do the action links at the top.
  $output .= drupal_render($form['action-links']);
  $header = array(
    t('Content Type'),
    t('Workflow'),
    t('Display Workflow Form on:'),
  );
  $rows = array();
  foreach (node_type_get_names() as $type => $name) {
    $rows[] = array(
      check_plain(t($name)),
      drupal_render($form[$type]['workflow']),
      drupal_render($form[$type]['placement']),
    );
  }
  $output .= drupal_render($form['help']);
  $output .= theme('table', array(
    'header' => $header,
    'rows' => $rows,
    'attributes' => array(
      'style' => 'width: auto; clear: both;',
    ),
  ));
  return $output . drupal_render_children($form);
}

/**
 * Submit handler for workflow type mapping form.
 *
 * @see workflow_types_form()
 */
function workflow_admin_ui_type_map_form_submit($form, &$form_state) {
  workflow_admin_ui_types_save($form_state['values']);
  drupal_set_message(t('The workflow mapping was saved.'));
}

Functions

Namesort descending Description
theme_workflow_admin_ui_edit_form Theme the workflow editing form.
theme_workflow_admin_ui_overview_form
theme_workflow_admin_ui_transitions_form Theme the workflow editing form.
theme_workflow_admin_ui_type_map_form Theme the workflow type mapping form.
theme_workflow_admin_ui_view_permissions_form Theme the workflow permissions view.
workflow_admin_ui_add_form Form builder. Create the form for adding/editing a workflow.
workflow_admin_ui_add_form_submit Submit handler for the workflow add form.
workflow_admin_ui_add_form_validate Validate the workflow add form.
workflow_admin_ui_delete_form Form builder. Create form for confirmation of workflow deletion.
workflow_admin_ui_delete_form_submit Submit handler for workflow deletion form.
workflow_admin_ui_edit_form Menu callback. Edit a workflow's properties.
workflow_admin_ui_edit_form_submit Submit handler for the workflow editing form.
workflow_admin_ui_edit_form_validate Validate the workflow editing form.
workflow_admin_ui_overview_form Menu callback. Create the main workflow page, which gives an overview of workflows and workflow states. Replaced by http://drupal.org/node/1367530.
workflow_admin_ui_overview_form_submit Submission handler for the state form.
workflow_admin_ui_overview_form_validate Validation handler for the state form.
workflow_admin_ui_transitions_form Menu callback. Edit a workflow's transitions.
workflow_admin_ui_transitions_form_submit Submit handler for the workflow editing form.
workflow_admin_ui_transitions_form_validate Validate the workflow editing form.
workflow_admin_ui_type_map_form Form builder. Allow administrator to map workflows to content types and determine placement.
workflow_admin_ui_type_map_form_submit Submit handler for workflow type mapping form.
workflow_admin_ui_view_permissions_form View workflow permissions by role
_workflow_admin_ui_transition_grid_form Form builder. Build the grid of transitions for defining a workflow.