123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- <?php
- /**
- * @file
- * Contains helper functions for WorkflowTransitionForm.
- */
- use Drupal\Component\Utility\Html;
- use Drupal\workflow\Entity\WorkflowTransitionInterface;
- /**
- * Getter/Setter to tell if the action buttons are used.
- *
- * @param string $button_type
- * Options. If empty, value is only getted, else the button type.
- *
- * @return string
- * Previous value. If 'dropbutton'||'buttons', action buttons must be created.
- *
- * @see workflow_form_alter()
- * @see WorkflowDefaultWidget::formElement()
- *
- * Used to save some expensive operations on every form.
- */
- function _workflow_use_action_buttons($button_type = '') {
- global $_workflow_use_actions_buttons;
- // Reset value if requested.
- if ($button_type) {
- $_workflow_use_actions_buttons = $button_type;
- }
- return $_workflow_use_actions_buttons;
- }
- /**
- * Implements hook_form_alter().
- *
- * Form builder. Move action buttons next to the 'Save'/'Delete' buttons.
- *
- * This is only used if the set the 'options widget' to 'action buttons'.
- * Do not use with multiple workflows per entity: confusing UX.
- * ATM this works for:
- * - Workflow Field: create, edit, view, workflow tab, comment;
- * - Workflow Node: view, workflow tab;
- * (For forms with Workflow Node, the form_alter() is AFTER formElement(). )
- *
- * @todo: move this to WorkflowTransitionForm::_addActionButtons();
- */
- function workflow_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
- // N.B. Keep code aligned: workflow_form_alter(), WorkflowTransitionForm::actions().
- // Use a fast, custom way to check if we need to do this.
- // @todo: Make this work with multiple workflows per entity.
- if (!_workflow_use_action_buttons()) {
- return;
- }
- if (isset($form_state->getBuildInfo()['base_form_id']) && $form_state->getBuildInfo()['base_form_id'] == 'workflow_transition_form') {
- // The WorkflowTransitionForm::actions() has its own handling.
- // E.g., Workflow History tab, Block.
- return;
- }
- // Find the first workflow.
- // (So this won't work with multiple workflows per entity.)
- $workflow_element = _workflow_transition_form_get_first_workflow_element($form);
- // Quit if there is no Workflow on this page.
- if (!$workflow_element ) {
- return;
- }
- // Quit if there are no Workflow Action buttons.
- // (If user has only 1 workflow option, there are no Action buttons.)
- if (count($workflow_element['to_sid']['#options']) <= 1) {
- return;
- }
- // Find the default submit button and replace with our own action buttons.
- if (isset($form['actions']['submit'])) {
- $default_submit_action = $form['actions']['submit'];
- // @todo D8-port: on Node-form, this is not sufficient.
- unset($form['actions']['submit']);
- }
- elseif (isset($form['actions']['save'])) {
- $default_submit_action = $form['actions']['save'];
- unset($form['actions']['save']);
- }
- else {
- // @todo test: when does this happen?
- $default_submit_action = [];
- }
- if (isset($default_submit_action)) {
- $actions = _workflow_transition_form_get_action_buttons($form, $workflow_element, $default_submit_action);
- // Place the button with the other action buttons.
- $form['actions'] = isset($form['actions']) ? $form['actions'] : [];
- $form['actions'] += $actions;
- }
- }
- /**
- * Fetches the first workflow_element from one of the Workflow Fields.
- *
- * @param array $form
- *
- * @return array
- */
- function _workflow_transition_form_get_first_workflow_element(&$form) {
- $workflow_element = [];
- // Find the first workflow.
- // (So this won't work with multiple workflows per entity.)
- foreach (\Drupal\Core\Render\Element::children($form) as $key) {
- if (isset($form[$key]['widget'][0]['#default_value'])) {
- $transition = $form[$key]['widget'][0]['#default_value'];
- if (is_object($transition) && $transition instanceof WorkflowTransitionInterface ) {
- $workflow_element = $form[$key]['widget'][0];
- break;
- }
- }
- }
- return $workflow_element;
- }
- /**
- * Returns the action buttons from the options widget.
- *
- * @param array $form
- * @param array $workflow_element
- * @param array $default_submit_action
- *
- * @return array $actions
- */
- function _workflow_transition_form_get_action_buttons(array $form, array $workflow_element, array $default_submit_action) {
- $actions = [];
- $current_sid = $workflow_element['to_sid']['#default_value'];
- /* @var $transition WorkflowTransitionInterface */
- $transition = $workflow_element['workflow_transition']['#value'];
- $field_name = $transition->getFieldName();
- // Find the default submit button and add our action buttons before it.
- // Get the min weight for our buttons.
- $option_weight = isset($default_submit_action['#weight']) ? $default_submit_action['#weight'] : 0;
- $option_weight = $option_weight - count($workflow_element['to_sid']['#options']);
- $min_weight = $option_weight;
- foreach ($workflow_element['to_sid']['#options'] as $sid => $option_name) {
- // Make the workflow button act exactly like the original submit button.
- $same_state_button = ($sid == $current_sid);
- $workflow_submit_action = $default_submit_action;
- // Add target State ID and Field name, to set correct value in validate_buttons callback.
- $workflow_submit_action['#workflow'] = [
- 'field_name' => $field_name,
- 'to_sid' => $sid,
- ];
- // Keep option order. Put current state first.
- $workflow_submit_action['#weight'] = ($same_state_button) ? $min_weight : ++$option_weight;
- // Add/Overwrite some other settings.
- $workflow_submit_action['#access'] = TRUE;
- $workflow_submit_action['#value'] = $option_name;
- // Use one drop button, instead of several action buttons.
- if ('dropbutton' == _workflow_use_action_buttons()) {
- $workflow_submit_action['#dropbutton'] = 'save';
- }
- $workflow_submit_action['#attributes'] = ($same_state_button) ? ['class' => ['form-save-default-button']] : [];
- $workflow_submit_action['#button_type'] = ($same_state_button) ? 'primary' : ''; // @todo: works for node form and workflow tab, not for workflow block.
- //$workflow_submit_action['#executes_submit_callback'] = TRUE;
- // Add class to workflow button.
- $workflow_submit_action['#attributes']['class'][] = Html::getClass('workflow_button_' . $option_name);
- // Append the form's #validate function, or it won't be called upon submit,
- // because the workflow buttons have its own #validate.
- $workflow_submit_action['#validate'] = [];
- $workflow_submit_action['#validate'][] = '_workflow_transition_form_validate_buttons';
- if (isset($default_submit_action['#validate'])) {
- $workflow_submit_action['#validate'] = $default_submit_action['#validate'];
- }
- elseif (isset($form['#validate'])) {
- $workflow_submit_action['#validate'] = $form['#validate'];
- }
- // Append the submit-buttons's #submit function, or it won't be called upon submit.
- if (isset($default_submit_action['#submit'])) {
- $workflow_submit_action['#submit'] = $default_submit_action['#submit'];
- }
- elseif (isset($form['#submit'])) {
- $workflow_submit_action['#submit'] = $form['#submit'];
- }
- // Hide the same-state button in some cases.
- if ($same_state_button) {
- if (isset($form['#form_id']) && substr($form['#form_id'], 0, 24) == 'workflow_transition_form') {
- // Hide same-state-button on the transition-form (that is:
- // view page or workflow history tab) if there is nothing to do.
- // However, a Transition may be fieldable (have attached fields).
- if ($form['comment']['#access'] == FALSE) {
- $workflow_submit_action['#access'] = FALSE;
- }
- }
- elseif (isset($form['#id']) && $form['#id'] == 'comment-form') {
- // On comment-form, the button must stay, since you can comment to same state.
- }
- else {
- // On a entity edit page, the button must stay.
- }
- }
- // Place the button with the other action buttons.
- $actions['workflow_' . $sid] = $workflow_submit_action;
- }
- return $actions;
- }
- /**
- * Get the Workflow parameter from the button, pressed by the user.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * The form state.
- * @return array
- * A $field_name => $to_sid array.
- */
- function _workflow_transition_form_get_triggering_button(\Drupal\Core\Form\FormStateInterface $form_state) {
- $result = ['field_name' => '', 'to_sid' => ''];
- $triggering_element = $form_state->getTriggeringElement();
- if (isset($triggering_element['#workflow'])) {
- $result['field_name'] = $triggering_element['#workflow']['field_name'];
- $result['to_sid'] = $triggering_element['#workflow']['to_sid'];
- }
- return $result;
- }
- /**
- * Submit callback function for the Workflow Form / DefaultWidget.
- *
- * Validate form data for 'time' element.
- * @param $element
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * @param $form
- */
- function _workflow_transition_form_element_validate_time($element, \Drupal\Core\Form\FormStateInterface &$form_state, $form) {
- if (!strtotime($element['#value'])) {
- $form_state->setError($element, t('Please enter a valid value for time.'));
- }
- }
- /**
- * Submit callback function for the Workflow Form / DefaultWidget.
- *
- * This is only used when using action buttons in the widget.
- * It sets the new state to proper
- * element and sets a submit function if needed, making sure the action is
- * executed, influencing function core/includes/form.inc/form_execute_handlers().
- * (While constructing the Workflow form, we were not yet aware of the submit
- * buttons of the complete form. We try to correct this here, without adding
- * another hook_form_alter. We guess the first button is the Save button.
- */
- function _workflow_transition_form_validate_buttons($form, \Drupal\Core\Form\FormStateInterface &$form_state) {
- // Retrieve the data from the form.
- $transition = $form_state->getValue('workflow_transition');
- if ($transition) {
- // On WorkflowTransitionForm :
- // D7: $form_state['input']['to_sid'] = $new_sid;
- // D7: $form_state['values'][$field_name][$langcode][0]['to_sid'] = $new_sid;
- $values = $form_state->getValues();
- $to_sid = $form_state->getTriggeringElement()['#workflow']['to_sid'];
- $values['to_sid'] = $to_sid;
- // Update the form_state.
- $form_state->setValues($values);
- }
- else {
- // On edit form : See $form_state->getTriggeringElement() in WorkflowDefaultWidget;
- }
- }
|