there are currently three distinct “size” attributes for configuring product variants on the website:
- size_international
- size_clothing
- size_foot
Considering it a wrong approach I intend to unify the three attributes under “size_international”.
To do this I need to fix all existing products that use “size_clothing” and “size_foot”.
<?php
namespace VendorMyModuleModelConfigurableSize;
class Fix {
protected $_productRepository;
protected $_attributeRepository;
protected $_optionMenagement;
protected $_optionInterface;
protected $_searchCriteriaBuilder;
protected $_state;
public function __construct(
MagentoCatalogApiProductRepositoryInterface $productRepository,
MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository,
MagentoCatalogApiProductAttributeOptionManagementInterface $optionMenagement,
MagentoEavApiDataAttributeOptionInterface $optionInterface,
MagentoFrameworkApiSearchCriteriaBuilder $searchCriteriaBuilder
){
$this->_productRepository = $productRepository;
$this->_attributeRepository = $attributeRepository;
$this->_optionMenagement = $optionMenagement;
$this->_optionInterface = $optionInterface;
$this->_searchCriteriaBuilder = $searchCriteriaBuilder;
}
public function fixSizeVariations($brand){
$sizeInternationalId = $this->_attributeRepository->get('size_international')->getAttributeId();
$manufacturer = $this->getOptionId($brand,'manufacturer');
if($manufacturer){
$productList = $this->getProductList($manufacturer);
} else {
return;
}
foreach($productList as $product){
echo $product->getSku()."n";
$skip = FALSE;
$oldAttributeCode = '';
$attributeIds = [$sizeInternationalId];
$conf = $product->getTypeInstance();
$variationAttributes = $conf->getConfigurableAttributes($product);
foreach($variationAttributes as $attribute) {
$attributeCode = $attribute->getProductAttribute()->getAttributeCode();
echo $attributeCode."n";
if($attributeCode != 'size_international'){
if(strpos($attributeCode,'size_') !== FALSE){
$oldAttributeCode = $attributeCode;
} else {
$attributeIds[] = $attribute->getProductAttribute()->getAttributeId();
}
} else {
$skip = TRUE;
}
}
if($skip){
continue;
}
if($oldAttributeCode){
foreach($conf->getUsedProductCollection($product)->addAttributeToSelect($oldAttributeCode) as $child){
$optionLabel = $child->getAttributeText($oldAttributeCode);
echo $optionLabel."n";
$optionId = $this->getOptionId($optionLabel,'size_international') ?: substr($this->_optionMenagement->add('size_international',$this->_optionInterface->setLabel($optionLabel)),3);
$child->setData($oldAttributeCode,0);
$child->getResource()->saveAttribute($child,$oldAttributeCode);
$child->setSizeInternational($optionId);
$child->getResource()->saveAttribute($child,'size_international');
}
}
$conf->setUsedProductAttributes($product,$attributeIds);
$this->_productRepository->save($product);
}
}
private function getProductList($manufacturer){
$this->_searchCriteriaBuilder->addFilter('manufacturer',$manufacturer);
$this->_searchCriteriaBuilder->addFilter('type_id','configurable');
$searcheResult = $this->_productRepository->getList($this->_searchCriteriaBuilder->create());
return $searcheResult->getItems();
}
private function getOptionId($optionLabel,$attributCode){
$attr = $this->_attributeRepository->get($attributCode);
$optionId = FALSE;
if ($attr->usesSource()) {
$optionId = $attr->getSource()->getOptionId($optionLabel);
}
return $optionId;
}
}
The values of the old attribute are correctly transferred to the new attribute in simple products, but the configurable product is not saved and returns the following error:
Product with id “7427” does not contain required attribute
“size_foot”.
where 7427 is a child product.
$conf->setUsedProductAttributes($product,$attributeIds);
appears to have no effect in this way.
If I manually edit the attribute_id column of the catalog_product_super_attribute table in database everithing works as expected.
So wich is the best way to directly modify that value?
Is there a better way to do it?