Magento 2 - Losing data with extension attributes in bundle options collection
-
08-10-2020 - |
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.xml
file
<?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 ?
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:
- 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;
}
- 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.