given.action.inc 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <?php
  2. /**
  3. * @file
  4. * VBO action to modify entity values (properties and fields).
  5. */
  6. /**
  7. * Implements hook_action_info().
  8. *
  9. * Registers custom VBO actions as Drupal actions.
  10. */
  11. function workflow_vbo_given_action_info() {
  12. return array(
  13. 'workflow_vbo_given_state_action' => array(
  14. 'type' => 'entity',
  15. 'label' => t('Change workflow state of post to new state'),
  16. 'configurable' => TRUE,
  17. 'triggers' => array('any'),
  18. // 'aggregate' => TRUE,
  19. // 'pass rows' => TRUE, // you will have $context['views row'] as the current selected row.
  20. ),
  21. );
  22. }
  23. /**
  24. * Implements a Drupal action. Move a node to a specified state in the workflow.
  25. * @param $entity
  26. * @param array $context
  27. */
  28. function workflow_vbo_given_state_action($entity, array $context) {
  29. global $user;
  30. // As advanced action with Trigger 'node':
  31. // - $entity is empty;
  32. // - $context['group'] = 'node'
  33. // - $context['hook'] = 'node_insert / _update / _delete'
  34. // - $context['node'] = (Object) stdClass
  35. // - $context['entity_type'] = NULL
  36. // As advanced action with Trigger 'taxonomy':
  37. // - $entity is (Object) stdClass;
  38. // - $context['type'] = 'entity'
  39. // - $context['group'] = 'taxonomy'
  40. // - $context['hook'] = 'taxonomy_term_insert / _update / _delete'
  41. // - $context['node'] = (Object) stdClass
  42. // - $context['entity_type'] = NULL
  43. // As advanced action with Trigger 'workflow API':
  44. // ...
  45. // As VBO action:
  46. // - $entity is (Object) stdClass;
  47. // - $context['type'] = NULL
  48. // - $context['group'] = NULL
  49. // - $context['hook'] = NULL
  50. // - $context['node'] = (Object) stdClass
  51. // - $context['entity_type'] = 'node'
  52. // Get the entity type, entity and entity ID.
  53. if (isset($context['entity_type'])) {
  54. // In a VBO Action.
  55. $entity_type = $context['entity_type'];
  56. }
  57. else {
  58. // In an Advanced Action.
  59. $entity_type = str_replace(array('_insert', '_update' , '_delete'), '', $context['hook']);
  60. }
  61. // Change the state of latest revision, not current revision.
  62. if (isset($context[$entity_type])) {
  63. $entity = $context[$entity_type];
  64. }
  65. elseif (!isset($entity)) {
  66. $entity = $context['node'];
  67. }
  68. // In 'after saving new content', the node is already saved. Avoid second insert.
  69. // Todo: clone?
  70. unset($entity->is_new);
  71. list($entity_id, , $entity_bundle) = entity_extract_ids($entity_type, $entity);
  72. if (!$entity_id) {
  73. watchdog('workflow_vbo', 'Unable to get current entity ID - entity is not yet saved.');
  74. return;
  75. }
  76. // Get data from the context.
  77. $form = $context['form'];
  78. $form_state = $context['form_state'];
  79. // Get the current State Id. Also, $field_name will be set magically, by reference.
  80. $field_name = NULL;
  81. $current_sid = workflow_node_current_state($entity, $entity_type, $field_name);
  82. if (!$current_sid) {
  83. watchdog('workflow_vbo', 'Unable to get current workflow state of entity %id.',
  84. array('%id' => $entity_id));
  85. return;
  86. }
  87. // Get the new State Id.
  88. $new_sid = $form_state['input']['workflow_sid'];
  89. // The following 2 lines should give the same result.
  90. // $force = $form_state['input']['workflow_force'];
  91. $force = $context['force'];
  92. // Get the Comment. Parse the $comment variables.
  93. $comment_string = $form_state['input']['workflow_comment'];
  94. $comment = t($comment_string, array(
  95. '%title' => entity_label($entity_type, $entity), // "@" and "%" will automatically run check_plain().
  96. '%state' => workflow_get_sid_label($new_sid),
  97. '%user' => $user->name,
  98. )
  99. );
  100. // Fire the transition.
  101. $transition = new WorkflowTransition();
  102. $transition->setValues($entity_type, $entity, $field_name, $current_sid, $new_sid, $user->uid, REQUEST_TIME, $comment);
  103. workflow_execute_transition($entity_type, $entity, $field_name, $transition, $force);
  104. }
  105. /**
  106. * Configuration form for "Change workflow state of post to new state" action.
  107. *
  108. * This copies functionality from workflow_tab_page, and overrides some fields.
  109. *
  110. * @see workflow_vbo_given_state_action()
  111. */
  112. function workflow_vbo_given_state_action_form(array $context) {
  113. $form = array();
  114. // If we are on admin/config/system/actions and use CREATE AN ADVANCED ACTION
  115. // Then $context only contains:
  116. // - $context['actions_label'] = "Change workflow state of post to new state"
  117. // - $context['actions_type'] = "entity"
  118. //
  119. // If we are on a VBO action form, then $context only contains:
  120. // - $context['entity_type'] = "node"
  121. // - $context['view'] = "(Object) view"
  122. // - $context['settings'] = "array()"
  123. // @todo: There's a problem here: we do not know the node types of the
  124. // selected items, and we do not know the field_names, so we have no clue
  125. // about the allowed workflows or states.
  126. if ($entity_type = isset($context['entity_type']) ? $context['entity_type'] : NULL) {
  127. $entity_info = entity_get_info($entity_type);
  128. $entity_key = $entity_info['entity keys']['id'];
  129. unset($entity_info);
  130. }
  131. $result = isset($context['view']) ? $context['view']->result : array();
  132. // Get the common workflow from entities. With Workflow Node, we knew how to do this.
  133. // With Workflow Field, we need to determine the workflow.
  134. $wid = 0;
  135. $field_name = NULL;
  136. foreach ($result as $entity_data) {
  137. // @todo: what to do with multiple workflow_fields per bundle?
  138. // The 'result' does not contain 'real' entities, and they mess up subfunctions.
  139. // We could fetch it from the array, like this: $entity = $entity_data->_field_data[$entity_key]['entity'];
  140. // But this is not reliable, if you have no fields to show.
  141. // So, last resort, just fetch from database/cache.
  142. $entity = entity_load_single($entity_type, $entity_data->{$entity_key});
  143. $field_name = NULL;
  144. $current_sid = workflow_node_current_state($entity, $entity_type, $field_name);
  145. $state = workflow_state_load_single($current_sid);
  146. if (!$wid && $state) {
  147. $wid = $state->wid;
  148. }
  149. elseif ($wid && $state && $wid <> $state->wid) {
  150. watchdog('workflow', 'Multiple workflows found in VBO action.', WATCHDOG_ERROR);
  151. drupal_set_message(t('Error: the selection contains more then one workflow.'), 'error');
  152. return $form; // <--- exit !!
  153. }
  154. }
  155. // Preserve $entity's bundle and id, if only 1 is selected.
  156. if (count($result) != 1) {
  157. $entity = NULL;
  158. }
  159. $entity_id = '';
  160. $entity_bundle = '';
  161. // Get the common Workflow, or create a dummy Workflow.
  162. $workflow = $wid ? workflow_load($wid) : workflow_create('dummy VBO');
  163. // Show the current state and the Workflow form to allow state changing.
  164. // N.B. This part is replicated in hook_node_view, workflow_tab_page, workflow_vbo.
  165. if ($workflow) {
  166. $field = _workflow_info_field($field_name, $workflow);
  167. $field_name = $field['field_name'];
  168. $field_id = $field['id'];
  169. $instance = field_info_instance($entity_type, $field_name, $entity_bundle);
  170. // Hide the submit button. VBO has its own 'next' button.
  171. $instance['widget']['settings']['submit_function'] = '';
  172. if (!$field_id) {
  173. // This is a Workflow Node workflow. Set widget options as in v7.x-1.2
  174. $field['settings']['widget']['comment'] = isset($workflow->options['comment_log_tab']) ? $workflow->options['comment_log_tab'] : 1; // vs. ['comment_log_node'];
  175. $field['settings']['widget']['current_status'] = TRUE;
  176. // As stated above, the options list is probably very long, so let's use select list.
  177. $field['settings']['widget']['options'] = 'select';
  178. // Do not show the default [Update workflow] button on the form.
  179. $instance['widget']['settings']['submit_function'] = '';
  180. }
  181. }
  182. // Add the form/widget to the formatter, and include the nid and field_id in the form id,
  183. // to allow multiple forms per page (in listings, with hook_forms() ).
  184. // Ultimately, this is a wrapper for WorkflowDefaultWidget.
  185. // $form['workflow_current_state'] = workflow_state_formatter($entity_type, $entity, $field, $instance);
  186. $form_id = implode('_', array('workflow_transition_form', $entity_type, $entity_id, $field_id));
  187. $form += drupal_get_form($form_id, $field, $instance, $entity_type, $entity);
  188. if (!$entity) {
  189. // For the Advanced actions form on admin/config/system/actions,
  190. // remove the Submit function.
  191. unset($form['#submit']);
  192. }
  193. // Make adaptations for VBO-form:
  194. // Override the options widget.
  195. $form['workflow']['workflow_sid']['#title'] = t('Target state');
  196. $form['workflow']['workflow_sid']['#description'] = t('Please select the state that should be assigned when this action runs.');
  197. $form['workflow']['workflow_sid']['#default_value'] = isset($context['target_sid']) ? $context['target_sid'] : '';
  198. $form['workflow']['workflow_force'] = array(
  199. '#type' => 'checkbox',
  200. '#title' => t('Force transition'),
  201. '#description' => t('If this box is checked, the new state will be assigned even if workflow permissions disallow it.'),
  202. '#default_value' => isset($context['force']) ? $context['force'] : '',
  203. );
  204. $form['workflow']['workflow_comment'] = array(
  205. '#type' => 'textfield',
  206. '#title' => t('Message'),
  207. '#description' => t('This message will be written into the workflow history log when the action
  208. runs. You may include the following variables: %state, %title, %user.'),
  209. '#default_value' => isset($context['workflow_history']) ? $context['workflow_history'] : t('Action set %title to %state by %user.'),
  210. );
  211. return $form;
  212. }
  213. /**
  214. * Submit handler for "Change workflow state of post to new state" action configuration form.
  215. *
  216. * @see workflow_vbo_given_state_action_form()
  217. */
  218. function workflow_vbo_given_state_action_submit($form, $form_state) {
  219. $new_sid = $form_state['input']['workflow_sid'];
  220. if (!$new_sid) {
  221. return;
  222. }
  223. return array(
  224. 'force' => $form_state['input']['workflow_force'],
  225. 'form' => $form,
  226. 'form_state' => $form_state,
  227. );
  228. }