🇩🇰Denmark @benjamin_dk

Account created on 11 November 2008, almost 16 years ago
#

Recent comments

🇩🇰Denmark benjamin_dk

To simplify things I have created a public repo with a module that illustrates the problem that led to all the complexity: The problem of the form storage not persisting across requests. This issue is also described here , I believe.

I think if I can get that issue fixed, the rest will fall into place.

Please ignore the above post for now.

🇩🇰Denmark benjamin_dk

Correcting a few typos.

🇩🇰Denmark benjamin_dk

A bit more context is probably helpful. We are using a Drupal service that interacts with an external API. Lets call it a CoffeeOrderService(). It fetches coffee orders from an external database.

The purpose of the form is to let a "waiter" user mark one or more of these orders as processed. They are fetched and listed in the modal form with checkboxes next to them. When an order is processed - by checking the checkbox and pressing submit - the external database is updated.

I quickly found it necessary to use a private TempStore to help keep track of the orders during the life cycle of the form. And as several waiters can potentially try to handle the same request simultaneously, we also have a few exciting edge cases that has led to complex and hard-to-debug code, including workaround logic in validateForm() as mentioned above.

It feels like we are stretching Drupals Ajax-in-forms-capabilities  beyond its intended use. Reading this SO post and this makes me think that we might be better of without the validation and handle those separately. This, I understand, should be possible with $form_state->setRebuild(true)?

Here is the #ajax from buildForm():

    // Add a submit button that handles the submission of the form.
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save'),
      '#name' => 'save_form',
      '#attributes' => [
        'class' => ['save-coffee-orders'],
        'disabled' => 'disabled',
      ],
      '#ajax' => [
        'callback' => '::ajaxSubmitForm',
        'event' => 'click',
        'wrapper' => 'coffee-orders-modal-form-wrapper', // wrapper element is updated with this AJAX callback.
        'progress' => [
          'type' => 'throbber',
          'message' => $this->t('Please wait...'),
        ],
      ],
    ];

Here is the callback:

  public function ajaxSubmitForm(array &$form, FormStateInterface $form_state) {
    // We begin building a new ajax reponse.
    $ajax_response = new AjaxResponse();

    // If the user submitted the form and there are errors, show them the
    // input dialog again with error messages. Since the title element is
    // required, the empty string wont't validate and there will be an error.
    if ( $form_state->getErrors() ) {
      // If there are errors, we can show the form again with the errors in
      // the status_messages section.
      $form['status_messages'] = [
        '#type' => 'status_messages',
        '#weight' => -10,
      ];
      $ajax_response->addCommand(new OpenModalDialogCommand(
        t('Error'),
        $form,
        static::getDataDialogOptions()
      ));
    }
    // If there are no validation errors, show the output dialog.
    else {
      // We don't want any messages that were added by submitForm().
      $this->messenger()->deleteAll();
      // The instance numbers of coffee orders that were successfully processed.
      $processed_items = [];
      // Fetch the coffee order instances and the customer user
      $stored_data = $form_state->getStorage();
      $customer = $stored_data['customer'];
      $coffee_orders = $stored_data['coffee_orders'];

      foreach ( $coffee_orders as $item ) {
        $instance = $item['coffee_order_instance'];
        if ( $form_state->getValue($instance) === 1 ) {
          // Attempt to process the coffee order
          try {
            $coffee_order_processed = $this->coffee_order_service
              ->markCoffeeOrderProcessed($customer, $instance);
            $response = $coffee_order_processed->getResponse();
            if ( $response && isset($response['error']) ) {
              $this->logger('my_module')
                ->error('There was an error processing the coffee order related to @_title',
                ['@_title' => $item['_title']],
                );
              $form_state->setError($form, t('Sorry, a coffee order could not be processed!'));
              continue;
            }
            $processed_items[] = $instance;
          }
          catch ( \Exception $e ) {
            $form_state->setError($form, $e->getMessage());
            $this->logger('my_module')->error($e->getMessage());
          }
        }
      }

      $processing_completed_message = t("You have marked %processed_items
      coffee orders as processed.", ['%processed_items' => count($processed_items)]);

      $content = [
        '#type' => 'item',
        '#markup' => $processing_completed_message,
      ];
      // Add the OpenModalDialogCommand to the response. This will cause Drupal
      // AJAX to show the modal dialog. The user can click the little X to close
      // the dialog.
      $options = static::getDataDialogOptions('30%', true);
      $ajax_response->addCommand(new OpenModalDialogCommand(
        t('Processing complete'),
        $content,
        $options,
      ));
      // Delete the tempstore data
      try {
        $tempstore = $this->temp_store_factory->get('coffee_orders');
        $tempstore->delete('coffee_orders');
      }
      catch ( \Exception $error ) {
        $this->logger('my_module')->error($error->getMessage());
      }
    }

    // Finally return our response.
    return $ajax_response;
  }
🇩🇰Denmark benjamin_dk

Add a note about the option of making the READ-COMMITTED setting persist.

🇩🇰Denmark benjamin_dk

I was unable to get the

transaction_isolation

setting to persist after reboot when using the command:

SET GLOBAL transaction_isolation='READ-COMMITTED';

However when using

SET PERSIST transaction_isolation = 'READ-COMMITTED';

 It persisted. Using mysql v8.2.0 on Linux.

https://stackoverflow.com/questions/7937472/how-to-set-transaction-isolation-level-mysql

🇩🇰Denmark benjamin_dk

Correcting a few typos.

Production build 0.71.5 2024