Zend certified PHP/Magento developer

Magento 2 Merge Configurable Attributes

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?