You are here

rules_webform.module in RULES WEBFORM 8

Same filename and directory in other branches
  1. 3.x rules_webform.module

File

rules_webform.module
View source
<?php

/**
 * @file
 * Contains rules_webform.module.
 */
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\rules_webform\Event\WebformSubmitEvent;
use Drupal\rules_webform\Event\UpdatingSubmissionEvent;
use Drupal\rules_webform\Event\DeletingSubmissionEvent;
use Drupal\rules_webform\Event\ViewingSubmissionEvent;
use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\Entity\Webform;
use Drupal\rules\Context\ContextConfig;
use Drupal\webform\Entity\WebformSubmission;

/**
 * Add the element for a 'Webform id' selection to the rule adding form.
 *
 * Implements hook_form_FORM_ID_alter().
 */
function rules_webform_form_rules_reaction_rule_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  // Create the element for a webform selection and hide it and its label.
  // It will made visible with JS if a user selects any web form event.
  $form['selection']['webform_id'] = [
    '#type' => 'select',
    '#title' => t('Webform'),
    '#empty_option' => t('- Select -'),
    '#attributes' => [
      'style' => 'display: none;',
    ],
    '#label_attributes' => [
      'style' => 'display: none;',
    ],
  ];
  $form['#attached']['library'][] = 'rules_webform/rules_webform.select_webform_id';
  $query = \Drupal::service('entity.query')
    ->get('webform');
  $webform_ids = $query
    ->execute();
  $webforms = Webform::loadMultiple($webform_ids);
  foreach ($webforms as $webform) {
    $form['selection']['webform_id']['#options'][$webform
      ->get('id')] = $webform
      ->get('title');
  }

  // Remove default Webform submission events from the list.
  unset($form['selection']['events'][0]['event_name']['#options']['Webform submission']);
  $form['actions']['submit']['#submit'][] = 'rules_webform_check_if_webform_submit_event_selected';
}

/**
 * Check if Webform events selected.
 *
 * And if so then adding the 'webform_fields' properties definitions
 * to the context variable and adding 'webform_name' condition.
 */
function rules_webform_check_if_webform_submit_event_selected($form, FormStateInterface $form_state) {
  $event_name = $form_state
    ->getValue('events')[0]['event_name'];

  // Events supported by the module.
  $webform_events = [
    'webform_submit',
    'updating_submission',
    'deleting_submission',
    'viewing_submission',
  ];
  if (in_array($event_name, $webform_events)) {
    rules_webform_store_webform_id($form, $form_state);
    rules_webform_add_condition($form, $form_state);
    rules_webform_save_rule($form, $form_state);
  }
}

/**
 * Add the 'webform_fields' properties definitions to the context variable.
 */
function rules_webform_store_webform_id($form, FormStateInterface $form_state) {
  $webform_id = $form_state
    ->getValue('webform_id');
  if (!empty($webform_id)) {
    $reaction_rule = $form_state
      ->getFormObject()
      ->getEntity();

    // Store webform id, it will be then using in the following hook:
    // 'rules_webform_form_rules_reaction_rule_edit_form_alter()'.
    // For storing we use state instead of setThirdPartySetting().
    // It enables reinstall the module and continue to using rules
    // that use this module.
    $rule_id = $reaction_rule->id;
    \Drupal::state()
      ->set('rules_webform.webform_id.' . $rule_id, $webform_id);
    \Drupal::state()
      ->get('rules_webform.webform_id.' . $rule_id);
  }
}

/**
 * Add rule condition 'webform_name' based on selected webform id.
 */
function rules_webform_add_condition($form, FormStateInterface $form_state) {
  $selected_webform_id = $form_state
    ->getValue('webform_id');
  $values = [];
  $values['context_values'] = [
    'selected_webform_id' => $selected_webform_id,
  ];

  // Submitted webform ID will be extracted from webform_info context variable.
  // And then will be using for compare selected and submitted webform
  // in 'webform_name' condition.
  $values['context_mapping']['submitted_webform_info'] = 'webform_info';
  $values['provides_mapping'] = [];
  $values['condition_id'] = 'webform_name';
  $values['negate'] = 0;
  $config = ContextConfig::create($values);
  $entity = $form_state
    ->getFormObject()
    ->getEntity();
  $component = $entity
    ->getComponent();
  $component
    ->getExpression()
    ->addCondition('webform_name', $config);
  $entity
    ->updateFromComponent($component);
}

