3

I've been looking into extension attributes from various articles and tutorials:

https://store.fooman.co.nz/blog/an-introduction-to-extension-attributes.html https://devdocs.magento.com/guides/v2.2/extension-dev-guide/extension_attributes/adding-attributes.html

Easy to explain, but the one thing that came up for me is adding an extension attribute to the CartInterface model. Basically, if I want to add a plugin for the save() repository model it does not return anything (void). How would I go about retrieving the recently saved Quote/Cart going by the above two methods. Right now I just have a method that puts data into the extension attribute, but the data is not persistent elsewhere.

    $quote = $this->quoteRepository->getActive($cartId);

    // Extension Attributes
    $quoteExtension = $quote->getExtensionAttributes();
    $quoteExtension->setFromApp(true);

    $this->quoteRepository->save($quote);
2

1 Answer 1

3

First time, you must create a file extension_attributes.xml

Vendor\Namespace\etc\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\CartInterface">
    <attribute code="from_app" type="string"/>
</extension_attributes>

Then, you have to change the behavior of the get(), getList() and save() function of the repository.

Vendor\Namespace\etc\extension_attributes.xml

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Quote\Api\CartRepositoryInterface">
    <plugin name="vendor_namespace_plugin_cart_repository" type="Vendor\Namespace\Plugin\CartRepositoryPlugin"/>
</type>

Having the field in the table of DB quote, you can directly save the data by the magic method. If you do this, in the plugin of below, you do not need the function beforSave().

$quote->setFromApp(true);
$this->quoteRepository->save($quote);

You can do on this way also, in which, the function beforeSave() of the plugin of below is mandatory.

$quote = $this->quoteRepository->getActive($cartId);

// Extension Attributes
$quoteExtension = $quote->getExtensionAttributes();
$quoteExtension->setFromApp(true);
$quote->setExtensionAttributes($quoteExtension);

$this->quoteRepository->save($quote);

Vendor\Namespace\Plugin\CartRepositoryPlugin

<?php
namespace Vendor\Namespace\Plugin;

use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Api\Data\CartExtension;
use Magento\Quote\Api\Data\CartExtensionFactory;
use Magento\Quote\Api\Data\CartInterface;
use Magento\Quote\Api\Data\CartSearchResultsInterface;

/**
 * Class CartRepositoryPlugin
 */
class CartRepositoryPlugin
{
    /**
     * @var CartExtensionFactory
     */
    private $extensionFactory;

    /**
     * CartRepositoryPlugin constructor.
     *
     * @param CartExtensionFactory $orderExtensionFactory
     */
    public function __construct(
        CartExtensionFactory $orderExtensionFactory
    ) {
        $this->extensionFactory = $orderExtensionFactory;
    }

    /**
     * @param CartRepositoryInterface $subject
     * @param CartInterface $resultEntity
     * @return CartInterface
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function afterGet(
        CartRepositoryInterface $subject,
        CartInterface $resultEntity
    ) {
        /** @var CartExtension $extensionAttributes */
        $extensionAttributes = $resultEntity->getExtensionAttributes() ?: $this->extensionFactory->create();

        $extensionAttributes->setFromApp($resultEntity->getData('from_app'));

        $resultEntity->setExtensionAttributes($extensionAttributes);

        return $resultEntity;
    }

    /**
     * @param CartRepositoryInterface $subject
     * @param CartSearchResultsInterface $resultCart
     * @return CartSearchResultsInterface
     */
    public function afterGetList(
        CartRepositoryInterface $subject,
        CartSearchResultsInterface $resultCart
    ) {
        /** @var CartInterface $order */
        foreach ($resultCart->getItems() as $order) {
            $this->afterGet($subject, $order);
        }

        return $resultCart;
    }

    /**
     * @param CartRepositoryInterface $subject
     * @param CartInterface $result
     * @return array
     */
    public function beforeSave(
        CartRepositoryInterface $subject,
        CartInterface $quote
    ) {
        $extensionAttributes = $quote->getExtensionAttributes() ?: $this->extensionFactory->create();
        if ($extensionAttributes !== null && $extensionAttributes->getFromApp() !== null) {
            $quote->setFromApp($extensionAttributes->getFromApp());
        }

        return [$quote];
    }
}

How you can look, the function beforeSave() use the magic method setFromApp() to save the data, instead of this, you can use the magic method directly to save the quote how I explained before.

If the data were in another table of DB with its own model, the function of the plugin will be afterSave() and it will seem similar to this.

/**
 * @param CartRepositoryInterface $subject
 * @param CartInterface $result
 * @return CartInterface
 */
public function afterSave(
    CartRepositoryInterface $subject,
    CartInterface $result
) {
    $extensionAttributes = $result->getExtensionAttributes() ?: $this->storeExtensionFactory->create();
    if ($extensionAttributes !== null && $extensionAttributes->getFromApp() !== null) {
        /** @var CustomEntity $customEntity */
        $customEntity = $this->customEntityFactory->create();
        $customEntity->setQuoteId($result->getId());
        $customEntity->setFromApp($result->getFromApp());
        $this->customEntityRepository->save($customEntity);
    }

    return $result;
}
9
  • Awesome! I did not knew I could use magic functions if I had columns made in the appropriate db tables. A far better solution than using extension attributes as I was having issues (unrelated to the question) using them with this project. Commented Jun 25, 2018 at 20:06
  • The correct way is use the extension attributes, but if you save the data in the table "quote", for saving you can use the magic method, but you need do the plugin to load the data with the function get() and getList().
    – raumatbel
    Commented Jun 25, 2018 at 20:45
  • Yeah I get that, but in my current situation I can not use the get() and getList() for reasons unrelated to this question. Commented Jun 26, 2018 at 12:01
  • @raumatbel, I have one doubt in the extension attribute. Where the custom created extension attribute was saved in the database.
    – Ramya
    Commented Mar 15, 2020 at 15:03
  • @Ramya in my example, you have 2 options: 1) This is the easiest way. You can create a new field in the quote table and follow the steps of my comment of Vendor\Namespace\Plugin\CartRepositoryPlugin. 2) The other option is to create a table of your own, with your models, resources model ... and as I indicated in the last part of my comment with the afterSave.
    – raumatbel
    Commented Mar 19, 2020 at 12:55

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.