View source
<?php
define('WORKFLOW_CREATION', 1);
define('WORKFLOW_CREATION_DEFAULT_WEIGHT', -50);
define('WORKFLOW_DELETION', 0);
module_load_include('inc', 'workflow', 'workflow.node');
module_load_include('inc', 'workflow', 'workflow.node.type_map');
module_load_include('inc', 'workflow', 'workflow.deprecated');
function workflow_permission() {
return array(
'schedule workflow transitions' => array(
'title' => t('Schedule workflow transitions'),
'description' => t('Schedule workflow transitions.'),
),
'show workflow state form' => array(
'title' => t('Show workflow state change on node view'),
'description' => t('Show workflow state change form on node viewing.'),
),
);
}
function workflow_menu() {
$items['node/%node/workflow'] = array(
'title' => 'Workflow',
'type' => MENU_LOCAL_TASK,
'file' => 'workflow.pages.inc',
'access callback' => 'workflow_tab_access',
'access arguments' => array(
1,
),
'page callback' => 'workflow_tab_page',
'page arguments' => array(
1,
),
'weight' => 2,
);
return $items;
}
function workflow_hook_info() {
$hooks['workflow'] = array(
'group' => 'workflow',
);
return $hooks;
}
function workflow_admin_paths_alter(&$paths) {
if (isset($path['node/*/edit'])) {
$path['node/*/workflow'] = $path['node/*/edit'];
}
}
function workflow_load($wid) {
return Workflow::load($wid);
}
function workflow_tab_access($node = NULL) {
global $user;
static $access = array();
$entity_type = 'node';
$node_type = $node->type;
if ($workflow = workflow_get_workflows_by_type($node_type, $entity_type)) {
$nid = isset($node->nid) ? $node->nid : 0;
if (isset($access[$user->uid][$nid])) {
return $access[$user->uid][$nid];
}
$roles = array_keys($user->roles);
if ($node->uid == $user->uid) {
$roles = array_merge(array(
'author',
), $roles);
}
$allowed_roles = $workflow->tab_roles ? explode(',', $workflow->tab_roles) : array();
if (user_access('administer nodes') || array_intersect($roles, $allowed_roles)) {
$access[$user->uid][$nid] = TRUE;
}
else {
$access[$user->uid][$nid] = FALSE;
}
return $access[$user->uid][$nid];
}
return FALSE;
}
function workflow_theme() {
return array(
'workflow_history_table_row' => array(
'variables' => array(
'history' => NULL,
'old_state_name' => NULL,
'state_name' => NULL,
),
),
'workflow_history_table' => array(
'variables' => array(
'rows' => array(),
'footer' => NULL,
),
),
'workflow_history_current_state' => array(
'variables' => array(
'state_name' => NULL,
'state_system_name' => NULL,
'sid' => NULL,
),
),
'workflow_current_state' => array(
'variables' => array(
'state' => NULL,
'state_system_name' => NULL,
'sid' => NULL,
),
),
'workflow_deleted_state' => array(
'variables' => array(
'state_name' => NULL,
'state_system_name' => NULL,
'sid' => NULL,
),
),
);
}
function workflow_cron() {
$clear_cache = FALSE;
foreach (WorkflowScheduledTransition::loadBetween() as $scheduled_transition) {
$entity_type = $scheduled_transition->entity_type;
$entity = $scheduled_transition
->getEntity();
if (empty($scheduled_transition->comment)) {
$scheduled_transition
->addDefaultComment();
}
$workflowItem = $scheduled_transition
->getWorkflowItem();
$field_info = $workflowItem ? $workflowItem
->getField() : array();
$current_sid = workflow_node_current_state($entity, $entity_type, $field_info);
if ($current_sid == $scheduled_transition->old_sid) {
$entity->workflow_uid = $scheduled_transition->uid;
$new_sid = $scheduled_transition
->execute($force = TRUE);
if ($field_info) {
$items[0]['value'] = $new_sid;
$field_name = $field_info['field_name'];
$entity->{$field_name}['und'] = $items;
$workflowItem
->entitySave($entity_type, $entity);
}
$clear_cache = TRUE;
}
else {
$scheduled_transition
->delete();
}
}
if ($clear_cache) {
cache_clear_all();
}
}
function workflow_user_delete($account) {
workflow_update_workflow_node_uid($account->uid, 0);
workflow_update_workflow_node_history_uid($account->uid, 0);
}
function workflow_features_api() {
return array(
'workflow' => array(
'name' => t('Workflow'),
'file' => drupal_get_path('module', 'workflow') . '/workflow.features.inc',
'default_hook' => 'workflow_default_workflows',
'feature_source' => TRUE,
),
);
}
function workflow_transition($entity, $new_sid, $force = FALSE, $field = array()) {
$entity_type = 'node';
$widget = new WorkflowDefaultWidget($field, $instance = array(), $entity_type, $entity);
$form = array();
$form_state = array();
$items = array();
$items[0]['workflow'] = (array) $entity;
$items[0]['workflow']['workflow_options'] = $new_sid;
$widget
->submit($form, $form_state, $items, $force);
}
function workflow_node_form(&$form, $form_state, $title, $name, $current, $choices, $timestamp = NULL, $comment = NULL) {
$form['#wf_options'] = array(
'title' => $title,
'name' => $name,
'current' => $current,
'choices' => $choices,
'timestamp' => $timestamp,
'comment' => $comment,
);
if (count($choices) == 1) {
$state = key($choices);
$form['workflow'][$name] = array(
'#type' => 'value',
'#value' => array(
$state => $state,
),
);
}
else {
$form['workflow'] = array(
'#type' => 'container',
'#attributes' => array(
'class' => array(
'workflow-form-container',
),
),
);
$form['workflow'][$name] = array(
'#type' => 'radios',
'#title' => !empty($form['#wf']->options['name_as_title']) ? $title : '',
'#options' => $choices,
'#name' => $name,
'#parents' => array(
'workflow',
),
'#default_value' => $current,
);
}
if (!(arg(0) == 'node' && arg(1) == 'add') && (!isset($form['#wf']->options['schedule']) || !empty($form['#wf']->options['schedule'])) && user_access('schedule workflow transitions')) {
$scheduled = $timestamp ? 1 : 0;
$timestamp = $scheduled ? $timestamp : REQUEST_TIME;
$form['workflow']['workflow_scheduled'] = array(
'#type' => 'radios',
'#title' => t('Schedule'),
'#options' => array(
t('Immediately'),
t('Schedule for state change'),
),
'#default_value' => isset($form_state['values']['workflow_scheduled']) ? $form_state['values']['workflow_scheduled'] : $scheduled,
);
$form['workflow']['workflow_scheduled_date_time'] = array(
'#type' => 'fieldset',
'#title' => t('At'),
'#prefix' => '<div style="margin-left: 1em;">',
'#suffix' => '</div>',
'#states' => array(
'visible' => array(
':input[name="workflow_scheduled"]' => array(
'value' => 1,
),
),
'invisible' => array(
':input[name="workflow_scheduled"]' => array(
'value' => 0,
),
),
),
);
$form['workflow']['workflow_scheduled_date_time']['workflow_scheduled_date'] = array(
'#type' => 'date',
'#default_value' => array(
'day' => isset($form_state['values']['workflow_scheduled_date']['day']) ? $form_state['values']['workflow_scheduled_date']['day'] : format_date($timestamp, 'custom', 'j'),
'month' => isset($form_state['values']['workflow_scheduled_date']['month']) ? $form_state['values']['workflow_scheduled_date']['month'] : format_date($timestamp, 'custom', 'n'),
'year' => isset($form_state['values']['workflow_scheduled_date']['year']) ? $form_state['values']['workflow_scheduled_date']['year'] : format_date($timestamp, 'custom', 'Y'),
),
);
$hours = format_date($timestamp, 'custom', 'H:i');
$form['workflow']['workflow_scheduled_date_time']['workflow_scheduled_hour'] = array(
'#type' => 'textfield',
'#description' => t('Please enter a time in 24 hour (e.g. HH:MM) format.
If no time is included, the default will be midnight on the specified date.
The current time is: @time', array(
'@time' => $hours,
)),
'#default_value' => $scheduled ? isset($form_state['values']['workflow_scheduled_hour']) ? $form_state['values']['workflow_scheduled_hour'] : $hours : '00:00',
);
global $user;
if (variable_get('configurable_timezones', 1) && $user->uid && drupal_strlen($user->timezone)) {
$timezone = $user->timezone;
}
else {
$timezone = variable_get('date_default_timezone', 0);
}
$timezone_type = isset($form['#wf']->options['schedule_timezone']) && empty($form['#wf']->options['schedule_timezone']) ? 'hidden' : 'select';
$timezones = drupal_map_assoc(timezone_identifiers_list());
$form['workflow']['workflow_scheduled_date_time']['workflow_scheduled_timezone'] = array(
'#type' => $timezone_type,
'#title' => t('Time zone'),
'#options' => $timezones,
'#default_value' => array(
$timezone => $timezone,
),
);
}
$determiner = isset($form['#tab']) ? 'comment_log_tab' : 'comment_log_node';
$comment_type = 'hidden';
if (isset($form['#wf']->options[$determiner])) {
$comment_type = $form['#wf']->options[$determiner] ? 'textarea' : 'hidden';
}
$form['workflow']['workflow_comment'] = array(
'#type' => $comment_type,
'#title' => t('Workflow comment'),
'#description' => t('A comment to put in the workflow log.'),
'#default_value' => $comment,
'#rows' => 2,
);
}
function workflow_execute_transition($entity, $new_sid, $comment = NULL, $force = FALSE, $old_sid = 0, $entity_type = 'node', $field_name = '') {
global $user;
if (empty($entity->nid)) {
return $old_sid;
}
$old_sid = $old_sid ? $old_sid : workflow_node_current_state($entity, $entity_type, $field_name);
$transition = new WorkflowTransition($entity_type, $entity, $field_name, $old_sid, $new_sid, $user->uid, REQUEST_TIME, $comment);
$new_sid = $transition
->execute($force);
return $new_sid;
}
function workflow_get_workflow_options($wid = 0, $grouped = FALSE) {
$options = array();
foreach (Workflow::getWorkflows($wid) as $workflow) {
$options += $workflow
->getOptions($grouped);
}
return $options;
}
function workflow_node_current_state($entity, $entity_type = 'node', $field = array()) {
$sid = FALSE;
$state = FALSE;
if ($field) {
$field_name = $field['field_name'];
if (isset($entity->is_new) && $entity->is_new == TRUE) {
$workflow = Workflow::load($field['settings']['wid']);
$sid = $workflow
->getCreationSid();
}
elseif (isset($entity->original)) {
$referenced_entity = $entity->original;
$items = field_get_items($entity_type, $referenced_entity, $field_name);
$sid = _workflow_get_sid_by_items($items);
}
else {
$items = field_get_items($entity_type, $entity, $field_name);
$sid = _workflow_get_sid_by_items($items);
}
if (empty($sid)) {
$workflow = Workflow::load($field['settings']['wid']);
$sid = $workflow
->getCreationSid();
}
return $sid;
}
$entity_type = 'node';
if (!$sid && !empty($entity->nid)) {
$state = workflow_get_workflow_node_by_nid($entity->nid);
if ($state) {
$sid = $state->sid;
}
}
if (!$sid && !empty($entity->type)) {
if ($workflow = workflow_get_workflows_by_type($entity->type, $entity_type)) {
$sid = $workflow
->getCreationSid();
}
}
return $sid;
}
function workflow_node_previous_state($node) {
$sid = FALSE;
if (!empty($node->nid)) {
$sids = array();
$sid = -1;
$last_history = workflow_get_recent_node_history($node->nid);
$sid = !$last_history ? FALSE : $last_history->old_sid;
}
if (!$sid && !empty($node->type)) {
$entity_type = 'node';
if ($workflow = workflow_get_workflows_by_type($node->type, $entity_type)) {
$sid = $workflow
->getCreationSid();
}
}
return $sid;
}
function workflow_transition_allowed($tid, $role = NULL) {
$transition = workflow_get_workflow_transitions_by_tid($tid);
$allowed = $transition->roles;
$allowed = explode(',', $allowed);
if ($role) {
if (!is_array($role)) {
$role = array(
$role,
);
}
return array_intersect($role, $allowed) == TRUE;
}
}
function workflow_get_workflows_by_type($entity_bundle, $entity_type = 'node') {
static $map = array();
$wid = 0;
$field_item = NULL;
if (!isset($map[$entity_type][$entity_bundle])) {
$type_map = workflow_get_workflow_type_map_by_type($entity_bundle);
if ($type_map) {
$wid = $type_map->wid;
}
if (!$wid && isset($entity_type)) {
foreach (field_info_instances($entity_type, $entity_bundle) as $field_name => $instance) {
$field = field_info_field($instance['field_name']);
if ($field['type'] == 'workflow') {
$wid = $field['settings']['wid'];
$field_item = new WorkflowItem($field, $instance, $entity_type, NULL);
}
}
}
$map[$entity_type][$entity_bundle] = FALSE;
if ($wid) {
$workflow = Workflow::load($wid);
$workflow
->getWorkflowItem($field_item);
$map[$entity_type][$entity_bundle] = $workflow;
}
}
return $map[$entity_type][$entity_bundle];
}
function workflow_update_workflows(&$data, $create_creation_state = TRUE) {
$data = (object) $data;
if (isset($data->tab_roles) && is_array($data->tab_roles)) {
$data->tab_roles = implode(',', $data->tab_roles);
}
if (isset($data->wid) && Workflow::load($data->wid)) {
drupal_write_record('workflows', $data, 'wid');
}
else {
drupal_write_record('workflows', $data);
if ($create_creation_state) {
$state_data = array(
'wid' => $data->wid,
'state' => t('(creation)'),
'sysid' => WORKFLOW_CREATION,
'weight' => WORKFLOW_CREATION_DEFAULT_WEIGHT,
);
workflow_update_workflow_states($state_data);
}
}
}
function workflow_get_workflow_transitions_by_wid($wid) {
static $transitions;
if (!isset($transitions[$wid])) {
$query = 'SELECT t.tid, t.sid, t.target_sid, t.roles, s1.wid ' . 'FROM {workflow_transitions} t ' . 'INNER JOIN {workflow_states} s1 ON t.sid=s1.sid ' . 'INNER JOIN {workflow_states} s2 ON t.target_sid=s2.sid ' . 'WHERE s1.wid = :wid AND s2.wid = :wid';
$transitions[$wid] = db_query('SELECT t.*, s1.wid FROM {workflow_transitions} AS t INNER JOIN {workflow_states} AS s1 ON t.sid=s1.sid INNER JOIN {workflow_states} AS s2 ON t.target_sid=s2.sid WHERE s1.wid = :wid AND s2.wid = :wid', array(
':wid' => $wid,
))
->fetchAll();
}
return $transitions[$wid];
}
function workflow_get_workflow_transitions_by_tid($tid) {
static $transitions;
if (!isset($transitions[$tid])) {
$transitions[$tid] = db_query('SELECT tid, sid, target_sid, roles FROM {workflow_transitions} WHERE tid = :tid', array(
':tid' => $tid,
))
->fetchObject();
}
return $transitions[$tid];
}
function workflow_get_workflow_transitions_by_sid($sid) {
static $transitions;
if (!isset($transitions[$sid])) {
$transitions[$sid] = db_query('SELECT tid, sid, target_sid, roles FROM {workflow_transitions} WHERE sid = :sid', array(
':sid' => $sid,
))
->fetchAll();
}
return $transitions[$sid];
}
function workflow_get_workflow_transitions_by_target_sid($target_sid) {
static $transitions;
if (!isset($transitions[$target_sid])) {
$transitions[$target_sid] = db_query('SELECT tid, sid, target_sid, roles FROM {workflow_transitions} WHERE target_sid = :target_sid', array(
':target_sid' => $target_sid,
))
->fetchAll();
}
return $transitions[$target_sid];
}
function workflow_get_workflow_transitions_by_sid_involved($sid) {
$results = db_query('SELECT tid, sid, target_sid, roles FROM {workflow_transitions} WHERE sid = :sid OR target_sid = :sid', array(
':sid' => $sid,
));
return $results
->fetchAll();
}
function workflow_get_workflow_transitions_by_roles($roles) {
$results = db_query('SELECT tid, sid, target_sid, roles FROM {workflow_transitions} WHERE roles LIKE :roles', array(
':roles' => $roles,
));
return $results
->fetchAll();
}
function workflow_get_workflow_transitions_by_sid_target_sid($sid, $target_sid) {
$results = db_query('SELECT tid, sid, target_sid, roles FROM {workflow_transitions} WHERE sid = :sid AND target_sid = :target_sid', array(
':sid' => $sid,
':target_sid' => $target_sid,
));
return $results
->fetchObject();
}
function workflow_delete_workflow_transitions_by_tid($tid) {
module_invoke_all('workflow', 'transition delete', $tid, NULL, NULL, FALSE);
return db_delete('workflow_transitions')
->condition('tid', $tid)
->execute();
}
function workflow_delete_workflow_transitions_by_roles($roles) {
foreach (workflow_get_workflow_transitions_by_roles($roles) as $transition) {
workflow_delete_workflow_transitions_by_tid($transition->tid);
}
}
function workflow_update_workflow_transitions(&$data) {
$data = (object) $data;
$transition = workflow_get_workflow_transitions_by_sid_target_sid($data->sid, $data->target_sid);
if ($transition) {
$roles = explode(',', $transition->roles);
foreach (explode(',', $data->roles) as $role) {
if (array_search($role, $roles) === FALSE) {
$roles[] = $role;
}
}
$transition->roles = implode(',', $roles);
drupal_write_record('workflow_transitions', $transition, 'tid');
$data = $transition;
}
else {
drupal_write_record('workflow_transitions', $data);
}
}
function workflow_update_workflow_transitions_roles($tid, $roles) {
return db_update('workflow_transitions')
->fields(array(
'roles' => implode(',', $roles),
))
->condition('tid', $tid, '=')
->execute();
}
function workflow_allowable_transitions($sid, $dir = 'to', $roles = 'ALL') {
$transitions = array();
$query = db_select('workflow_transitions', 't')
->fields('t', array(
'tid',
));
if ($dir == 'to') {
$query
->innerJoin('workflow_states', 's', 's.sid = t.target_sid');
$query
->addField('t', 'target_sid', 'state_id');
$query
->condition('t.sid', $sid);
}
else {
$query
->innerJoin('workflow_states', 's', 's.sid = t.sid');
$query
->addField('t', 'sid', 'state_id');
$query
->condition('t.target_sid', $sid);
}
$query
->addField('s', 'state', 'state_name');
$query
->addField('s', 'weight', 'state_weight');
$query
->addField('s', 'sysid');
$query
->condition('s.status', 1);
$query2 = db_select('workflow_states', 's');
$query2
->addField('s', 'sid', 'tid');
$query2
->addField('s', 'sid', 'state_id');
$query2
->addField('s', 'state', 'state_name');
$query2
->addField('s', 'weight', 'state_weight');
$query2
->addField('s', 'sysid');
$query2
->condition('s.status', 1);
$query2
->condition('s.sid', $sid);
$query2
->orderBy('state_weight');
$query2
->orderBy('state_id');
$query
->union($query2, 'UNION');
$results = $query
->execute();
foreach ($results as $transition) {
if ($roles == 'ALL' || $sid == $transition->state_id || workflow_transition_allowed($transition->tid, $roles)) {
$transitions[] = $transition;
}
}
return $transitions;
}
function workflow_get_recent_node_history($nid) {
$results = db_query_range('SELECT h.hid, h.nid, h.old_sid, h.sid, h.uid, h.stamp, h.comment, ' . 's.state AS state_name ' . 'FROM {workflow_node_history} h ' . 'INNER JOIN {workflow_states} s ON s.sid = h.sid ' . 'WHERE h.nid = :nid ORDER BY h.stamp DESC', 0, 1, array(
':nid' => $nid,
));
return $results
->fetchObject();
}
function workflow_get_workflow_node_history_by_nid($nid, $limit = NULL) {
if (empty($limit)) {
$limit = variable_get('workflow_states_per_page', 20);
}
$results = db_query_range('SELECT h.hid, h.nid, h.old_sid, h.sid, h.uid, h.stamp, h.comment ' . 'FROM {workflow_node_history} h ' . 'LEFT JOIN {users} u ON h.uid = u.uid ' . 'WHERE nid = :nid ' . 'ORDER BY h.stamp DESC, h.hid DESC ', 0, $limit, array(
':nid' => $nid,
));
if ($limit == 1) {
return $results
->fetchObject();
}
return $results
->fetchAll();
}
function workflow_update_workflow_node_history_uid($uid, $new_value) {
return db_update('workflow_node_history')
->fields(array(
'uid' => $new_value,
))
->condition('uid', $uid, '=')
->execute();
}
function workflow_insert_workflow_node_history($data) {
$data = (object) $data;
if (isset($data->hid)) {
unset($data->hid);
}
if ($data->old_sid == $data->sid) {
$last_history = workflow_get_workflow_node_history_by_nid($data->nid, 1);
if (isset($last_history) && $last_history->stamp == REQUEST_TIME) {
return;
}
}
drupal_write_record('workflow_node_history', $data);
}
function workflow_get_workflow_node_by_nid($nid) {
$results = db_query('SELECT nid, sid, uid, stamp FROM {workflow_node} WHERE nid = :nid', array(
':nid' => $nid,
));
return $results
->fetchObject();
}
function workflow_get_workflow_node_by_sid($sid) {
$results = db_query('SELECT nid, sid, uid, stamp FROM {workflow_node} WHERE sid = :sid', array(
':sid' => $sid,
));
return $results
->fetchAll();
}
function workflow_update_workflow_node_stamp($nid, $new_stamp) {
return db_update('workflow_node')
->fields(array(
'stamp' => $new_stamp,
))
->condition('nid', $nid, '=')
->execute();
}
function workflow_update_workflow_node_uid($uid, $new_uid) {
return db_update('workflow_node')
->fields(array(
'uid' => $new_uid,
))
->condition('uid', $uid, '=')
->execute();
}
function workflow_delete_workflow_node_by_nid($nid) {
return db_delete('workflow_node')
->condition('nid', $nid)
->execute();
}
function workflow_delete_workflow_node_by_sid($sid) {
return db_delete('workflow_node')
->condition('sid', $sid)
->execute();
}
function workflow_update_workflow_node($data, $old_sid, $comment = NULL) {
$data = (object) $data;
if (isset($data->nid) && workflow_get_workflow_node_by_nid($data->nid)) {
drupal_write_record('workflow_node', $data, 'nid');
}
else {
drupal_write_record('workflow_node', $data);
}
$data = array(
'nid' => $data->nid,
'old_sid' => $old_sid,
'sid' => $data->sid,
'uid' => $data->uid,
'stamp' => $data->stamp,
'comment' => $comment,
);
workflow_insert_workflow_node_history($data);
}
function workflow_requirements($phase) {
$requirements = array();
switch ($phase) {
case 'runtime':
$types = db_query('SELECT wid, type FROM {workflow_type_map} WHERE wid <> 0 ORDER BY type')
->fetchAllKeyed();
if (count($types) == 0) {
return;
}
if (count($types) == 1) {
$type_list = current($types);
}
else {
$last = array_pop($types);
if (count($types) > 2) {
$type_list = implode(', ', $types) . ', and ' . $last;
}
else {
$type_list = current($types) . ' and ' . $last;
}
}
$requirements['workflow'] = array(
'title' => t('Workflow'),
'value' => t('Workflow is active on the @types content types.', array(
'@types' => $type_list,
)),
'severity' => REQUIREMENT_OK,
);
return $requirements;
}
}
function workflow_show_form($sid, $workflow, $choices) {
$count = count($choices);
if ($count > 1) {
return TRUE;
}
if ($sid == $workflow
->getCreationSid()) {
return TRUE;
}
return FALSE;
}
function _workflow_get_sid_by_items($items) {
$sid = isset($items[0]['value']) ? $items[0]['value'] : 0;
$sid = isset($items[0]['workflow']['workflow_options']) ? $items[0]['workflow']['workflow_options'] : $sid;
return $sid;
}
function _workflow_get_entity_id($entity_type, $entity) {
return $entity_id = $entity_type == 'node' ? isset($entity->nid) ? $entity->nid : 0 : entity_id($entity_type, $entity);
}