/**
 * Save changes in the Rule after storing webform_id and adding the condition.
 */
function rules_webform_save_rule($form, FormStateInterface $form_state) {
  $form_state
    ->getFormObject()
    ->getEntity()
    ->save();
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * 1. Hiding our condition ('webform_name'), that user don't distracted on it.
 * 2. If the 'Delete webform submission' action was added, then remove the
 *    'Edit' operation link, because a user doesn't have to edit this action.
 * 3. Add to a condition title a webform title, that a user can see which a
 *    webform has been selected.
 */
function rules_webform_form_rules_reaction_rule_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $reaction_rule = $form_state
    ->getFormObject()
    ->getEntity();
  $event_name = $reaction_rule
    ->getEventNames()[0];

  // Events supported by the module.
  $webform_events = [
    'webform_submit',
    'updating_submission',
    'deleting_submission',
    'viewing_submission',
  ];
  if (!in_array($event_name, $webform_events)) {
    return;
  }
  $rule_id = $reaction_rule->id;
  $webform_id = \Drupal::state()
    ->get('rules_webform.webform_id.' . $rule_id);
  $webform = Webform::load($webform_id);

  // Hiding our condition ('webform_name'), that user don't distracted on it.
  foreach ($form['conditions-table']['conditions'] as $key => $value) {
    if (is_array($value) && isset($value['element']) && is_array($value['element']) && isset($value['element']['data']) && is_array($value['element']['data'])) {
      if (isset($value['element']['data']['#plain_text']) && get_class($value['element']['data']['#plain_text']) == 'Drupal\\Core\\StringTranslation\\TranslatableMarkup' && $value['element']['data']['#plain_text']
        ->__toString() == 'Webform name') {
        unset($form['conditions-table']['conditions'][$key]);
      }
    }
  }

  // If the 'Delete webform submission' action was added then
  // remove the 'Edit' operation link, because a user doesn't have to edit it.
  foreach ($form['actions-table']['actions'] as $key => $value) {
    if (is_array($value) && isset($value['element']) && is_array($value['element']) && isset($value['element']['data']) && is_array($value['element']['data'])) {
      if (isset($value['element']['data']['#plain_text']) && get_class($value['element']['data']['#plain_text']) == 'Drupal\\Core\\StringTranslation\\TranslatableMarkup' && $value['element']['data']['#plain_text']
        ->__toString() == 'Delete webform submission') {
        unset($form['actions-table']['actions'][$key]['operations']['data']['#links']['edit']);
      }
    }
  }

  // Add webform title to the event title that user can see which a webform
  // has been selected.
  $webform_title = $webform
    ->get('title');
  $form['event'][0]['#title'] = t('Event:');
  switch ($event_name) {
    case 'webform_submit':
      $event_title = t('Webform "@title" submit', [
        '@title' => $webform_title,
      ]);
      break;
    case 'updating_submission':
      $event_title = t('Updating a submission of the "@title" webform', [
        '@title' => $webform_title,
      ]);
      break;
    case 'deleting_submission':
      $event_title = t('Deleting a submission of the "@title" webform', [
        '@title' => $webform_title,
      ]);
      break;
    case 'viewing_submission':
      $event_title = t('Viewing a submission of the "@title" webform', [
        '@title' => $webform_title,
      ]);
  }
  $form['events']['table']['#rows'][0]['element']['data']['#plain_text'] = $event_title;

  // Removing 'Edit' button for 'Delete webform submission' action because
  // there is nothing to edit.
  if (isset($form['action_table']['table']['#rows'])) {
    foreach ($form['action_table']['table']['#rows'] as &$row) {
      if ($row['element']
        ->render() == 'Action: Delete webform submission') {
        unset($row['operations']['data']['#links']['edit']);
        break;
      }
    }
    unset($row);
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Add the 'webform_fields' properties definitions to the context variable.
 * The information are then using in the 'WebformFieldsDataDefinition' class
 * and in the 'WebformFieldsUnchangedDataDefinition' class.
 * And it's needed for autocomplete of properties of 'webform_fields' context
 * variable and the 'webform_fields_unchanged' context variable.
 * Also, removing default 'Webform submission' action from the Action
 * selection list. And also removing condition 'webform name from the condition
 * list, because it set programmatically by default. The module doesn't work
 * with Rules components (actions and variables are not available).
 * Therefore if this hook was called when a user edit a Rule component then
 * hide related actions and condition.
 */
function rules_webform_form_rules_expression_edit_alter(&$form, FormStateInterface $form_state, $form_id) {
  $reaction_rule = \Drupal::request()
    ->get('rules_reaction_rule');

  // If this hook was called when a user edit a Rule component then hide
  // related actions and condition.
  // The module doesn't work with Rules components (actions and variables
  // are not available).
  if (is_null($reaction_rule)) {

    // Removing our actions 'Delete webform submission' and 'Set webform
    // field value' from the action list.
    unset($form['action_id']['#options']['A Webform']);

    // Removing our condition 'webform_name' from the condition list.
    unset($form['condition_id']['#options']['A Webform']);
    return;
  }
  $event_name = $reaction_rule
    ->getEventNames()[0];

  // Events supported by the module.
  $webform_events = [
    'webform_submit',
    'updating_submission',
    'deleting_submission',
    'viewing_submission',
  ];
  if (!in_array($event_name, $webform_events)) {

    // Removing our condition 'webform_name' from the condition list.
    unset($form['condition_id']['#options']['A Webform']);

    // Removing our actions because they are unuseful for other events.
    unset($form['action_id']['#options']['A Webform']);
    return;
  }

  // Removing default 'Webform submission' actions from the Action selection
  // list.
  unset($form['action_id']['#options']['Webform submission']);

  // Removing our condition 'webform name from the condition list, because it
  // set programmatically by default.
  unset($form['condition_id']['#options']['A Webform']);

  // Get the information about a webform fields.
  $rule_id = $reaction_rule->id;
  $webform_id = \Drupal::state()
    ->get('rules_webform.webform_id.' . $rule_id);
  $webform = Webform::load($webform_id);
  $elements = $webform
    ->getElementsInitializedAndFlattened();
  $fields_definitions = [];
  rules_webform_extract_composite_elements($elements, $fields_definitions);

  // Store webform fields information for using in the
  // 'WebformFieldsDataDefinition' class and in
  // the'WebformFieldsUnchangedDataDefinition' class.
  \Drupal::state()
    ->set('rules_webform.fields_definitions', $fields_definitions);

  // If this is the form of 'set_webform_field_value' action
  // then store event name.
  if (isset($form_state
    ->getStorage()['action_id'])) {
    if ($form_state
      ->getStorage()['action_id'] == 'set_webform_field_value') {

      // Store 'event_name' for using in "set_webform_field_value" action.
      $form['context_definitions']['event_name']['setting']['#default_value'] = $event_name;
      $form['context_definitions']['event_name']['#access'] = FALSE;
    }
  }

  // If this is add 'Action' form then alter it.
  if (isset($form['action_id'])) {

    // If event is 'Deleting a submission' then remove 'Deleting a submission'
    // and 'Set webform field value' actions.
    if ($event_name == 'deleting_submission') {
      unset($form['action_id']['#options']['A Webform']);
    }

    // Add validate handler to add and setup 'delete_webform_submission'
    // action if user will select it.
    $form['continue']['#validate'] = [
      'rules_webform_form_rules_expression_edit_validate',
    ];
  }
}

/**
 * Adding submit handler for adding rule actions.
 *
 * Adding submit handler for adding 'delete_webform_submission' action
 * if a user will select it.
 */
function rules_webform_form_rules_expression_edit_validate($form, FormStateInterface $form_state) {
  if ($form_state
    ->getValue('action_id') == 'delete_webform_submission') {
    $form_state
      ->setSubmitHandlers([
      'rules_webform_add_action_delete_webform_submission',
    ]);
  }
  else {
    $form_state
      ->setSubmitHandlers([
      'Drupal\\rules\\Form\\Expression\\ActionForm::submitFirstStep',
    ]);
  }
}

/**
 * Adding 'Delete webform submission' action if a user selected it.
 */
function rules_webform_add_action_delete_webform_submission($form, FormStateInterface $form_state) {
  $values = [];
  $values['context_mapping']['webform_info'] = 'webform_info';
  $values['provides_mapping'] = [];
  $values['action_id'] = 'delete_webform_submission';
  $values['negate'] = 0;
  $config = ContextConfig::create($values);
  $reaction_rule = \Drupal::request()
    ->get('rules_reaction_rule');
  $component = $reaction_rule
    ->getComponent();

  // Check if this action was already added then don't add it again.
  $actions = $component
    ->getExpression()
    ->getActions()
    ->getConfiguration()['actions'];
  foreach ($actions as $action) {
    if ($action['action_id'] == 'delete_webform_submission') {
      $form_state
        ->setRedirect('entity.rules_reaction_rule.edit_form', [
        'rules_reaction_rule' => $reaction_rule->id,
      ]);
      return;
    }
  }
  $component
    ->getExpression()
    ->addAction('delete_webform_submission', $config);
  $reaction_rule
    ->updateFromComponent($component);
  $reaction_rule
    ->save();
  $form_state
    ->setRedirect('entity.rules_reaction_rule.edit_form', [
    'rules_reaction_rule' => $reaction_rule->id,
  ]);
}

/**
 * Extract the information about a webform fields.
 *
 * This information will be used for fields data definition
 * in the 'WebformFieldsDataDefinition' class
 * and in the'WebformFieldsUnchangedDataDefinition' class.
 */
function rules_webform_extract_composite_elements(array $elements, array &$fields_definitions) {
  foreach ($elements as $name => $options) {
    if (isset($options['#webform_composite_elements'])) {
      rules_webform_extract_composite_elements($options['#webform_composite_elements'], $fields_definitions);
    }
    else {

      // Exclude wizard pages and buttons from the list of elements.
      if ($options['#type'] != 'webform_wizard_page' && $options['#type'] != "webform_actions") {
        $fields_definitions[$name] = (string) isset($options['#title']) ? $options['#title'] : '';
      }
    }
  }
}

/**
 * If a submission is new then fire 'Webform submit' rules event.
 *
 * Implements hook_ENTITY_TYPE_insert().
 */
function rules_webform_webform_submission_insert(WebformSubmission $submission) {
  $event = new WebformSubmitEvent($submission);
  \Drupal::service('event_dispatcher')
    ->dispatch($event::EVENT_NAME, $event);
}

/**
 * If a submission is not new then fire 'Updating a submission' rules event.
 *
 * Implements hook_ENTITY_TYPE_presave().
 */
function rules_webform_webform_submission_presave(WebformSubmission $submission) {
  if (!$submission
    ->isNew()) {
    $event = new UpdatingSubmissionEvent($submission);
    \Drupal::service('event_dispatcher')
      ->dispatch($event::EVENT_NAME, $event);
  }
}

/**
 * If a submission has been deleted then fire 'Delete a submission' rules event.
 *
 * Implements hook_ENTITY_TYPE_delete().
 */
function rules_webform_webform_submission_delete(WebformSubmission $submission) {
  $event = new DeletingSubmissionEvent($submission);
  \Drupal::service('event_dispatcher')
    ->dispatch($event::EVENT_NAME, $event);
}

/**
 * If a submission is viewing then fire 'Viewing a submission' rules event.
 *
 * Implements hook_ENTITY_TYPE_view().
 */
function rules_webform_webform_submission_view(array &$build, WebformSubmission $submission) {
  $event = new ViewingSubmissionEvent($submission);
  \Drupal::service('event_dispatcher')
    ->dispatch($event::EVENT_NAME, $event);
}

/**
 * Implements hook_help().
 */
function rules_webform_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {

    // Main module help for the rules_webform module.
    case 'help.page.rules_webform':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>';
      $output .= t("The 'Rules Webform' module provides integration of 'Rules' and 'Webform' modules.") . ' ';
      $output .= t('It enables site builders and administrators to get access to webform submission data from rules.');
      $output .= ' ';
      $output .= t('Also it provides possibility of altering and removing webform submissions from rules.');
      $output .= '</p>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<h4>' . t('Read a webform submission') . '</h4>';
      $output .= t('To access webform submission data from a rule you need to do two things:');
      $output .= '<ol>';
      $output .= '<li>' . t("Select the 'Webform submit' event from the 'React on event' listbox.") . '</li>';
      $output .= '<li>' . t("Select  necessary webform from the 'Webform' listbox that will appear below.") . '</li>';
      $output .= '</ol>';
      $output .= '<p>';
      $output .= t("After that will be available two new variables: 'webform_fields' and 'webform_info'.") . ' ';
      $output .= t('You can use them in your rule actions and conditions.') . ' ' . '<br/>';
      $output .= t("'webform_fields' contains values of webform fields and 'webform_info' contains") . ' ';
      $output .= t('additional information like submission date, author and so on.');
      $output .= '</p>';
      $output .= '<p>';
      $output .= t("To investigate them it's conveniently to use 'Data selection mode'.") . ' ';
      $output .= t("Therefore click on 'Switch to data selection mode' button in your condition or action page.") . ' ';
      $output .= t("Then type variable name with dot at the end, like this: 'webform_fields.'") . ' ';
      $output .= t('After that you will see all webform fields and you can choose any of them.') . ' ';
      $output .= t("But you can also use 'Direct input mode'.") . ' ';
      $output .= t("For instance, if you need to get the value of 'message' field you can use Twig syntax like this:");
      $output .= ' ';
      $output .= '{{&nbsp; webform_fields.message &nbsp;}}';
      $output .= '</p>';
      $output .= '<h4>' . t('Alter a webform submission') . '</h4>';
      $output .= '<p>';
      $output .= t("To alter a webform field value you need to do the following:");
      $output .= '</p>';
      $output .= '<p>';
      $output .= t("1. Add 'Set webform field value' action.");
      $output .= '</p>';
      $output .= '<p>';
      $output .= t('2. Select a webform field you want to alter.');
      $output .= '</br>';
      $output .= t("Keep in mind that it's possible to select a webform field only in 'Data selection' mode.");
      $output .= ' ';
      $output .= t("Therefore click on 'Switch to data selection' button before you start typing.");
      $output .= ' ';
      $output .= t('Then type the name of a necessary webfrom field.');
      $output .= ' ';
      $output .= t("For instance, if you want to alter the value of 'message' field, type the following:");
      $output .= '</br>';
      $output .= ' webform_fields.message';
      $output .= '<p>';
      $output .= t("3. Input a new value of webform field into the 'VALUE' field.");
      $output .= '</br>';
      $output .= t('Remember that you can completely replace field value as well as to complement existing value.');
      $output .= ' ';
      $output .= t("Let's say you want to complement the value of field 'name' with 'Sir'.");
      $output .= ' ';
      $output .= t("Then stay in the 'Direct input' mode and type the following:");
      $output .= '</br>';
      $output .= 'Sir {{ webform_field.name }}';
      $output .= '</p>';
      $output .= '<h4>' . t('Delete a webform submission') . '</h4>';
      $output .= '<p>';
      $output .= t("To delete a webform submission from a rule use 'Delete webform submission' action.");
      $output .= '</p>';
      $output .= '<h3>' . t('Known issues') . '</h3>';
      $output .= '<p>';
      $output .= t("Before adding 'Delete webform submission' action ensure that you save previous changes of your rule");
      $output .= ' (';
      $output .= t("click on 'Save' button");
      $output .= ').';
      $output .= '</p>';
      return $output;
  }
}

Functions

Namesort descending Description
rules_webform_add_action_delete_webform_submission Adding 'Delete webform submission' action if a user selected it.
rules_webform_add_condition Add rule condition 'webform_name' based on selected webform id.
rules_webform_check_if_webform_submit_event_selected Check if Webform events selected.
rules_webform_extract_composite_elements Extract the information about a webform fields.
rules_webform_form_rules_expression_edit_alter Implements hook_form_FORM_ID_alter().
rules_webform_form_rules_expression_edit_validate Adding submit handler for adding rule actions.
rules_webform_form_rules_reaction_rule_add_form_alter Add the element for a 'Webform id' selection to the rule adding form.
rules_webform_form_rules_reaction_rule_edit_form_alter Implements hook_form_FORM_ID_alter().
rules_webform_help Implements hook_help().
rules_webform_save_rule Save changes in the Rule after storing webform_id and adding the condition.
rules_webform_store_webform_id Add the 'webform_fields' properties definitions to the context variable.
rules_webform_webform_submission_delete If a submission has been deleted then fire 'Delete a submission' rules event.
rules_webform_webform_submission_insert If a submission is new then fire 'Webform submit' rules event.
rules_webform_webform_submission_presave If a submission is not new then fire 'Updating a submission' rules event.
rules_webform_webform_submission_view If a submission is viewing then fire 'Viewing a submission' rules event.