Битрикс удаление дублей свойств инфоблока

Свойство называлось "Производители". СЕОшники сделали вывод списка производителей на сайте, примерно так:

global $currentCity;
CModule::IncludeModule('iblock');

$property_enums = CIBlockPropertyEnum::GetList(Array("SORT"=>"ASC"), Array("IBLOCK_ID"=>$currentCity["PROPERTY_ID_IBLOCK_CATALOG_VALUE"], "CODE"=>"MANUFACTURER"));
while($enum_fields = $property_enums->GetNext())
{
$aMenuLinksExt[] = array(
"0"=>$enum_fields["VALUE"],
"1"=>"/catalog/?arrFilter_pf".urlencode("[MANUFACTURER]")."=".$enum_fields["ID"]."&set_filter=Y",
"2"=>array("0"=>"/catalog/?arrFilter_pf".urlencode("[MANUFACTURER]")."=".$enum_fields["ID"]."&set_filter=Y")
);
}

Соответственно в этом списке появились дубли. Ситуация осложнялась тем, что по факту производитель один, но с точки зрения битрикса их оказалось двое, и у каждого из производителей были свои товары.

Алгоритм решения был такой:

  1. Переместить все товары в одного производителя
  2. Удилить производителей, у которых нет товаров

Сразу оговорюсь, что не во всех случаях этот алгоритм подойдет, т.к. бывает что производителей нельзя удалить или еще какие то обстоятельства. Но в данном случае это можно было сделать.

Для реализации алгоритма, создаем новую страничку или консольную утилиту битрикса, кому как больше нравиться. И первым делаем снимаем вограничения на работу скрипта

ini_set('memory_limit', '128M');
ini_set('max_execution_time', 0);

По скольку неизвестно сколько элементов нам нужно обработать, то увеличиваем ограничение по памяти и убираем ограничение на время выполнения скрипта.

Первая часть алгоритма:

//Перемещаем элементы
$arSelect = Array("ID", "IBLOCK_ID", "NAME", "PROPERTY_MANUFACTURER");
$arFilter = Array("IBLOCK_ID"=>2);
$res = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect);
$manufacturers = [];
while($ob = $res->GetNextElement())
{
$arFields = $ob->GetFields();
if ($arFields['PROPERTY_MANUFACTURER_VALUE'] !== null && $arFields['PROPERTY_MANUFACTURER_ENUM_ID'] !== null ) {
$manufacturers[$arFields['PROPERTY_MANUFACTURER_ENUM_ID']] = $arFields['PROPERTY_MANUFACTURER_VALUE'];
$newValues = [
'MANUFACTURER' => array_search($arFields['PROPERTY_MANUFACTURER_VALUE'], $manufacturers)
];
CIBlockElement::SetPropertyValuesEx($arFields["ID"], 2, $newValues);
echo $arFields["ID"],' '.array_search($arFields['PROPERTY_MANUFACTURER_VALUE'], $manufacturers)."<br />";
}
}
  • Делаем выборку элементов инфоблока, которые будем обрабатывать
  • В цикле проходимся по всем элементам
  • Заполняем массив со списком производителей
  • Присваиваем свойству производитель самое первое значение из массива производителей

Вторая часть алгоритма:

function hasElements($proprttyId)
{
$arSelect = Array("ID", "NAME", "PROPERTY_MANUFACTURER");
$arFilter = Array("IBLOCK_ID" => 2, "PROPERTY_MANUFACTURER" => $proprttyId);
$res = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect);
return (boolean)$r = $res->GetNextElement();
}

$property_enums = CIBlockPropertyEnum::GetList(Array("SORT"=>"ASC"), Array("IBLOCK_ID"=>$currentCity["PROPERTY_ID_IBLOCK_CATALOG_VALUE"], "CODE"=>"MANUFACTURER"));
while($enum_fields = $property_enums->GetNext())
{
if (!hasElements($enum_fields['ID'])) {
CIBlockPropertyEnum::Delete($enum_fields["ID"]);
echo $enum_fields["ID"]."\n";
}
}
  • Получаем список элементов производителей
  • Проверяем есть ли у этого производителя товары. Для этого я написал отдельную функцию
  • Если нет товаров, удалем производителя

В коде используется много плохих конструкций, не оптимальных по производительности, медленных и т.д. У меня не было цели написать красивый код. У меня была задача как можно быстрее решить проблему.

Теги:

Битрикс