Allow custom form fields in confirmation form

Created on 10 March 2021, over 3 years ago
Updated 15 January 2024, 11 months ago

Problem/Motivation

We need bulk change purchased product variation references to a new one, to do this we need to select other product variation after selecting the required order items.

Steps to reproduce

Create a new VBO Action plugin to update order items.
Create a view to select order items to update.
How we can select the new product variation to set?

In our use case, we can ignore things like price differences, etc.

Proposed resolution

A solution could be to allow Action plugins to extend the confirmation form to add custom fields.

For example:

And a Action plugin like this:


namespace Drupal\custom_module_commerce\Plugin\Action;

use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\views_bulk_operations\Action\ViewsBulkOperationsActionBase;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Delete entity action with default confirmation form.
 *
 * @Action(
 *   id = "custom_module_commerce_order_item_update",
 *   label = @Translation("Update order call"),
 *   type = "commerce_order_item",
 *   confirm = TRUE,
 * )
 */
class OrderItemUpdateAction extends ViewsBulkOperationsActionBase implements ContainerFactoryPluginInterface {

  /**
   * Entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManager
   */
  protected $entityTypeManager;

  /**
   * Creates a ExampleBlock instance.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
   *   The optional dependency.
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    EntityTypeManager $entityTypeManager
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfirmationForm(array $form, FormStateInterface $form_state, array $form_data) {
    if ($form_data["selected_count"] > 0) {
      // Get the first order item to get the variation reference.

      $view = Views::getView($form_data["view_id"]);
      $view->setDisplay($form_data["display_id"]);
      if (!empty($form_data["arguments"])) {
        $view->setArguments($form_data["arguments"]);
      }
      $view->execute();
      /** @var \Drupal\views\ResultRow $firstResult */
      $firstResult = current($view->result);
      $entity = $firstResult->_entity;
      if ($entity->purchased_entity->count() > 0) {
        // Get variation product.
        $purchasedEntity = $entity->purchased_entity->first()->get('entity')->getTarget()->getValue();
        if ($purchasedEntity) {
          // And get the product.
          /** @var \Drupal\commerce_product\Entity\Product $product */
          $product = $purchasedEntity->product_id->first()->get('entity')->getTarget()->getValue();
          if ($product) {
            // Get all product variations.
            $variations = $product->getVariations();
            // And set variations how options, except the current one.
            $options = [];
            /** @var \Drupal\commerce_product\Entity\ProductVariation $variation */
            foreach ($variations as $variation) {
              if ($variation->isPublished() && $purchasedEntity->id() != $variation->id()) {
                $options[$variation->id()] = $variation->label();
              }
            }
            $form['target_call'] = [
              '#type' => 'select',
              '#title' => $this->t('Select target call'),
              '#options' => $options,
            ];
          }
        }

      }
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfirmationForm(array &$form, FormStateInterface $form_state) {
    // @todo: Validate selected purchased entity.
  }

  /**
   * {@inheritdoc}
   */
  public function execute($entity = NULL) {
    // @todo: Update the order item purchased entity with the target ID added to $this->pluginData.
  }

  /**
   * {@inheritdoc}
   */
  public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
    $access = $object->access('update', $account, TRUE);
    return $return_as_object ? $access : $access->isAllowed();
  }

}

Remaining tasks

  • Test each action plugins use case.

User interface changes

Each plugin can add custom fields to the confirmation form.

API changes

ViewsBulkOperationsActionBase class, and the interface, add buildConfirmationForm, validateConfirmationForm and setPluginData.
ConfirmAction class add an default validateForm method, and call to the new plugin methods when required.
ViewsBulkOperationsActionProcessor class expose a new setActionPluginData method to propagate plugin data while execution.

Data model changes

N/A

Feature request
Status

Active

Version

3.0

Component

Core

Created by

🇪🇸Spain psf_ Huelva

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024