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