3

Hello everyone i would like to add an extension_attribute to quote item in magento 2. I create extension attribute:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Quote\Api\Data\CartItemInterface">
        <attribute code="image" type="string" />
    </extension_attributes>
</config>

Then i have created plugin that set an extension attribute "image" to every quote item in qoute, this plugin is running on afterGet magento rest endpoint

"V1/guest-carts/:cartId/totals":

/**
 * @var CartItemExtensionFactory
 */
protected $cartItemExtension;

/**
 * @param CartItemExtensionFactory $cartItemExtension
 * @param ProductRepositoryInterfaceFactory $productRepository
 */
public function __construct(
    CartItemExtensionFactory $cartItemExtension
) {
    $this->cartItemExtension = $cartItemExtension;
}

/**
 * Add attribute values
 *
 * @param CartRepositoryInterface $subject ,
 * @param   $quote
 * @return mixed $quoteData
 * @throws NoSuchEntityException
 */
public function afterGet(
    CartRepositoryInterface $subject,
    $quote
) {
    return $this->setAttributeValue($quote);
}

/**
 * set value of attributes
 *
 * @param $quote
 * @return mixed $extensionAttributes
 * @throws NoSuchEntityException
 */
private function setAttributeValue($quote)
{
    if ($quote->getItemsCount()) {
        foreach ($quote->getItems() as $item) {
            $extensionAttributes = $item->getExtensionAttributes();
            if ($extensionAttributes === null) {
                $extensionAttributes = $this->cartItemExtension->create();
            }
            $extensionAttributes->setImage('fooo');
            $item->setExtensionAttributes($extensionAttributes);
        }
    }

    return $quote;
}

But in response there is no extension_attributes in quote item. When i debug it in PHPSTORM i see that attribute is set in _data object but it is not returning in response.

My response in postman:

{
    "grand_total": 882.91,
    "base_grand_total": 1085.98,
    "subtotal": 882.91,
    "base_subtotal": 882.91,
    "discount_amount": 0,
    "base_discount_amount": 0,
    "subtotal_with_discount": 882.91,
    "base_subtotal_with_discount": 882.91,
    "shipping_amount": 0,
    "base_shipping_amount": 0,
    "shipping_discount_amount": 0,
    "base_shipping_discount_amount": 0,
    "tax_amount": 203.07,
    "base_tax_amount": 203.07,
    "weee_tax_applied_amount": null,
    "shipping_tax_amount": 0,
    "base_shipping_tax_amount": 0,
    "subtotal_incl_tax": 1085.98,
    "shipping_incl_tax": 0,
    "base_shipping_incl_tax": 0,
    "base_currency_code": "PLN",
    "quote_currency_code": "PLN",
    "items_qty": 2,
    "items": [
        {
            "item_id": 1324,
            "price": 21.13,
            "base_price": 21.13,
            "qty": 1,
            "row_total": 21.13,
            "base_row_total": 21.13,
            "row_total_with_discount": 0,
            "tax_amount": 4.86,
            "base_tax_amount": 4.86,
            "tax_percent": 23,
            "discount_amount": 0,
            "base_discount_amount": 0,
            "discount_percent": 0,
            "price_incl_tax": 25.99,
            "base_price_incl_tax": 25.99,
            "row_total_incl_tax": 25.99,
            "base_row_total_incl_tax": 25.99,
            "options": "[{\"value\":\"+30GB\",\"label\":\"Transfer Size\"}]",
            "weee_tax_applied_amount": null,
            "weee_tax_applied": null,
            "name": "Transfer"
        },
        {
            "item_id": 1325,
            "price": 861.78,
            "base_price": 861.78,
            "qty": 1,
            "row_total": 861.78,
            "base_row_total": 861.78,
            "row_total_with_discount": 0,
            "tax_amount": 198.21,
            "base_tax_amount": 198.21,
            "tax_percent": 23,
            "discount_amount": 0,
            "base_discount_amount": 0,
            "discount_percent": 0,
            "price_incl_tax": 1059.99,
            "base_price_incl_tax": 1059.99,
            "row_total_incl_tax": 1059.99,
            "base_row_total_incl_tax": 1059.99,
            "options": "[{\"value\":\"Unlimited\",\"label\":\"Variant\"}]",
            "weee_tax_applied_amount": null,
            "weee_tax_applied": null,
            "name": "foo"
        }
    ],
    "total_segments": [
        {
            "code": "subtotal",
            "title": "sum",
            "value": 1085.98
        },
        {
            "code": "shipping",
            "title": "shipping",
            "value": 0
        },
        {
            "code": "tax",
            "title": "Tax",
            "value": 203.07,
            "extension_attributes": {
                "tax_grandtotal_details": [
                    {
                        "amount": 203.07,
                        "rates": [
                            {
                                "percent": "23",
                                "title": "Poland (standard)"
                            }
                        ],
                        "group_id": 1
                    }
                ]
            }
        },
        {
            "code": "grand_total",
            "title": "Sub",
            "value": 1085.98,
            "area": "footer"
        }
    ]
}

