Magento 2:以编程方式删除重复的产品属性选项

本文介绍了如何在Magento 2中删除重复的产品属性选项。

我为此使用了独立脚本。您也可以在自定义模块中使用此代码。

初始化对象管理器并设置区号

以下代码完成了以下操作:

–初始化对象管理器。
–在编辑产品时,将区号设置为adminhtml。

<?php
error_reporting(1);
set_time_limit(0);
ini_set('memory_limit', '2048M');
 
use Magento\Framework\App\Bootstrap;
 
/**
 * If your external file is in root folder
 */
require __DIR__ . '/app/bootstrap.php';
 
/**
 * If your external file is NOT in root folder
 * Let's suppose, your file is inside a folder named 'xyz'
 *
 * And, let's suppose, your root directory path is
 * /var/www/html/magento2
 */
// $rootDirectoryPath = '/var/www/html/magento2';
// require $rootDirectoryPath . '/app/bootstrap.php';
 
$params = $_SERVER;
 
$bootstrap = Bootstrap::create(BP, $params);
 
$obj = $bootstrap->getObjectManager();
 
$state = $obj->get('Magento\Framework\App\State');
$state->setAreaCode('adminhtml');

获取所有属性

$allAttributes = $obj->get('Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection')
                     ->getItems();
 
foreach ($allAttributes as $attribute) {
    var_dump($attribute->getData());
    //echo $attribute->getFrontendLabel() . ' - ' . $attribute->getAttributeCode() . '<br />';
}

通过属性代码加载产品属性

$attributeCode = 'color';
 
$attribute = $obj->get('Magento\Eav\Model\Config')
                 ->getAttribute('catalog_product', $attributeCode);
 
var_dump($attribute->getData());

输出:

array (size=41)
  'attribute_id' => string '93' (length=2)
  'entity_type_id' => string '4' (length=1)
  'attribute_code' => string 'color' (length=5)
  'attribute_model' => null
  'backend_model' => null
  'backend_type' => string 'int' (length=3)
  'backend_table' => null
  'frontend_model' => null
  'frontend_input' => string 'select' (length=6)
  'frontend_label' => string 'Color' (length=5)
  'frontend_class' => null
  'source_model' => null
  'is_required' => string '0' (length=1)
  'is_user_defined' => string '1' (length=1)
  'default_value' => null
  'is_unique' => string '0' (length=1)
  'note' => null
  'frontend_input_renderer' => null
  'is_global' => string '1' (length=1)
  'is_visible' => string '1' (length=1)
  'is_searchable' => string '1' (length=1)
  'is_filterable' => string '0' (length=1)
  'is_comparable' => string '1' (length=1)
  'is_visible_on_front' => string '0' (length=1)
  'is_html_allowed_on_front' => string '0' (length=1)
  'is_used_for_price_rules' => string '0' (length=1)
  'is_filterable_in_search' => string '0' (length=1)
  'used_in_product_listing' => string '0' (length=1)
  'used_for_sort_by' => string '0' (length=1)
  'apply_to' => null
  'is_visible_in_advanced_search' => string '1' (length=1)
  'position' => string '0' (length=1)
  'is_wysiwyg_enabled' => string '0' (length=1)
  'is_used_for_promo_rules' => string '1' (length=1)
  'is_required_in_admin_store' => string '0' (length=1)
  'is_used_in_grid' => string '1' (length=1)
  'is_visible_in_grid' => string '0' (length=1)
  'is_filterable_in_grid' => string '1' (length=1)
  'search_weight' => string '1' (length=1)
  'additional_data' => null
  ...
  ...
  ...

获取已加载属性的所有选项

$options = $attribute->getSource()->getAllOptions();
var_dump($options); 

输出:

