Question

I am using Magento 2.1.4 I add a new column required_total on table catalog_product_bundle_option

I created the extension_attributes.xmlfile

<?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\Bundle\Api\Data\OptionInterface">
        <attribute code="required_total" type="int"/>
    </extension_attributes>
</config>

I did bin/magento setup:di:compile to generate the interface \Magento\Bundle\Api\Data\OptionExtensionInterface in var/generation folder.

In admin edit form of a bundled product Magento use $this->optionsRepository->getList() to retrieve bundle options.
Here Magento will use populateWithArray method to hydrate the collection entities.

/**
 * @param \Magento\Catalog\Api\Data\ProductInterface $product
 * @return \Magento\Bundle\Api\Data\OptionInterface[]
 */
public function getItems(\Magento\Catalog\Api\Data\ProductInterface $product)
{
    $optionCollection = $this->type->getOptionsCollection($product);
    [...]
    /** @var \Magento\Bundle\Model\Option $option */
    foreach ($optionCollection as $option) {
        [...]
        /** @var \Magento\Bundle\Api\Data\OptionInterface $optionDataObject */
        $optionDataObject = $this->optionFactory->create();

        \Zend_Debug::dump($option->debug(), 'before populate');
        $this->dataObjectHelper->populateWithArray(
            $optionDataObject,
            $option->getData(),
            '\Magento\Bundle\Api\Data\OptionInterface'
        );
        \Zend_Debug::dump($optionDataObject->debug(), 'after populate');
        die;

        $optionDataObject->setOptionId($option->getOptionId())
            ->setTitle($option->getTitle() === null ? $option->getDefaultTitle() : $option->getTitle())
            ->setDefaultTitle($option->getDefaultTitle())
            ->setSku($product->getSku())
            ->setProductLinks($productLinks);
        $optionList[] = $optionDataObject;
    }
    return $optionList;
}

Here is the debug

before populate array(10) {
  ["option_id"] => string(2) "17"
  ["parent_id"] => string(3) "719"
  ["required"] => string(1) "1"
  ["position"] => string(1) "1"
  ["type"] => string(8) "checkbox"
  ["required_total"] => string(1) "2"
  ["default_title"] => string(16) "Foo"
  ["title"] => string(16) "Foo"
}

after populate array(5) {
  ["option_id"] => string(2) "17"
  ["required"] => string(1) "1"
  ["position"] => string(1) "1"
  ["type"] => string(8) "checkbox"
  ["title"] => string(16) "Foo"
}

As you can see my new column is not set, as far as I understand looking at \Magento\Framework\Api\DataObjectHelper::_setDataValues it is because :

  • setter does not exist in \Magento\Bundle\Api\Data\OptionInterface
  • attribute is not a custom attribute

Because of that I can not retrieve my attribute value and so can not edit it in the admin edit form.

Of course $option->getExtensionAttributes() is empty.

What are my solutions here :

  • using a plugin to make $optionDataObject->setRequiredTotal($option->getRequiredTotal()) at the end of the function ?
  • Am I using the extension attributes the wrong way ?
  • Am I missing something ?
Was it helpful?

Solution

The documentation for extension attributes is not quite clear on what's the right way to use them and it seems like each entity type does it in a slightly different way.

That being said, from my experience you have to create plugins to populate the extension attributes, and also to save them. It is not done automatically.

Take a look at Magento\GiftMessage\Model\Plugin\OrderGet and Magento\GiftMessage\Model\Plugin\OrderSave for an example.

OTHER TIPS

You should process extension attributes manually. But, for repository and collections there are different ways. Magento...

Common action: create extension attributes declaration.

For repo:

  1. Create plugin for init object.

Plugin:

<type name="Magento\Sales\Api\Data\OrderInterface">

Code:

public function afterGetExtensionAttributes(
    OrderInterface $entity,
    OrderExtensionInterface $extension = null
) {
    if ($extension === null) {
        $extension = $this->extensionFactory->create();
    }

    return $extension;
}
  1. Add plugin-handlers for getting and saving the attributes.

For Collections: use plugins for preload custom fields from db and observers (after collection load) for filling the attributes.


In conclusion, for each new entity you have to do all steps again.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top