WorkflowItem.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. <?php
  2. /**
  3. * @file
  4. * Contains workflow\includes\Field\WorkflowItem.
  5. * @see https://drupal.org/node/2064123 for 'Field Type Plugin' change record D7->D8.
  6. */
  7. /**
  8. * Plugin implementation of the 'workflow' field type.
  9. *
  10. * @FieldType(
  11. * id = "workflow",
  12. * label = @Translation("Workflow"),
  13. * description = @Translation("This field stores Workflow values for a certain Workflow type from a list of allowed 'value => label' pairs, i.e. 'Publishing': 1 => unpublished, 2 => draft, 3 => published."),
  14. * default_widget = "options_select",
  15. * default_formatter = "list_formatter",
  16. * property_type' = WORKFLOWFIELD_PROPERTY_TYPE,
  17. * )
  18. */
  19. class WorkflowItem extends WorkflowD7Base {// D8: extends ConfigFieldItemBase implements PrepareCacheInterface {
  20. /**
  21. * Function, that gets replaced by the 'annotations' in D8. (@see comments above this class)
  22. */
  23. public static function getInfo() {
  24. return array(
  25. 'workflow' => array(
  26. 'label' => t('Workflow'),
  27. 'description' => t("This field stores Workflow values for a certain Workflow type from a list of allowed 'value => label' pairs, i.e. 'Publishing': 1 => unpublished, 2 => draft, 3 => published."),
  28. 'settings' => array(
  29. 'allowed_values_function' => 'workflowfield_allowed_values', // For the list.module formatter
  30. // 'allowed_values_function' => 'WorkflowItem::getAllowedValues', // For the list.module formatter.
  31. 'wid' => '',
  32. // 'history' => 1,
  33. // 'schedule' => 0,
  34. // 'comment' => 0,
  35. 'widget' => array(
  36. 'options' => 'select',
  37. 'name_as_title' => 1,
  38. 'fieldset' => 0,
  39. 'hide' => 0,
  40. 'schedule' => 1,
  41. 'schedule_timezone' => 1,
  42. 'comment' => 1,
  43. ),
  44. 'watchdog_log' => 1,
  45. 'history' => array(
  46. 'history_tab_show' => 1,
  47. 'roles' => array(),
  48. ),
  49. ),
  50. 'instance_settings' => array(),
  51. 'default_widget' => 'workflow',
  52. 'default_formatter' => 'list_default',
  53. // Properties are introduced in Entity API and used for Rules integration.
  54. 'property_type' => WORKFLOWFIELD_PROPERTY_TYPE,
  55. 'property_callbacks' => array('workflowfield_property_info_callback'),
  56. ),
  57. );
  58. }
  59. /**
  60. * Implements hook_field_settings_form() -> ConfigFieldItemInterface::settingsForm().
  61. *
  62. * @param array $form
  63. * @param array $form_state
  64. * @param $has_data
  65. *
  66. * @return array $element
  67. * The newly constructed element.
  68. */
  69. public function settingsForm(array $form, array &$form_state, $has_data) {
  70. $field_info = self::getInfo();
  71. $settings = $this->field['settings'];
  72. $settings += $field_info['workflow']['settings'];
  73. $settings['widget'] += $field_info['workflow']['settings']['widget'];
  74. // Create list of all Workflow types. Include an initial empty value.
  75. // Validate each workflow, and generate a message if not complete.
  76. /* @var $workflow Workflow */
  77. $workflows = array();
  78. $workflows[''] = t('- Select a value -');
  79. foreach ($workflows += workflow_get_workflow_names() as $wid => $label) {
  80. $workflow = workflow_load_single($wid);
  81. if ($wid && !$workflow->isValid()) {
  82. unset($workflows[$wid]);
  83. }
  84. }
  85. // Set message, if no 'validated' workflows exist.
  86. if (count($workflows) == 1) {
  87. drupal_set_message(
  88. t('You must create at least one workflow before content can be
  89. assigned to a workflow.')
  90. );
  91. }
  92. // The allowed_values_functions is used in the formatter from list.module.
  93. $element['allowed_values_function'] = array(
  94. '#type' => 'value',
  95. '#value' => $settings['allowed_values_function'], // = 'workflowfield_allowed_values',
  96. );
  97. // $field['settings']['wid'] can be numeric or named, or empty.
  98. $wid = isset($settings['wid']) ? $settings['wid'] : '';
  99. // Let the user choose between the available workflow types.
  100. $element['wid'] = array(
  101. '#type' => 'select',
  102. '#title' => t('Workflow type'),
  103. '#options' => $workflows,
  104. '#default_value' => $wid,
  105. '#required' => TRUE,
  106. '#disabled' => $has_data,
  107. '#description' => t('Choose the Workflow type. Maintain workflows !url.', array('!url' => l(t('here'), WORKFLOW_ADMIN_UI_PATH))),
  108. );
  109. // Inform the user of possible states.
  110. // If no Workflow type is selected yet, do not show anything.
  111. if ($wid) {
  112. // Get a string representation to show all options.
  113. $allowed_values = workflow_state_load_multiple($wid);
  114. $allowed_values_string = $this->_allowed_values_string($wid);
  115. $element['allowed_values_string'] = array(
  116. '#type' => 'textarea',
  117. '#title' => t('Allowed values for the selected Workflow type'),
  118. '#default_value' => $allowed_values_string,
  119. '#rows' => count($allowed_values),
  120. '#access' => TRUE, // User can see the data,
  121. '#disabled' => TRUE, // .. but cannot change them.
  122. );
  123. }
  124. $element['widget'] = array(
  125. '#type' => 'fieldset',
  126. '#title' => t('Workflow widget'),
  127. '#description' => t('Set some global properties of the widgets for this
  128. workflow. Some can be altered per widget instance.'
  129. ),
  130. );
  131. $fieldset_options = array(0 => t('No fieldset'), 1 => t('Collapsible fieldset'), 2 => t('Collapsed fieldset'));
  132. $element['widget']['fieldset'] = array(
  133. '#type' => 'select',
  134. '#options' => $fieldset_options,
  135. '#title' => t('Show the form in a fieldset?'),
  136. '#default_value' => $settings['widget']['fieldset'],
  137. '#description' => t("The Widget can be wrapped in a visible fieldset. You'd
  138. do this when you use the widget on a Node Edit page."
  139. ),
  140. );
  141. $element['widget']['options'] = array(
  142. '#type' => 'select',
  143. '#title' => t('How to show the available states'),
  144. '#required' => FALSE,
  145. '#default_value' => $settings['widget']['options'],
  146. // '#multiple' => TRUE / FALSE,
  147. '#options' => array(
  148. // These options are taken from options.module
  149. 'select' => 'Select list',
  150. 'radios' => 'Radio buttons',
  151. // This option does not work properly on Comment Add form.
  152. 'buttons' => 'Action buttons',
  153. ),
  154. '#description' => t("The Widget shows all available states. Decide which
  155. is the best way to show them. ('Action buttons' do not work on Comment form.)"
  156. ),
  157. );
  158. $element['widget']['hide'] = array(
  159. '#type' => 'checkbox',
  160. '#attributes' => array('class' => array('container-inline')),
  161. '#title' => t('Hide the widget on Entity form.'),
  162. '#default_value' => $settings['widget']['hide'],
  163. '#description' => t(
  164. 'Using Workflow Field, the widget is always shown when editing an
  165. Entity. Set this checkbox in case you only want to change the status
  166. on the Workflow History tab or on the Node View. (This checkbox is
  167. only needed because Drupal core does not have a "hidden" widget.)'
  168. ),
  169. );
  170. $element['widget']['name_as_title'] = array(
  171. '#type' => 'checkbox',
  172. '#attributes' => array('class' => array('container-inline')),
  173. '#title' => t('Use the workflow name as the title of the workflow form'),
  174. '#default_value' => $settings['widget']['name_as_title'],
  175. '#description' => t(
  176. 'The workflow section of the editing form is in its own fieldset.
  177. Checking the box will add the workflow name as the title of workflow
  178. section of the editing form.'
  179. ),
  180. );
  181. $element['widget']['schedule'] = array(
  182. '#type' => 'checkbox',
  183. '#title' => t('Allow scheduling of workflow transitions.'),
  184. '#required' => FALSE,
  185. '#default_value' => $settings['widget']['schedule'],
  186. '#description' => t(
  187. 'Workflow transitions may be scheduled to a moment in the future.
  188. Soon after the desired moment, the transition is executed by Cron.
  189. This may be hidden by settings in widgets, formatters or permissions.'
  190. ),
  191. );
  192. $element['widget']['schedule_timezone'] = array(
  193. '#type' => 'checkbox',
  194. '#title' => t('Show a timezone when scheduling a transition.'),
  195. '#required' => FALSE,
  196. '#default_value' => $settings['widget']['schedule_timezone'],
  197. );
  198. $element['widget']['comment'] = array(
  199. '#type' => 'select',
  200. '#title' => t('Allow adding a comment to workflow transitions'),
  201. '#required' => FALSE,
  202. '#options' => array(
  203. // Use 0/1/2 to stay compatible with previous checkbox.
  204. 0 => t('hidden'),
  205. 1 => t('optional'),
  206. 2 => t('required'),
  207. ),
  208. '#default_value' => $settings['widget']['comment'],
  209. '#description' => t('On the Workflow form, a Comment form can be included
  210. so that the person making the state change can record reasons for doing
  211. so. The comment is then included in the node\'s workflow history. This
  212. may be altered by settings in widgets, formatters or permissions.'
  213. ),
  214. );
  215. $element['watchdog_log'] = array(
  216. '#type' => 'checkbox',
  217. '#attributes' => array('class' => array('container-inline')),
  218. '#title' => t('Log informational watchdog messages when a transition is
  219. executed (a state value is changed)'),
  220. '#default_value' => $settings['watchdog_log'],
  221. '#description' => t('Optionally log transition state changes to watchdog.'),
  222. );
  223. $element['history'] = array(
  224. '#type' => 'fieldset',
  225. '#title' => t('Workflow history'),
  226. '#collapsible' => TRUE,
  227. '#collapsed' => FALSE,
  228. );
  229. $element['history']['history_tab_show'] = array(
  230. '#type' => 'checkbox',
  231. '#title' => t('Use the workflow history, and show it on a separate tab.'),
  232. '#required' => FALSE,
  233. '#default_value' => $settings['history']['history_tab_show'],
  234. '#description' => t("Every state change is recorded in table
  235. {workflow_node_history}. If checked and user has proper permission, a
  236. tab 'Workflow' is shown on the entity view page, which gives access to
  237. the History of the workflow. If you have multiple workflows per bundle,
  238. better disable this feature, and use, clone & adapt the Views display
  239. 'Workflow history per Entity'."),
  240. );
  241. $element['history']['roles'] = array(
  242. '#type' => 'checkboxes',
  243. '#options' => workflow_get_roles(),
  244. '#title' => t('Workflow history permissions'),
  245. '#default_value' => $settings['history']['roles'],
  246. '#description' => t('Select any roles that should have access to the workflow tab on nodes that have a workflow.'),
  247. );
  248. return $element;
  249. }
  250. /**
  251. * Implements hook_field_insert() -> FieldItemInterface::insert().
  252. */
  253. public function insert() {
  254. return $this->update();
  255. }
  256. /**
  257. * Helper functions for the Field Settings page.
  258. *
  259. * Generates a string representation of an array of 'allowed values'.
  260. * This is a copy from list.module's list_allowed_values_string().
  261. * The string format is suitable for edition in a textarea.
  262. *
  263. * @param int $wid
  264. * The Workflow Id.
  265. *
  266. * @return string
  267. * The string representation of the $values array:
  268. * - Values are separated by a carriage return.
  269. * - Each value is in the format "value|label" or "value".
  270. */
  271. protected function _allowed_values_string($wid = 0) {
  272. $lines = array();
  273. $states = workflow_state_load_multiple($wid);
  274. $previous_wid = -1;
  275. /* @var $state WorkflowState */
  276. foreach ($states as $state) {
  277. // Only show enabled states.
  278. if ($state->isActive()) {
  279. // Show a Workflow name between Workflows, if more then 1 in the list.
  280. if (($wid == 0) && ($previous_wid <> $state->wid)) {
  281. $previous_wid = $state->wid;
  282. $lines[] = $state->name . "'s states: ";
  283. }
  284. $label = $state->label();
  285. $states[$state->sid] = $label;
  286. $lines[] = $state->sid . ' | ' . $label;
  287. }
  288. }
  289. return implode("\n", $lines);
  290. }
  291. /**
  292. * Helper function for list.module formatter.
  293. *
  294. * Callback function for the list module formatter.
  295. *
  296. * @see list_allowed_values
  297. * "The strings are not safe for output. Keys and values of the array should
  298. * "be sanitized through field_filter_xss() before being displayed.
  299. *
  300. * @return array
  301. * The array of allowed values. Keys of the array are the raw stored values
  302. * (number or text), values of the array are the display labels.
  303. * It contains all possible values for the field, because the result is
  304. * cached on a field basis, and used for all nodes on a page.
  305. */
  306. public function getAllowedValues() {
  307. // Get all state names, including inactive states.
  308. $wid = isset($this->field['settings']['wid']) ? $this->field['settings']['wid'] : 0;
  309. $options = workflow_get_workflow_state_names($wid, $grouped = FALSE, $all = TRUE);
  310. return $options;
  311. }
  312. }