Webforms e integración con terceros

16/09/2021
Webforms e integraciones de terceros

Introducción

Seguramente si sois desarrolladores de sitios web en Drupal, tanto programadores como site builders, gestores de contenido o simplemente aficionados a Drupal, conoceréis el módulo Webform. Para quien no lo conozca citaré la propia descripción del módulo: “El módulo Webform le permite crear cualquier tipo de formulario para recopilar cualquier tipo de datos, que se pueden enviar a cualquier aplicación o sistema. Cada comportamiento y aspecto de sus formularios y sus entradas son personalizables. Ya sea que necesite un formulario de varias páginas que contenga un diseño de entrada de varias columnas con lógica condicional o un formulario de contacto simple que envíe datos a SalesForce / CRM, todo es posible utilizando el módulo Webform para Drupal 8/9.”.

La solución que vamos a explicar en este post explota una de las muchas características del módulo Webform, la integración con terceros. Esto es, vamos a implementar dicha solución para, usando un formulario web creado con Webform, conectarnos a una API externa para consumir información y cuyos parámetros de entrada serán introducidos a través de los campos del formulario, sin necesidad de tener que programar el formulario completo, incluidas validaciones, lógica del envío, etc. A su vez, podremos usar esta funcionalidad para configurar llamadas a diferentes servicios de la API sin necesidad de volver a programar nada.

Integración con terceros

Para realizar la integración con terceros vamos a hacer uso de dos hooks proporcionados por la api del módulo Webform:

hook_webform_third_party_settings_form_alter

Usado para alterar el formulario de configuración de un webform y así poder añadir los elementos de configuración que deseemos en una nueva sección llamada ‘Third Party Settings’ para ese webform. Cabe destacar que cuando se usa este hook, que aparentemente es similar al hook_form_alter, no sólo se altera el formulario, sino que además no hay que gestionar el guardado de los datos, es decir, de manera automática, al enviar dicho formulario de configuración se guarda la información en la base de datos, de manera que al exportar la configuración del webform a su correspondiente fichero .yml, nuestros campos personalizados de configuración también estarán incluidos. Esto simplifica mucho la tarea.

hook_webform_submission_form_alter

Usado para alterar el propio webform que estamos creando. En nuestro caso lo usaremos para añadir una función de submit personalizada que sustituya a las funciones de submit por defecto de webforms, ya que no queremos que se registre el envío en el webform, si no solo consumir una API y mostrar el resultado por pantalla.

Ejemplo práctico

En nuestro caso de ejemplo tenemos una API con varios servicios disponibles y en la que todos ellos aceptan dos parámetros de entrada que pueden ser iguales o diferentes. Uno de ellos podría ser el siguiente:

Url del servicio: https://mybussines.com/api/v2/getEmployeeData
Parámetros del servicio:
- employeeNumber -> type string
- employeeDepartment -> type string

Crear webform

Crearemos un webform con dos campos, uno para cada parámetro requerido por el servicio que vamos a consumir.

Webforms e integración con terceros - Imagen 1

Alterar el formulario de configuración de webform para añadir la configuración de nuestra integración con terceros

Programáticamente y usando el hook_webform_third_party_settings_form_alter vamos a alterar la configuración para añadir los siguientes campos:
- URL del servicio
- mapeo de parámetros de entrada

De manera que esta configuración ahora estará disponible para todos los formularios que creemos, y podremos configurarla para cada uno individualmente, de modo que cambiando la url del servicio y el mapeo de los parámetros de nuestro webform con los parámetros del servicio, podemos vincular cada formulario a un servicio diferente. Por ejemplo:

/**
 * 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
    ];
  }
}

Y como resultado tendremos esta nueva sección (Third Party Settings) en el apartado de configuración del webform:

Webforms e integración con terceros - Imagen 2

Alterar nuestro webform para añadirle un submit personalizado

Haciendo uso del hook_webform_submission_form_alter vamos a alterar nuestro formulario para añadir una función submit personalizada en donde se ejecutará la llamada al servicio  configurado y que tomará como parámetros de entrada los valores que introduzcamos en formulario.

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'];
  }
}

Submit personalizado:

/**
 * 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);
  }
}

Configurar el servicio y el mapeo de campos

Webforms e integración con terceros - Imagen 3

Una vez que tengamos esto configurado ya podemos realizar un envío en el webform que hemos creado, el cual llamará al servicio de la API y nos devolverá un resultado que mostraremos en una página personalizada.