workflow.pages.inc 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. <?php
  2. /**
  3. * @file
  4. * Provide user interface for changing workflow state.
  5. */
  6. /**
  7. * Menu callback. Display workflow summary of a node.
  8. */
  9. function workflow_tab_page($node = NULL) {
  10. drupal_set_title($node->title);
  11. $workflow = workflow_get_workflow_type_map_by_type($node->type);
  12. $states = array();
  13. $state_system_names = array();
  14. foreach (workflow_get_workflow_states() as $data) {
  15. $states[$data->sid] = check_plain(t($data->state));
  16. $state_system_names[$data->sid] = check_plain($data->state);
  17. }
  18. $deleted_states = array();
  19. $deleted_state_system_names = array();
  20. $options = array('status' => 0);
  21. foreach (workflow_get_workflow_states($options) as $data) {
  22. $deleted_states[$data->sid] = check_plain(t($data->state));
  23. $deleted_state_system_names[$data->sid] = check_plain($data->state);
  24. }
  25. $current = workflow_node_current_state($node);
  26. // theme_workflow_history_current_state() must run state through check_plain().
  27. $current_state = theme('workflow_history_current_state', array('state_name' => $states[$current], 'state_system_name' => $state_system_names[$current], 'sid' => $current));
  28. $output = theme('workflow_current_state', array('state' => $states[$current], 'state_system_name' => $state_system_names[$current], 'sid' => $current));
  29. // Show the form to allow state changing.
  30. // But only if we are not at the terminal state.
  31. $choices = workflow_field_choices($node);
  32. if (count($choices) != 0 || count($choices) != 1 || $current != key($choices)) {
  33. $form = drupal_get_form('workflow_tab_form', $node, $workflow->wid, $states, $current);
  34. $output .= drupal_render($form);
  35. }
  36. $rows = array();
  37. foreach (workflow_get_workflow_node_history_by_nid($node->nid) as $history) {
  38. if ($history->sid == $current && !isset($deleted_states[$history->sid]) && !isset($current_themed)) {
  39. // Theme the current state differently so it stands out.
  40. $state_name = theme('workflow_history_current_state', array('state_name' => $states[$history->sid], 'state_system_name' => $state_system_names[$history->sid], 'sid' => $history->sid));
  41. // Make a note that we have themed the current state; other times in the history
  42. // of this node where the node was in this state do not need to be specially themed.
  43. $current_themed = TRUE;
  44. }
  45. elseif (isset($deleted_states[$history->sid])) {
  46. // The state has been deleted, but we include it in the history.
  47. $state_name = theme('workflow_deleted_state', array('state_name' => $deleted_states[$history->sid], 'state_system_name' => $deleted_state_system_names[$history->sid], 'sid' => $history->sid));
  48. $footer_needed = TRUE;
  49. }
  50. else {
  51. // Regular state.
  52. $state_name = check_plain(t($states[$history->sid]));
  53. }
  54. if (isset($deleted_states[$history->old_sid])) {
  55. $old_state_name = theme('workflow_deleted_state', array('state_name' => $deleted_states[$history->old_sid], 'state_system_name' => $deleted_state_system_names[$history->old_sid], 'sid' => $history->old_sid));
  56. $footer_needed = TRUE;
  57. }
  58. elseif (isset($states[$history->old_sid])) {
  59. $old_state_name = check_plain(t($states[$history->old_sid]));
  60. }
  61. else {
  62. $old_state_name = '*';
  63. }
  64. $variables = array(
  65. 'history' => $history,
  66. 'old_sid' => $history->old_sid,
  67. 'old_state_name' => $old_state_name,
  68. 'sid' => $history->sid,
  69. 'uid' => $history->uid,
  70. 'state_name' => $state_name,
  71. );
  72. // Allow other modules to modify the row.
  73. drupal_alter('workflow_history', $variables);
  74. $rows[] = theme('workflow_history_table_row', $variables);
  75. }
  76. // Mark the first and last rows.
  77. $rows[0]['class'][] = 'first';
  78. $last = count($rows) - 1;
  79. $rows[$last]['class'][] = 'last';
  80. // Only display the table if there's anything in it.
  81. if ($rows) {
  82. $output .= theme('workflow_history_table', array('rows' => $rows, 'footer' => !empty($footer_needed)));
  83. $output .= theme('pager', array('tags' => variable_get('workflow_states_per_page', 20)));
  84. }
  85. return $output;
  86. }
  87. /*
  88. * Theme one workflow history table row.
  89. *
  90. * $old_state_name and $state_name must be run through check_plain(t()) prior
  91. * to calling this theme function.
  92. */
  93. function theme_workflow_history_table_row($variables) {
  94. $row = array();
  95. $old_state_name = $variables['old_state_name'];
  96. $state_name = $variables['state_name'];
  97. $history = $variables['history'];
  98. $account = user_load($variables['uid']);
  99. $row = array(
  100. 'data' => array(
  101. array('data' => format_date($history->stamp), 'class' => array('timestamp')),
  102. array('data' => $old_state_name, 'class' => array('previous-state-name')),
  103. array('data' => $state_name, 'class' => array('state-name')),
  104. array('data' => theme('username', array('account' => $account)), 'class' => array('user-name')),
  105. array('data' => filter_xss($history->comment), 'class' => array('log-comment')),
  106. ),
  107. 'class' => array('workflow_history_row'),
  108. );
  109. if (!empty($variables['extra'])) {
  110. $row['data'][] = $variables['extra'];
  111. }
  112. return $row;
  113. }
  114. /*
  115. * Theme entire workflow history table.
  116. */
  117. function theme_workflow_history_table($variables) {
  118. $rows = $variables['rows'];
  119. $footer = $variables['footer'];
  120. $headers = array(t('Date'), t('Old State'), t('New State'), t('By'), t('Comment'));
  121. $output = theme('table', array('header' => $headers, 'rows' => $rows, 'caption' => t('Workflow History')));
  122. if ($footer) {
  123. $output .= t('*State is no longer available.');
  124. }
  125. return $output;
  126. }
  127. /**
  128. * Theme the current state in the workflow history table.
  129. */
  130. function theme_workflow_history_current_state($variables) {
  131. return check_plain(t($variables['state_name']));
  132. }
  133. /**
  134. * Theme a deleted state in the workflow history table.
  135. */
  136. function theme_workflow_deleted_state($variables) {
  137. return check_plain(t($variables['state_name'])) . '*';
  138. }
  139. /**
  140. * Form builder. Allow workflow state change and scheduling from workflow tab.
  141. *
  142. * @param $node
  143. * Node for which workflow information will be displayed.
  144. * @param $wid
  145. * ID of workflow to display.
  146. * @param $states
  147. * Array of states for the workflow.
  148. * @param $current
  149. * Current workflow state of this node.
  150. * @return
  151. * Form definition array.
  152. */
  153. function workflow_tab_form($form, $form_state, $node, $wid, $states, $current) {
  154. // Tell FAPI where this form is.
  155. form_load_include($form_state, 'inc', 'workflow', 'workflow.pages');
  156. // Let's make sure we should be here.
  157. if (workflow_node_tab_access($node) === FALSE) {
  158. return;
  159. }
  160. $form['#tab'] = TRUE;
  161. $choices = workflow_field_choices($node);
  162. $min = ($states[$current] == t('(creation)') ? 1 : 2);
  163. // Only build form if user has possible target state(s).
  164. if (count($choices) >= $min) {
  165. $workflow = workflow_get_workflow_type_map_by_type($node->type);
  166. $workflow = workflow_get_workflows_by_wid($workflow->wid);
  167. $form['#wf'] = $workflow;
  168. $form['#choices'] = $choices;
  169. $name = t($workflow->name);
  170. $timestamp = '';
  171. $comment = '';
  172. // See if scheduling information is present.
  173. if (!empty($node->workflow_scheduled_timestamp) && !empty($node->workflow_scheduled_sid)) {
  174. global $user;
  175. if (variable_get('configurable_timezones', 1) && $user->uid && drupal_strlen($user->timezone)) {
  176. $timezone = $user->timezone;
  177. }
  178. else {
  179. $timezone = variable_get('date_default_timezone', 0);
  180. }
  181. // The default value should be the upcoming sid.
  182. $current = $node->workflow_scheduled_sid;
  183. $timestamp = $node->workflow_scheduled_timestamp;
  184. $comment = $node->workflow_scheduled_comment;
  185. }
  186. // Include the same form elements here that are included on a
  187. // regular node editing page. $form is modified by reference.
  188. workflow_node_form($form, $form_state, t('Change !name state', array('!name' => $name)), $name, $current, $choices, $timestamp, $comment);
  189. $form['node'] = array(
  190. '#type' => 'value',
  191. '#value' => $node,
  192. );
  193. $form['submit'] = array(
  194. '#type' => 'submit',
  195. '#value' => t('Update workflow'),
  196. );
  197. }
  198. return $form;
  199. }
  200. /**
  201. * Submit handler for the form on the workflow tab.
  202. *
  203. * @see workflow_tab_form()
  204. */
  205. function workflow_tab_form_submit($form, &$form_state) {
  206. // The entire node object was stashed in the form.
  207. $node = $form_state['values']['node'];
  208. if (isset($form_state['values']['workflow'])) {
  209. $node->workflow = $form_state['values']['workflow'];
  210. $node->workflow_comment = isset($form_state['values']['workflow_comment']) ?
  211. $form_state['values']['workflow_comment'] : '';
  212. if (!empty($form_state['values']['workflow_scheduled'])) {
  213. $node->workflow_scheduled = $form_state['values']['workflow_scheduled'];
  214. }
  215. if (!empty($form_state['values']['workflow_scheduled_date'])) {
  216. $node->workflow_scheduled_date = $form_state['values']['workflow_scheduled_date'];
  217. }
  218. if (!empty($form_state['values']['workflow_scheduled_hour'])) {
  219. $node->workflow_scheduled_hour = $form_state['values']['workflow_scheduled_hour'];
  220. }
  221. if (!empty($form_state['values']['workflow_scheduled_timezone'])) {
  222. $node->workflow_scheduled_timezone = $form_state['values']['workflow_scheduled_timezone'];
  223. }
  224. }
  225. // ALERT: Rules that use node_save to check the node transition are going to be missed if
  226. // the tab form is used to check for the change. It is *always* better practice to use
  227. // the transition change itself as your value to check for changes with Rules and other
  228. // behaviors. Do NOT rely on node_save() to drive transition changes.
  229. workflow_transition($node, $node->workflow);
  230. }