0

At PriceRenderer we have \Magento\Framework\Pricing\Render\PriceBox::getSaleableItem

It returns \Magento\Framework\Pricing\SaleableInterface which is implemented in \Magento\Catalog\Model\Product.

Question is how to add Extension Attribute to this model to be visible at SaleableItem?

At repository it works perfect with Magento\Catalog\Api\Data\ProductInterface. But here if i go to \Magento\Framework\Pricing\Render\PriceBox::getSaleableItem, extension attributes are empty.

3
  • Can you show how extension attributes are being applied to products? Commented Mar 24, 2023 at 14:12
  • Let say „standard way” :) like here devdocs.magento.com/guides/v2.3/extension-dev-guide/… . So it’s afterGet() and afterGetList() plugins. It worka if collection goes from ProductRepositoryInterface. But if you load product by model or by collection, it work’s not.
    – Sebas
    Commented Mar 25, 2023 at 0:06
  • Right, the guide does not show all the ways a product model instance may be hydrated, only basic examples on the repository. Glad you figured it out! Commented Mar 29, 2023 at 13:41

2 Answers 2

0

I assume that you could try to set plugin on the getExtensionAttributes method of the Magento\Catalog\Model\Product directly or set plugin on the getSaleableItem method of the Magento\Framework\Pricing\Render\PriceBox and install an extension attribute there.

First things first we need to declare extension_attributes.xml file:

<extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
    <attribute code="test_ext_attr" type="int"/>
</extension_attributes>

Plugin on the Magento\Catalog\Model\Product (di.xml file):

<type name="Magento\Catalog\Model\Product">
    <plugin name="set_test_ext_attr_plugin"
            type="Vendor\Module\Plugin\SetTestExtAttr"
            sortOrder="20"/>
</type>

After plugin implementation:

<?php

declare(strict_types=1);

namespace Vendor\Module\Plugin;

use Magento\Catalog\Model\Product;
use Magento\Catalog\Api\Data\ProductExtensionInterface;
use Magento\Catalog\Api\Data\ProductExtensionInterfaceFactory;

class SetTestExtAttr
{
    private ProductExtensionInterfaceFactory $extensionAttributesFactory;

    public function __construct(ProductExtensionInterfaceFactory $extensionAttributesFactory)
    {
        $this->extensionAttributesFactory = $extensionAttributesFactory;
    }

    public function afterGetExtensionAttributes(
        Product $subject,
        ?ProductExtensionInterface $result
    ): ?ProductExtensionInterface {
        if (null === $result) {
            $result = $this->extensionAttributesFactory->create();
        }

        $result->setTestExtAttr(2222);

        return $result;
    }
}

And then you can access declared extension attribute from the Magento\Framework\Pricing\Render\PriceBox::getSaleableItem:

Dump and die result of the getExtensionAttributes in getSaleableItem method Dumped result on the frontend

6
  • Thanks. That works. I resolved this issue another way. With catalog_product_collection_load_after observer. Now I think witch solution is better in case of performance. As extension attribute I use interface with some methods inside, so there is no additional call to DB at this point. Yours solution with plugin on getExtensionAttributes() looks more strict. And here we don't have additional foreach like in collection.
    – Sebas
    Commented Mar 28, 2023 at 20:08
  • Now i checked, that if we add this plugin here, it seams that we don't need plugin for ProductRepositoryInterface::get() and ProductRepositoryInterface::getList() like is described in developer.adobe.com/commerce/php/development/components/… . And again, I think that with this solution we have better perfomance than iterating foreach in afterGetList plugin. Am i right about that? If yes why adobe chose to show in docs this solution with repositories and afterGet() and afterGetList()? I didn't checked that from api site.
    – Sebas
    Commented Mar 28, 2023 at 20:53
  • I checked API. And if we add plugin on Product::getExtensionAttributes we will get extension attribute in collection, in product repository but it will be not added by API call. To get extensionAttribute at API /V1/products we have to add this plugin to ProductRepositoryInterface. It's confusing.
    – Sebas
    Commented Mar 28, 2023 at 21:22
  • @Sebas, not sure what is the difference in our actions, but I am getting the extension attribute from the API call with solution above. I double checked, maybe I have another plugin on ProductRepositoryInterface which triggers plugin declared on the getExtensionAttributes and there is no another plugins. Commented Mar 29, 2023 at 12:16
  • That's strange. My type of extension_attribute is Interface that have some methods that returns value. What kind of extension attribute you have? Primitive type like string, int or some object? Strange :) .
    – Sebas
    Commented Mar 29, 2023 at 21:14
0

Summarizing: we can use plugin on Magento\Catalog\Model\Product::getExtensionAttribute to add extension attribute to collection, model and ProductRepositoryInterface. It will be available in code from admin or frontend area. If we would like to add it in web-api, we have to add plugin at ProductRepositoryInterface.

To prevent unnecessary duble add of this extension attribute at ProductRepositoryInterface::getList after plugin, if we add also "after" plugin for Magento\Catalog\Model\Product::getExtensionAttribute we should check is this extension attribute already set. Because if we call that method for code at frontend area, this will be set by Magento\Catalog\Model\Product::getExtensionAttribute. Here is fragment of my code: afterGetList()

As you can see at line 82 I check is my extension attribute is already set. Because if it will be called from code front or admin area, this will be already set. But if it will be called from web_api area, it will be null so it has to be set.

Your Answer

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

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