Webforms and integration with third party services

16/09/2021
Webforms and integration with third party services

Introduction

If you work with Drupal as a developer (as programmers as site builders), content manager or a merely fan of Drupal, surely you already know the Webform module. For those who don't know about this I will quote the own description of the module: “The Webform module allows you to create any type of form to collect any type of data that can be sent to any application or system. Every behavior or aspect of this form and his inputs are customizable. Whether you need a form of several pages that contains an input design of several columns with conditional logic or a form of mere contact that sends data to SalesForce/CRM. All of this is possible using the Webform module for Drupal 8/9”.

The solution we are going to explain in this post exploits one of the many features of the Webform module, the integration with third parties. That is, we are going to implement this solution to, using a Webform, connect to an external API to query information and whose input parameters will be entered through the form fields, without having to program the whole form, including validations, submission logic, etc. At the same time, we can use this functionality to configure calls to different API services without having to reprogram anything.

Integration with third party services

To perform the integration with third parties we are going to make use of two hooks provided by the Webform module API:

hook_webform_third_party_settings_form_alter

This hook is used to alter the configuration form of a webform in order to add the configuration elements we want in a new section called 'Third Party Settings' for that webform. It is worth noting that when using this hook, which is apparently similar to hook_form_alter, not only the form is altered, but also there is no need to manage the saving of the data, that is, automatically, when sending the configuration form, the information is saved in the database, so that when exporting the webform configuration to its corresponding .yml file, our custom configuration fields will also be included. This greatly simplifies the task.

hook_webform_submission_form_alter

This hook is used to alter the webform itself that we are creating. In our case we will use it to add a custom submit function to replace the default webforms submit functions, as we don't want to register the submission in the webform, but just consume an API and display the result on the screen.

Example

In our example case we have an API with several services available and where all of them accept two input parameters that can be the same or different. One of them could be the following:

Service URL: https://mybussines.com/api/v2/getEmployeeData
Service parameters:
- employeeNumber -> type string
- employeeDepartment -> type string

Creating the webform

We will create a webform with two fields, one for each parameter required by the service we are going to query.

Webforms and integration with third party services - Image 1

Alter the webform configuration form to add our third-party integration configuration

Programmatically using the hook_webform_third_party_settings_form_alter we are going to alter the settings to add these fields:
- Service URL
- input parameters matching

So this configuration will now be available for all the forms we create, and we can configure it for each one individually, so that by changing the url of the service and the mapping of the parameters of our webform with the parameters of the service, we can link each form to a different service. For example:

/**
 * Implements hook_webform_third_party_settings_form_alter().
 */
function my_custom_module_webform_third_party_settings_form_alter(array &$form, FormStateInterface $form_state) {
  // Define max input params or get for configuration previously created.
  $max_input_params = 2;

  // Load current webform entity and his third party settings.
  $webform = $form_state->getFormObject()->getEntity();
  $third_party_settings = $webform->getThirdPartySettings('api_settings');

  $form['third_party_settings']['api_settings']['api_service_url'] = [
    '#type' => 'textfield',
    '#title' => t('API service url'),
    '#default_value' => isset($third_party_settings['api_service_url']) ? $third_party_settings['api_service_url'] : '',
    '#maxlength' => 255,
    '#weight' => 1,
  ];

  $form['third_party_settings']['api_settings']['params'] = [
    '#type' => 'fieldset',
    '#title' => t('API parameters mapping'),
    '#weight' => 3,
  ];

  for ($i=1; $i<=$max_input_params; $i++) {
    $form['third_party_settings']['api_settings']['params']['param' . $i] = [
      '#type' => 'fieldset',
      '#title' => t('Parameter %i', ['%i' => $i]),
    ];

    $form['third_party_settings']['api_settings']['params']['param' . $i]['ws_param_webform_field'] = [
      '#type' => 'textfield',
      '#title' => t('Webform field machine name'),
      '#default_value' => isset($third_party_settings['params']['param' . $i]['ws_param_webform_field']) ? $third_party_settings['params']['param' . $i]['ws_param_webform_field'] : '',
      '#maxlength' => 255
    ];

    $form['third_party_settings']['api_settings']['params']['param' . $i]['ws_param_ws_parameter'] = [
      '#type' => 'textfield',
      '#title' => t('API service parameter name'),
      '#default_value' => isset($third_party_settings['params']['param' . $i]['ws_param_ws_parameter']) ? $third_party_settings['params']['param' . $i]['ws_param_ws_parameter'] : '',
      '#maxlength' => 255
    ];
  }
}

And as a result we will have this new section (Third Party Settings) in the configuration section of the webform:

Webforms and integration with third party services - Image 2

Alter our webform to add a customised submit to it

Using the hook_webform_submission_form_alter we are going to alter our form to add a custom submit function where the call to the configured service will be executed and it will take as input parameters the values we introduce in the form.

Hook:

/**
 * Implements hook_webform_submission_form_alter().
 */
function my_custom_module_webform_submission_form_alter(array &$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  // Load current webform entity and his third party settings.
  $webform = Drupal::entityTypeManager()->getStorage('webform')->load($form['#webform_id']);
  $third_party_settings = $webform->getThirdPartySettings('api_settings');

  // Replace original submits for custom submit.
  if (isset($third_party_settings) && !empty($third_party_settings)) {
    $form['actions']['submit']['#submit'] = ['_my_custom_module_webform_submission_form_submit'];
  }
}

Custom submit function:

/**
 * Send API call in custom submit.
 *
 * @param array $form
 *   The form that will be altered.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   FormState Object.
 */
function _my_custom_module_webform_submission_form_submit(array &$form, FormStateInterface &$form_state) {
  // Load current webform entity and his third party settings.
  $webform = Drupal::entityTypeManager()->getStorage('webform')->load($form['#webform_id']);
  $third_party_settings = $webform->getThirdPartySettings('api_settings');

  // Set and format input parameters.
  $values = $form_state->getValues();
  $api_service_url = $third_party_settings['api_service_url'];
  $api_service_params = [];

  foreach ($third_party_settings['params'] as $param) {
    $api_service_params[$param['ws_param_ws_parameter']] = $values[$param['ws_param_webform_field']];
  }

  // TODO: API web service call...
  //  $result = ...

  if ($result = 'OK') {
    // Get the private tempstore factory, inject this in your form, controller
    // or service.
    $tempstore = Drupal::service('tempstore.private');
    // Get the store collection.
    $store = $tempstore->get('my_custom_module_collection');
    // Set the key/value pair.
    $store->set('data', $response['data']);

    // Redirect to custom results page.
    $form_state->setRedirect('my_custom_module.results_page');
  }
  else {
    Drupal::messenger()->addMessage(t('Error: ...'), MessengerInterface::TYPE_ERROR);
  }
}

Service settings and fields mapping

Webforms and integration with third party services - Image 3

Once we have this set up, we can make a submission in the webform we have created, which will call the API service and return a result that we will display in a custom page.