123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- <?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 creadit 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 assingments 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 assignements 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 seprate 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']);
- }
- }
|