Magento – Extending Magento’s Quote API to Receive New Attribute

apimagento2

I am trying to add a custom attribute to a quote item via the API, however I am struggling to see how Magento's architecture actually allows for this?

I have created the following files:

extension_attributes.xml:

<config>
    <extension_attributes for="Magento\Quote\Api\Data\CartItemInterface">
        <attribute code="my_custom_field" type="string">
            <resources>
                <resource  ref="anonymous"/>
            </resources>
        </attribute>
    </extension_attributes>
</config>

di.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Quote\Api\GuestCartItemRepositoryInterface">
        <plugin name="example" type="Brideo\Example\Model\GuestCart\GuestCartItemRepository\Plugin" sortOrder="100" disabled="false" />
    </type>
</config>

Brideo\Example\Model\GuestCart\GuestCartItemRepository\Plugin:

/**
     * @param GuestCartItemRepositoryInterface $subject
     * @param CartItemInterface                $entity
     *
     * @return CartItemInterface[]
     */
    public function beforeSave(
        GuestCartItemRepositoryInterface $subject,
        CartItemInterface $entity
    )
    {
            $extensionAttributes = $entity->getExtensionAttributes();

        if ($entity->getData('my_custom_field') || $extensionAttributes == null || $extensionAttributes->getMyCustomField() == null) {
            return [$entity];
        }

        $someEntity = $this->someRepo->get($extensionAttributes->getMyCustomField());

        $extensionAttributes->setMyCustomField($someEntity->getMyCustomField());
        $entity->setExtensionAttributes($extensionAttributes);

        return [$entity];
    }

I can see the extension attribute being added, however when Magento passes the cart item to the CartItemPersister::save() method it runs this code:

$item = $quote->addProduct(
                    $product,
                    $this->cartItemOptionProcessor->getBuyRequest($productType, $item)
                );

This code gives you the opportunity to add to the buy request but not add any custom data and it simply removes the extension attributes.

Any ideas? I think I might just have to create an additional mapping table even though it's not a many to many relationship.

Best Answer

So in the end I had to use the around method.

  • beforeSave I have no entity to save against
  • afterSave I have no data to save
  • aroundSave grab the data then save against the new entity

    public function aroundSave
    (
        \Magento\Quote\Api\GuestCartItemRepositoryInterface $subject,
        \Closure $proceed,
        \Magento\Quote\Api\Data\CartItemInterface $entity
    ) 
    {
        $extensionAttributes = $entity->getExtensionAttributes();
    
        if ($extensionAttributes == null || $extensionAttributes->getMyCustomField() == null) 
        {
            return [$entity];
        }
    
        /** @var \Magento\Quote\Api\Data\CartItemInterface|\Magento\Framework\Model\AbstractModel $cartItem */
        $cartItem = $proceed($entity);
        if (!$cartItem) 
        {
            return $cartItem;
        }
    
        $someData = $this->someRepo->get($extensionAttributes->getMyCustomField());
        $cartItem->setData('my_custom_id', $someData->getId());
        $this->itemResource->save($cartItem);
    
        return $cartItem;
    }
    
Related Topic