After more than half a year silence, this is now my third blog post within two days :)
This time I'm showing you, how you can automatically add another order item after a product has been added to the cart in Drupal Commerce 2.x. The most important info here is, how you can pass the pitfall of possible transient data problems here.
Prologue
Our use case was that our customer wanted to optionally sell warranty extensions with their products. The plan was to extend the add to cart form on the product page with a checkbox, which allows to add the warranty extension. Because this counts as an insurance and insurances are taxed especially in Austria and therefore VAT free, simply adding the amount to the product's order item was not a valid choice. We had to add extra order items for that. That would still have been possible to solve within a custom form submit callback. However, we prefer OOP based approaches, and so we just stored the info of checking the selection temporarliy and decided to react on this in an event subscriber later on. Commerce offers the CartEvents::CART_ENTITY_ADD event to react on the add to cart event.
Implement the event subscriber
I won't describe the basics of how to write an event subscriber in general here. The event we'll want to subscribe to is the \Drupal\commerce_cart\Event\CartEvents::CART_Entity_ADD and you'll receive an event of type \Drupal\commerce_cart\Event\CartEntityAddEvent. Let's assume we register a callback named addWarrantyExtension(). This would look like that:
/**
* Adds an warranty extension order item on add to cart event, if requested.
*
* @param \Drupal\commerce_cart\Event\CartEntityAddEvent $event
* The add to cart event.
*/
public function addWarrantyExtension(CartEntityAddEvent $event) {
$add_warranty_extension = doAnyCustomCheckWeNeedHere();
if (!$add_warranty_extension) {
return;
}
$my_custom_purchasable_entity = createTheWarrantyExtensionOrWhatever();
// Don't do it like that. This can cause problems - explained below in the post!
//$cart = $order_item->getOrder();
// This is the right way!
$cart = $event->getCart();
$my_order_item = $this->orderItemStorage->createFromPurchasableEntity($my_custom_purchasable_entity );
$my_order_item->set('order_id', $cart->id());
$my_order_item->save();
$cart->addItem($my_order_item);
}
This is a shortened outline about we have done. But the most interesting thing is already mentioned in the code's comments above:
Beware of transient data problems
The original version of our code didn't fetched the cart by using $event->getCart() - I've simply overseen that this getter exists, neverminded and used $order_item->getOrder() instead. At first glance, everything seems to work nicely, but literally the last tests before going live with this features showed us some problems.
What happened? Upon adding a product with checking the warranty extension, the cart showed the product only. On a closer look, I saw the order item with the warranty extension existed, but the order's order items field only contained the product. A few tries later I saw that this issue can be reproduced every time the order entity was created before within the same request. If the cart existed before the requested, no problem occured. I've took another close look and saw that the order within our event subscriber already had an ID though, but no order items were set at all - so the originally added product was missing. Upon save at last, the product was in the cart, but our warranty item was missing.
However, as soon as I have started to correctly use the getCart() function of the event to fetch the order entity, I was no more having any problem. The product was present within the event subscriber, and the additionally added warranty extension was still part of the cart upon visiting the cart page :)
Drupal Commerce ist eine flexible E-Commerce-Plattform auf Basis des Content-Management-Systems Drupal. Sie ermöglicht die Verwaltung von Produkten, Preisen, Bestellungen, Zahlungen und individuellen Verkaufsprozessen und lässt sich über Schnittstellen mit ERP-, CRM- oder Warenwirtschaftssystemen verbinden. Durch die modulare Architektur eignet sich Drupal Commerce besonders für komplexe Onlineshops und digitale Geschäftsmodelle mit individuellen Anforderungen.
Ein Event Subscriber ist eine Softwarekomponente, die sich gezielt für bestimmte Ereignisse (Events) registriert und bei deren Auslösung automatisch eine definierte Reaktion ausführt. In Drupal und dem Symfony Framework lassen sich damit beispielsweise Anfragen, Benutzeraktionen oder Änderungen an Inhalten zentral verarbeiten, ohne den bestehenden Anwendungscode direkt zu verändern. Das unterstützt eine modulare, wartbare und flexibel erweiterbare Systemarchitektur.
Ein Event Subscriber ist eine Softwarekomponente, die sich gezielt für bestimmte Ereignisse (Events) registriert und bei deren Auslösung automatisch eine definierte Reaktion ausführt. In Drupal und dem Symfony Framework lassen sich damit beispielsweise Anfragen, Benutzeraktionen oder Änderungen an Inhalten zentral verarbeiten, ohne den bestehenden Anwendungscode direkt zu verändern. Das unterstützt eine modulare, wartbare und flexibel erweiterbare Systemarchitektur.
Drupal ist ein leistungsfähiges, freies Content-Management-System (CMS) zur Erstellung und Verwaltung komplexer Websites, Portale und Webanwendungen. Die modular aufgebaute, auf PHP und Symfony-Komponenten basierende Plattform unterstützt individuelle Inhaltsstrukturen, mehrsprachige Websites, umfangreiche Benutzerrechte und die Anbindung externer Systeme über APIs. Dadurch eignet sich Drupal besonders für skalierbare Enterprise-Projekte mit hohen Anforderungen an Sicherheit, Performance und redaktionelle Prozesse.
Drupal ist ein leistungsfähiges, freies Content-Management-System (CMS) zur Erstellung und Verwaltung komplexer Websites, Portale und Webanwendungen. Die modular aufgebaute, auf PHP und Symfony-Komponenten basierende Plattform unterstützt individuelle Inhaltsstrukturen, mehrsprachige Websites, umfangreiche Benutzerrechte und die Anbindung externer Systeme über APIs. Dadurch eignet sich Drupal besonders für skalierbare Enterprise-Projekte mit hohen Anforderungen an Sicherheit, Performance und redaktionelle Prozesse.
Drupal ist ein leistungsfähiges, freies Content-Management-System (CMS) zur Erstellung und Verwaltung komplexer Websites, Portale und Webanwendungen. Die modular aufgebaute, auf PHP und Symfony-Komponenten basierende Plattform unterstützt individuelle Inhaltsstrukturen, mehrsprachige Websites, umfangreiche Benutzerrechte und die Anbindung externer Systeme über APIs. Dadurch eignet sich Drupal besonders für skalierbare Enterprise-Projekte mit hohen Anforderungen an Sicherheit, Performance und redaktionelle Prozesse.
Ein Event Subscriber ist eine Softwarekomponente, die sich gezielt für bestimmte Ereignisse (Events) registriert und bei deren Auslösung automatisch eine definierte Reaktion ausführt. In Drupal und dem Symfony Framework lassen sich damit beispielsweise Anfragen, Benutzeraktionen oder Änderungen an Inhalten zentral verarbeiten, ohne den bestehenden Anwendungscode direkt zu verändern. Das unterstützt eine modulare, wartbare und flexibel erweiterbare Systemarchitektur.
Eine Entity ist ein eindeutig identifizierbares, strukturiertes Datenobjekt innerhalb eines Softwaresystems. In Drupal werden beispielsweise Inhalte, Benutzerkonten, Medien und Taxonomiebegriffe als Entities verwaltet; sie besitzen eine eigene ID, definierte Felder und können über die Entity API bearbeitet sowie mit weiteren Systemen verknüpft werden. Dadurch lassen sich flexible und skalierbare Datenmodelle für Websites, Portale und Enterprise-Anwendungen umsetzen.
Ein Event Subscriber ist eine Softwarekomponente, die sich gezielt für bestimmte Ereignisse (Events) registriert und bei deren Auslösung automatisch eine definierte Reaktion ausführt. In Drupal und dem Symfony Framework lassen sich damit beispielsweise Anfragen, Benutzeraktionen oder Änderungen an Inhalten zentral verarbeiten, ohne den bestehenden Anwendungscode direkt zu verändern. Das unterstützt eine modulare, wartbare und flexibel erweiterbare Systemarchitektur.
Eine Entity ist ein eindeutig identifizierbares, strukturiertes Datenobjekt innerhalb eines Softwaresystems. In Drupal werden beispielsweise Inhalte, Benutzerkonten, Medien und Taxonomiebegriffe als Entities verwaltet; sie besitzen eine eigene ID, definierte Felder und können über die Entity API bearbeitet sowie mit weiteren Systemen verknüpft werden. Dadurch lassen sich flexible und skalierbare Datenmodelle für Websites, Portale und Enterprise-Anwendungen umsetzen.
- Antworten