Can anyone tell me why there is no my extension_attribute image in every single quote item ?

2 Answers 2

4

Not sure, but the first thing I noticed in your code is that you write plugin for \Magento\Quote\Api\CartRepositoryInterface but should be for \Magento\Quote\Api\GuestCartTotalRepositoryInterface

Upd #1: The following works for me:

extension_attributes.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Quote\Api\Data\TotalsItemInterface">
        <attribute code="some_super_cool_attribute" type="string" />
    </extension_attributes>
</config>

module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Underser_CartExtensionAttributes" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Quote"/>
        </sequence>
    </module>
</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\GuestCartTotalRepositoryInterface">
        <plugin name="underser_add_extension_attributes" type="Underser\CartExtensionAttributes\Plugin\Quote\TotalsPlugin"/>
    </type>
</config>

\Underser\CartExtensionAttributes\Plugin\Quote\TotalsPlugin

<?php

namespace Underser\CartExtensionAttributes\Plugin\Quote;

use Magento\Quote\Api\Data\TotalsInterface;
use Magento\Quote\Api\GuestCartTotalRepositoryInterface;
use Magento\Quote\Api\Data\TotalsItemInterface;
use Magento\Quote\Api\Data\TotalsItemExtensionInterfaceFactory;

class TotalsPlugin
{
    /**
     * @var TotalsItemExtensionInterfaceFactory
     */
    protected $totalsItemExtensionInterfaceFactory;

    /**
     * TotalsPlugin constructor.
     *
     * @param TotalsItemExtensionInterfaceFactory $totalsItemExtensionInterfaceFactory
     */
    public function __construct(TotalsItemExtensionInterfaceFactory $totalsItemExtensionInterfaceFactory)
    {
        $this->totalsItemExtensionInterfaceFactory = $totalsItemExtensionInterfaceFactory;
    }

    /**
     * After get items.
     *
     * @param GuestCartTotalRepositoryInterface $subject
     * @param TotalsInterface $result
     * @return TotalsInterface
     */
    public function afterGet(
        GuestCartTotalRepositoryInterface $subject,
        TotalsInterface $result
    ) {
        /** @var TotalsItemInterface $item */
        foreach ($result->getItems() as $item) {
            $extensionAttributes = $item->getExtensionAttributes();

            if (!$extensionAttributes) {
                $extensionAttributes = $this->totalsItemExtensionInterfaceFactory->create();
            }

            $extensionAttributes->setSomeSuperCoolAttribute('someSuperCoolAttributeValue');

            $item->setExtensionAttributes($extensionAttributes);
        }

        return $result;
    }
}
4
  • After applying your suggestion i'm getting the following error: Uncaught TypeError: Argument 1 passed to MyModuleName\QuoteCustomization\Plugin\QuotePlugin: :afterGet() must be an instance of Magento\Quote\Api\GuestCartTotalRepositoryInterface, instance of Magento\Quote\Model\QuoteRepository\Interceptor given, called in /Users/papryk/Sites/htdocs/magento-shop/vendor/magento/framework/Interception/Interceptor.php on line 146 and defined in /Users/papryk/Sites/htdocs/magento-shop/app/code/MyModuleName/QuoteCustomization/Plugin/QuotePlugin.php: 33
    – Patryk
    Oct 11, 2019 at 6:32
  • you need to change your plugin signature $subject should be \Magento\Quote\Api\GuestCartTotalRepositoryInterface
    – underser
    Oct 11, 2019 at 12:44
  • @Patryk, please see the updated answer. Feel free to ping me, if you still face problems.
    – underser
    Oct 11, 2019 at 15:39
  • Thank you very much, it's working now properly. I'm very grateful for your help.
    – Patryk
    Oct 14, 2019 at 11:57
0

I think that using this repository you will call this plugin several times. You can use the observer sales_quote_item_additional_data.

File: etc/frontend/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="sales_quote_add_item">
        <observer name="sales_quote_item_additional_data" instance="Vendor\ModuleName\Observer\QuoteItemExtensionAttribute"/>
    </event>
</config>

File: Observer/QuoteItemExtensionAttribute.php

<?php

namespace Vendor\ModuleName\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class QuoteItemExtensionAttribute implements ObserverInterface
{
    /**
     * @param Observer $observer
     */
    public function execute(Observer $observer)
    {
        // your code here
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.