workflow_actions.module in Workflow 7
Same filename and directory in other branches
Provide actions and triggers for workflows. Why it's own module? Some sites prefer rules, some prefer actions, all prefer a lower code footprint and better performance. Additional credit to gcassie ( http://drupal.org/user/80260 ) for the initial push to split actions out of core workflow.
File
workflow_actions/workflow_actions.moduleView source
<?php
/**
* @file
* Provide actions and triggers for workflows.
* Why it's own module? Some sites prefer rules, some prefer actions,
* all prefer a lower code footprint and better performance.
* Additional credit to gcassie ( http://drupal.org/user/80260 ) for
* the initial push to split actions out of core workflow.
*/
/**
* Implements hook_hook_info().
* Expose each transition as a hook.
*/
function workflow_actions_trigger_info() {
$states = array();
foreach (workflow_get_workflow_states() as $data) {
$states[$data->sid] = check_plain($data->state);
}
if (empty($states)) {
return array();
}
$trigger_page = drupal_substr($_GET['q'], 0, 32) == 'admin/structure/trigger/workflow';
// TODO these should be pulled into their own DB function calls.
if ($trigger_page && ($wid = arg(4))) {
$result = db_query('SELECT tm.type, w.wid, w.name, ws.state, wt.tid, wt.sid, wt.target_sid ' . 'FROM {workflow_type_map} tm ' . 'LEFT JOIN {workflows} w ON tm.wid = w.wid ' . 'LEFT JOIN {workflow_states} ws ON w.wid = ws.wid ' . 'LEFT JOIN {workflow_transitions} wt ON ws.sid = wt.sid ' . 'WHERE w.wid = :wid AND ws.status = 1 AND wt.target_sid IS NOT NULL ' . 'ORDER BY tm.type, ws.weight', array(
':wid' => $wid,
));
}
else {
$result = db_query('SELECT tm.type, w.wid, w.name, ws.state, wt.tid, wt.sid, wt.target_sid ' . 'FROM {workflow_type_map} tm ' . 'LEFT JOIN {workflows} w ON tm.wid = w.wid ' . 'LEFT JOIN {workflow_states} ws ON w.wid = ws.wid ' . 'LEFT JOIN {workflow_transitions} wt ON ws.sid = wt.sid ' . 'WHERE ws.status = 1 AND wt.target_sid IS NOT NULL ' . 'ORDER BY tm.type, ws.weight');
}
$creation_state = t('(creation)');
foreach ($result as $data) {
$creation_flag = FALSE;
if ($states[$data->sid] == $creation_state) {
$creation_flag = TRUE;
}
$pseudohooks['workflow-' . $data->type . '-' . $data->tid] = array(
'label' => t('When %type moves from %state to %target_state', array(
'%type' => $data->type,
'%state' => $states[$data->sid],
'%target_state' => $states[$data->target_sid],
)),
'workflow_creation_state' => $creation_flag,
);
}
// $pseudohooks will not be set if no workflows have been assigned
// to node types.
if (isset($pseudohooks)) {
return array(
'workflow' => $pseudohooks,
);
}
if ($trigger_page) {
drupal_set_message(t('Either no transitions have been set up or this workflow has not yet been ' . 'assigned to a content type. To enable the assignment of actions, edit the workflow to assign ' . 'permissions for roles to do transitions. After that is completed, transitions will appear here ' . 'and you will be able to assign actions to them.'));
}
}
/**
* Implements hook_workflow().
*
* @param $hook
* The current workflow operation: 'transition pre' or 'transition post'.
* @param $old_state
* The state ID of the current state.
* @param $new_state
* The state ID of the new state.
* @param $node
* The node whose workflow state is changing.
*/
function workflow_actions_workflow($op, $old_state, $new_state, $node) {
switch ($op) {
case 'transition post':
// A transition has occurred; fire off actions associated with this transition.
if ($transition = workflow_get_workflow_transitions_by_sid_target_sid($old_state, $new_state)) {
$hook = 'workflow-' . $node->type . '-' . $transition->tid;
$aids = trigger_get_assigned_actions($hook);
if ($aids) {
$context = array(
'hook' => $hook,
);
// We need to get the expected object if the action's type is not 'node'.
// We keep the object in $objects so we can reuse it if we have multiple actions
// that make changes to an object.
foreach ($aids as $aid => $action_info) {
if ($action_info['type'] != 'node') {
if (!isset($objects[$action_info['type']])) {
$objects[$action_info['type']] = _trigger_normalize_node_context($action_info['type'], $node);
}
// Since we know about the node, we pass that info along to the action.
$context['node'] = $node;
$result = actions_do($aid, $objects[$action_info['type']], $context);
}
else {
actions_do($aid, $node, $context);
}
}
}
}
break;
case 'transition delete':
if ($transition = workflow_get_workflow_transitions_by_sid_target_sid($old_state, $new_state)) {
$actions = workflow_actions_get_actions_by_tid($transition->tid);
foreach ($actions as $aid) {
workflow_actions_remove($transition->tid, $aid);
}
}
break;
}
}
/**
* Implements hook_workflow_operations().
* Called in workflow.admin.inc to add actions for states.
*/
function workflow_actions_workflow_operations($level, $workflow = NULL, $state = NULL) {
if ($workflow) {
return array(
'workflow_overview_actions' => array(
'title' => t('Actions'),
'href' => 'admin/structure/trigger/workflow/' . $workflow->wid,
),
);
}
}
/**
* Remove an action assignment programmatically.
*
* Helpful when deleting a workflow.
*
* @param $tid
* Transition ID.
* @param $aid
* Action ID.
*/
function workflow_actions_remove($tid, $aid) {
$ops = array();
foreach (workflow_actions_get_trigger_assignments_by_aid($aid) as $data) {
// Transition ID is the last part, e.g., foo-bar-1.
$transition = array_pop(explode('-', $data->hook));
if ($tid == $transition) {
$hooks[] = $data->hook;
}
}
foreach ($hooks as $hook) {
workflow_actions_delete_trigger_assignments_by_aid_op($aid, $hook);
foreach (workflow_actions_get_actions_by_aid($aid) as $action) {
watchdog('workflow', 'Action %action has been unassigned.', array(
'%action' => $action->description,
));
}
}
}
/**
* DB functions.
*/
/**
* Get all trigger assignments for workflow.
*/
function workflow_actions_get_trigger_assignments() {
$results = db_query('SELECT hook FROM {trigger_assignments} WHERE hook = "workflow"');
return $results
->fetchAll();
}
/**
* Get all trigger assignments for workflow and a given action.
*/
function workflow_actions_get_trigger_assignments_by_aid($aid) {
$results = db_query('SELECT hook FROM {trigger_assignments} WHERE hook = "workflow" AND aid = ":aid"', array(
':aid' => $aid,
));
return $results
->fetchAll();
}
/**
* Delete assignments, by action and operation.
*/
function workflow_actions_delete_trigger_assignments_by_aid_op($aid, $op) {
return db_delete('trigger_assignments')
->condition('hook', 'workflow')
->condition('hook', $op)
->condition('aid', $aid)
->execute();
}
/**
* Get a specific action.
*/
function workflow_actions_get_actions_by_aid($aid) {
$results = db_query('SELECT * FROM {actions} WHERE aid = ":aid"', array(
':aid' => $aid,
));
return $results
->fetchAll();
}
/**
* Get the actions associated with a given transition.
* Array of action ids in the same format as _trigger_get_hook_aids().
*/
function workflow_actions_get_actions_by_tid($tid) {
$aids = array();
foreach (workflow_actions_get_trigger_assignments() as $data) {
// Transition ID is the last part, e.g., foo-bar-1.
$transition = array_pop(explode('-', $data->hook));
if ($tid == $transition) {
// Specialized, TODO separate this SQL out later
$results = db_query('SELECT aa.aid, a.type FROM {trigger_assignments} aa ' . 'LEFT JOIN {actions} a ON aa.aid = a.aid ' . 'WHERE aa.hook = ":hook" ' . 'ORDER BY weight', array(
':hook' => $data->hook,
));
foreach ($results as $action) {
$aids[$action->aid]['type'] = $action->type;
}
}
}
return $aids;
}
/**
* Implementation of hook_drupal_alter().
*/
function workflow_actions_action_info_alter(&$info) {
$transitions = workflow_actions_trigger_info();
if (empty($transitions)) {
return;
}
foreach ((array) $transitions['workflow'] as $transition => $data) {
// Loop through all available node actions and add them as triggers.
// But not if this has been flagged as a creation state.
if ($data['workflow_creation_state'] != TRUE) {
foreach (node_action_info() as $action => $data) {
$info[$action]['triggers'][] = $transition;
}
}
// Either way, unset the creation flag so we don't confuse anyone later.
unset($transitions['workflow'][$transition]['workflow_creation_state']);
}
}
Functions
Name | Description |
---|---|
workflow_actions_action_info_alter | Implementation of hook_drupal_alter(). |
workflow_actions_delete_trigger_assignments_by_aid_op | Delete assignments, by action and operation. |
workflow_actions_get_actions_by_aid | Get a specific action. |
workflow_actions_get_actions_by_tid | Get the actions associated with a given transition. Array of action ids in the same format as _trigger_get_hook_aids(). |
workflow_actions_get_trigger_assignments | Get all trigger assignments for workflow. |
workflow_actions_get_trigger_assignments_by_aid | Get all trigger assignments for workflow and a given action. |
workflow_actions_remove | Remove an action assignment programmatically. |
workflow_actions_trigger_info | Implements hook_hook_info(). Expose each transition as a hook. |
workflow_actions_workflow | Implements hook_workflow(). |
workflow_actions_workflow_operations | Implements hook_workflow_operations(). Called in workflow.admin.inc to add actions for states. |