shopwareshopware6shopware6-api

How to add data to an OrderEntity extension when creating an order from a cart over the Shopware 6 Store API?


This is not a question about how to create an order in Shopware 6 via API, but on how to add extension data to the order while creating the order from the cart using the Shopware 6 Store API.

Shopware 6 version 6.4.20

The following endpoint is used: https://shopware.stoplight.io/docs/store-api/a020d67a79ed0-create-an-order-from-a-cart

I have created an OrderExtensionEntity which has a simple text field in it.

<?php

namespace MyPlugin\Order\Extension;

class OrderExtension extends \Shopware\Core\Framework\DataAbstractionLayer\EntityExtension
{
    public function extendFields(\Shopware\Core\Framework\DataAbstractionLayer\FieldCollection $collection): void
    {
        $collection->add(
            (new \Shopware\Core\Framework\DataAbstractionLayer\Field\StringField('my_text', 'myText'))->addFlags(new \Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\ApiAware())
        );
    }

    public function getDefinitionClass(): string
    {
        return \Shopware\Core\Checkout\Order\OrderDefinition::class;
    }
}

This field has been added to the MySQL database:

ALTER TABLE `order` ADD COLUMN (`my_text` text);

Now I execute a store API request against the above-mentioned endpoint, but no matter where I put the value for the myText field, it never gets saved to the database. If I create an order via the endpoint POST /api/order, it gets saved without problem, but I need to use the endpoint Create an order from a cart due to underlying checks and validation logic.

Modifying the order with the extension data, after it was created (example: a 2nd call to the API) is not possible, since by then certain Flows from FlowBuilder needing the myText value will already have started and will be missing the value when they are executed.

How does the body of the request against /checkout/order have to be set, so the value of myText is immediately saved to the database? Or do I have to modify the CartEntity or even decorate the CheckoutController of Shopware 6?


Solution

  • You shouldn't alter the default tables. This is considered bad practice and if you want to publish your plugin the community store, it will be an issue. Create a custom entity with a OneToOneAssociationField to the OrderDefinition. Then change the EntityExtension on the OrderDefinition to add a OneToOneAssociationField to your custom entity. You can set the autoload argument to true so your extension is always loaded when the order is loaded.

    To write the extension when the order is persisted, you can listen to the CartConvertedEvent and add the data to the converted cart.

    use Shopware\Core\Checkout\Cart\Order\CartConvertedEvent;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\HttpFoundation\RequestStack;
    
    class CartConvertedSubscriber implements EventSubscriberInterface
    {
        public function __construct(private readonly RequestStack $requestStack) {
        }
    
        public static function getSubscribedEvents(): array
        {
            return [
                CartConvertedEvent::class => 'onCartConverted',
            ];
        }
    
        public function onCartConverted(CartConvertedEvent $event): void
        {
           $data = $event->getConvertedCart();
           $myText = $this->requestStack->getMainRequest()?->request->get('myText');
    
           if (isset($data['extension']['myCustomEntityExtension']) || !$myText) {
               return;
           }
    
           $data['extension']['myCustomEntityExtension'] = [
                'myText' => $myText,
           ];
    
           $event->setConvertedCart($data);
        }
    }