Array
(
    [0] => Array
        (
            [label] =>  
            [value] => 
        )
 
    [1] => Array
        (
            [value] => 557
            [label] => Berry
        )
 
    [2] => Array
        (
            [value] => 517
            [label] => Black
        )
 
    [3] => Array
        (
            [value] => 573
            [label] => Blue
        )
    ...
    ...
    ...

获取与每个属性选项关联的所有产品

在这里,我们遍历上面代码中加载的属性的所有选项。然后,我们获取与每个属性选项关联的产品。

foreach ($options as $option) {
    $products = $obj->get('Magento\Catalog\Model\Product')
                    ->getCollection()
                    ->addAttributeToFilter($attributeCode, $option['value']);
 
    $productIds = [];
    foreach ($products as $prod) {
        $productIds[] = $prod->getId();
    }
 
    echo 'Option ID: ' . $option['value'] . '<br />';
    echo 'Option Label: ' . $option['label'] . '<br />';
    echo 'Total Products: ' . $products->count() . '<br />';
    echo 'Product IDs: ' . implode(', ', $productIds) . '<br />';
    echo '<br />';
}

输出:

Option ID: 71
Option Label: Berry
Total Products: 1
Product IDs: 566
 
Option ID: 61
Option Label: Black
Total Products: 4
Product IDs: 269, 276, 864, 868
 
Option ID: 52
Option Label: Blue
Total Products: 8
Product IDs: 626, 637, 649, 659, 672, 690, 701, 861
    
...
...
...

创建一个数组以找出重复的属性选项

在这里,我们遍历上面代码中加载的属性的所有选项。然后,我们创建一个包含属性标签作为键的新数组,该键包含另一个数组,该数组具有属性选项的ID和与该属性选项ID关联的产品总数。

该数组将如下所示:

Array
(
    [AttributeLabel] => Array
                     (
                         [AttributeID] => ProductCount
                     )
)

这是代码:

$duplicateOptions = [];
foreach ($options as $option) {
    // because the first option can be blank
    if(!empty(trim($option['label']))) {
        $products = $obj->get('Magento\Catalog\Model\Product')
                        ->getCollection()
                        ->addAttributeToFilter($attributeCode, $option['value']);
 
        if ($products->count()) {
            $productsCount = $products->count();
        } else {
            $productsCount = 0;
        }
 
        $duplicateOptions[$option['label']][$option['value']] = $productsCount;
    }
}
 
echo '<pre>'; print_r($duplicateOptions); 

输出:

Array
(
    [Berry] => Array
        (
            [53] => 1
            [247] => 0
        )
 
    [Black] => Array
        (
            [13] => 42
        )
 
    [Blue] => Array
        (
            [61] => 4
        )
 
    [White] => Array
        (
            [16] => 0
            [246] => 0
        )
 
    ...
    ...
    ...

在上面的输出中,您可以在数组键Berry中看到两项。这表明属性选项“ Berry”具有重复的条目,即有两个条目与Berry具有相同的标签。

删除重复属性选项

到目前为止,我们已经找到了重复的属性选项。现在,在删除重复属性选项时,您需要确定需要删除的选项。

有可能:

–新添加的属性选项,即具有较高ID的重复属性选项
–旧的属性选项,即具有较低ID的
重复属性选项–产品计数为零的重复属性选项

对于此示例,我将尝试删除重复的最新/新添加的属性选项,即,我假设某些属性选项最近已添加到该属性,但是那些属性选项之前已存在于该属性中。

首先,

–我们将在deleteOptions数组中创建一个名为delete的新键条目。 –它将包含要删除的属性选项ID的值。 –包含零产品计数的属性选项ID被视为要删除的那个。

foreach ($duplicateOptions as $key => $value) {
    if (count($value) > 1) {
        foreach ($value as $k => $v) {
            if ($v == 0) {
                $duplicateOptions[$key]['delete'][] = $k;
            }
        }
    }
}
echo '<pre>'; print_r($duplicateOptions); 

输出:

Array
(
    [Berry] => Array
        (
            [53] => 1
            [247] => 0
            [delete] => Array
                (
                    [0] => 247
                )
 
        )
 
    [Black] => Array
        (
            [13] => 42
        )
 
    [White] => Array
        (
            [16] => 0
            [246] => 0
            [delete] => Array
                (
                    [0] => 16
                    [1] => 246
                )
 
        )
 
    ...
    ...
    ...

在上面的输出中,对于属性选项White,两个选项ID均被视为要删除的选项ID。这是因为两个选项ID的关联产品均为零。

在这种情况下,我们将从“删除”键数组中删除我们不想删除的属性选项ID。

如上所述,对于此示例,我将新添加/最新添加的选项视为重复的选项。因此,我将删除具有较高ID的选项,而不是删除具有较低ID值的选项。

foreach ($duplicateOptions as $key => $value) {
    if (count($value) > 1) {
        foreach ($value as $k => $v) {
            if ($v == 0) {
                $duplicateOptions[$key]['delete'][] = $k;
            }
        }
 
        if (isset($duplicateOptions[$key]['delete'])) {
            /**
             * if multiple options are in delete array, 
             * i.e. multiple option ids have zero product count
             */ 
            if (count($duplicateOptions[$key]['delete']) > 1) { 
                sort($duplicateOptions[$key]['delete']); // sort the array
                array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
 
                /**
                 * if you assume that the older option id is the duplicate one
                 * then, you keep the older option id in the delete list 
                 * and remove the latest/newly-added attribute option from the delete list
                 */ 
                // rsort($duplicateOptions[$key]['delete']); // reverse sort the array
                // array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
            }
        }
    }
}
echo '<pre>'; print_r($duplicateOptions); 

输出:

Array
(
    [Berry] => Array
        (
            [53] => 1
            [247] => 0
            [delete] => Array
                (
                    [0] => 247
                )
 
        )
 
    [Black] => Array
        (
            [13] => 42
        )
 
    [White] => Array
        (
            [16] => 0
            [246] => 0
            [delete] => Array
                (
                    [0] => 246
                )
 
        )
 
    ...
    ...
    ...

现在,我们实际上删除了重复属性选项。

foreach ($duplicateOptions as $key => $value) {
    if (count($value) > 1) {
        foreach ($value as $k => $v) {
            if ($v == 0) {
                $duplicateOptions[$key]['delete'][] = $k;
            }
        }
 
        if (isset($duplicateOptions[$key]['delete'])) {
            /**
             * if multiple options are in delete array, 
             * i.e. multiple option ids have zero product count
             */ 
            if (count($duplicateOptions[$key]['delete']) > 1) { 
                sort($duplicateOptions[$key]['delete']); // sort the array
                array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
 
                /**
                 * if you assume that the older option id is the duplicate one
                 * then, you keep the older option id in the delete list 
                 * and remove the latest/newly-added attribute option from the delete list
                 */ 
                // rsort($duplicateOptions[$key]['delete']); // reverse sort the array
                // array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
 
                // DELETE DUPLICATE ATTRIBUTE OPTIONS
                foreach ($duplicateOptions[$key]['delete'] as $optionId) {
                    $optionModel = $obj->get('Magento\Eav\Model\Entity\Attribute\Option')->load($optionId);
                    try {
                        $optionModel->delete();
                        echo '<font color="green">"'.$key.' ('.$optionId.')" Option Deleted!</font><br />';
                    }
                    catch(Exception $e) {
                        echo '<font color="red">'. $e->getMessage() .'</font><br />';
                    }
                }
            }
        }
    }
}

输出:

"Berry (247)" duplicate option deleted!
"White (246)" duplicate option deleted!

删除重复的属性选项并将操作保存在日志文件中

删除代码与上述相同。我们刚刚添加了将删除的消息保存在日志文件中的代码。日志文件将保存在var / log文件夹中。

$file = 'var/log/delete_duplicate_attribute_options.log';
$handle = fopen($file, 'a') or die('Cannot open file:  '.$file); //implicitly creates file
$data = date('Y-m-d H:i:s');
$data .= "\n";
$data .= 'Attribute Code: ' . $attributeCode;
$data .= "\n\n";
 
foreach ($duplicateOptions as $key => $value) {
    if (count($value) > 1) {
        foreach ($value as $k => $v) {
            if ($v == 0) {
                $duplicateOptions[$key]['delete'][] = $k;
            }
        }
 
        if (isset($duplicateOptions[$key]['delete'])) {
            /**
             * if multiple options are in delete array, 
             * i.e. multiple option ids have zero product count
             */ 
            if (count($duplicateOptions[$key]['delete']) > 1) { 
                sort($duplicateOptions[$key]['delete']); // sort the array
                array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
 
                /**
                 * if you assume that the older option id is the duplicate one
                 * then, you keep the older option id in the delete list 
                 * and remove the latest/newly-added attribute option from the delete list
                 */ 
                // rsort($duplicateOptions[$key]['delete']); // reverse sort the array
                // array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
            }
 
            // DELETE DUPLICATE ATTRIBUTE OPTIONS
            foreach ($duplicateOptions[$key]['delete'] as $optionId) {
                $optionModel = $obj->get('Magento\Eav\Model\Entity\Attribute\Option')->load($optionId);
                try {
                    $optionModel->delete();
                    echo '<font color="green">"'.$key.' ('.$optionId.')" duplicate option deleted!</font><br />';
                    $data .= 'Option Value: ' . $key . ', ' . 'Option ID: ' . $optionId;
                    $data .= "\n";
                } catch(Exception $e) {
                    echo '<font color="red">'. $e->getMessage() .'</font><br />';
                    $data .= $e->getMessage();
                }
            }
        }
    }
}
 
$data .= "\n\n";
fwrite($handle, $data);
fclose($handle);

日志文件的输出:

2018-11-08 07:54:49
Attribute Code: color
 
Option Value: Berry, Option ID: 247
Option Value: White, Option ID: 248

希望这可以帮助。谢谢。

相关文章

0 0 投票数
文章评分
订阅评论
提醒
0 评论
内联反馈
查看所有评论