Задача. Простановка символьных кодов у всех элементов инфоблока (или его конкретного раздела) через API Битрикса средствами старого ядра и D7.

1. Нужно массово (для всех элементов инфоблока или конкретного раздела) выполнить логику:
- Вариант 1: Если у элемента есть символьный код, то не меняем его, если нет – формируем по новым правилам.
- Вариант 2: Если у элемента есть код, то заменить его на новый (по тем же правилам).
2. Правило формирования символьного кода из названия берётся из массива $params:
$params = array(
"max_len" => "100", // обрезает символьный код до 100 символов
"change_case" => "L", // буквы преобразуются к нижнему регистру
"replace_space" => "-", // меняем пробелы на "-"
"replace_other" => "-", // все "левые" символы заменяем на "-"
"delete_repeat_replace" => "true", // удаляем повторяющиеся "-"
"safe_chars" => "false" // cтрока символов, которые не нужно заменять (по умолчанию – пустая строка).
);
3. В каждом примере кода обязательно ведётся логирование через AddMessage2Log().
Решение
Ниже — статья, где мы рассматриваем 4 примера массовых операций (по два на каждое ядро):
- Старое ядро (CIBlockElement)
- Если код у элемента уже есть, не меняем его. Если нет кода — создаём по заданным правилам.
- Если код есть — заменяем его по новым правилам.
- Новая модель (D7)
- Если код у элемента есть — не меняем. Если нет кода — генерируем по заданным правилам.
- Если код есть — заменяем его по новым правилам.
1. Старое ядро (CIBlockElement)
Пример 1. Если код у элемента уже есть, не меняем его. Если нет кода — создаём по заданным правилам.
<?php
AddMessage2Log("Начало массовой обработки элементов (Старое ядро). Вариант 1");
// Обязательно подключаем модуль
CModule::IncludeModule("iblock");
// Указываем ID инфоблока
$iblockId = 2;
// Набор параметров для транслитерации
$params = array(
"max_len" => "100",
"change_case" => "L",
"replace_space" => "-",
"replace_other" => "-",
"delete_repeat_replace" => "true",
"safe_chars" => "false",
);
// Получаем все элементы нужного инфоблока
$arFilter = [
"IBLOCK_ID" => $iblockId
];
$rsElements = CIBlockElement::GetList([], $arFilter, false, false, ["ID", "NAME", "CODE", "IBLOCK_ID"]);
while ($arElement = $rsElements->GetNext())
{
$elementID = $arElement["ID"];
$elementName = $arElement["NAME"];
$elementCode = $arElement["CODE"];
if (!empty($elementCode))
{
// Код уже есть, не меняем
AddMessage2Log("Элемент ID {$elementID}: символьный код уже существует ({$elementCode}), пропускаем.");
}
else
{
// Генерируем новый код из имени
$newCode = Cutil::translit($elementName, "ru", $params);
// Обновляем элемент
$el = new CIBlockElement;
$res = $el->Update($elementID, ["CODE" => $newCode]);
if ($res)
{
AddMessage2Log("Элемент ID {$elementID}: новый код установлен -> {$newCode}");
}
else
{
AddMessage2Log("Элемент ID {$elementID}: ошибка при обновлении кода -> " . $el->LAST_ERROR);
}
}
}
?>
В данном скрипте:
- Задаём $iblockId, массив $params для формирования кода.
- Выбираем все элементы инфоблока.
- Для каждого проверяем, есть ли у него код: если есть — пропускаем, если нет — формируем транслитом из NAME.
- Всё логируем через AddMessage2Log().
Пример 2. Если код у элемента есть – меняем его по новым правилам
<?php
AddMessage2Log("Начало массовой обработки элементов (Старое ядро). Вариант 2");
// Подключаем модуль
CModule::IncludeModule("iblock");
// ID инфоблока
$iblockId = 2;
// Параметры для транслита
$params = array(
"max_len" => "100",
"change_case" => "L",
"replace_space" => "-",
"replace_other" => "-",
"delete_repeat_replace" => "true",
"safe_chars" => "false",
);
// Получаем все элементы инфоблока
$arFilter = [
"IBLOCK_ID" => $iblockId
];
$rsElements = CIBlockElement::GetList([], $arFilter, false, false, ["ID", "NAME", "CODE", "IBLOCK_ID"]);
while ($arElement = $rsElements->GetNext())
{
$elementID = $arElement["ID"];
$elementName = $arElement["NAME"];
$elementCode = $arElement["CODE"];
// Формируем код по-новому из названия
$newCode = Cutil::translit($elementName, "ru", $params);
// Если старый код такой же, как новый, - можем пропустить, но
// в примере принудительно меняем, чтобы показать механику
$el = new CIBlockElement;
$res = $el->Update($elementID, ["CODE" => $newCode]);
if ($res)
{
AddMessage2Log("Элемент ID {$elementID}: код изменён c [{$elementCode}] на [{$newCode}]");
}
else
{
AddMessage2Log("Элемент ID {$elementID}: ошибка при обновлении кода -> " . $el->LAST_ERROR);
}
}
?>
Этот вариант покажет, как заменить уже существующий код, не проверяя, пустой ли он. При желании можно усложнить логику: проверять, отличается ли новый транслит от старого кода, и обновлять только при необходимости.
2. Новое ядро (D7)
Пример 3. D7. Если код у элемента есть – оставляем, если нет – генерируем
<?php
AddMessage2Log("Начало массовой обработки (D7). Вариант 1");
use Bitrix\Main\Loader;
use Bitrix\Iblock\Elements\ElementCatalogTable; // Или ваш класс для нужного инфоблока
Loader::includeModule('iblock');
// ID инфоблока
$iblockId = 3;
// Параметры транслита
$params = array(
"max_len" => "100",
"change_case" => "L",
"replace_space" => "-",
"replace_other" => "-",
"delete_repeat_replace" => "true",
"safe_chars" => "false",
);
// Получаем нужные элементы (пример: по всему инфоблоку)
$elements = ElementCatalogTable::getList([
'filter' => ['IBLOCK_ID' => $iblockId],
'select' => ['ID', 'NAME', 'CODE']
]);
while ($element = $elements->fetch())
{
$elementID = $element['ID'];
$elementName = $element['NAME'];
$elementCode = $element['CODE'];
if (!empty($elementCode))
{
// Код существует, не меняем
AddMessage2Log("D7. Элемент ID {$elementID}: код уже есть ({$elementCode}), пропускаем.");
}
else
{
// Генерируем новый код
$newCode = Cutil::translit($elementName, "ru", $params);
// Обновляем
$result = ElementCatalogTable::update($elementID, ['CODE' => $newCode]);
if ($result->isSuccess())
{
AddMessage2Log("D7. Элемент ID {$elementID}: установлен новый код -> {$newCode}");
}
else
{
AddMessage2Log("D7. Элемент ID {$elementID}: ошибка при обновлении -> " . implode(', ', $result->getErrorMessages()));
}
}
}
?>
В данном примере:
- Выбираем все элементы инфоблока 3.
- Проверяем CODE: если не пустой, пропускаем, иначе генерируем из NAME.
- Обновляем элемент через ORM-метод update() и логируем результат.
Пример 4. D7. Если код у элемента есть – заменяем на новый
<?php
AddMessage2Log("Начало массовой обработки (D7). Вариант 2");
use Bitrix\Main\Loader;
use Bitrix\Iblock\Elements\ElementCatalogTable; // Замените на свой класс
Loader::includeModule('iblock');
// ID инфоблока
$iblockId = 3;
// Параметры транслита
$params = array(
"max_len" => "100",
"change_case" => "L",
"replace_space" => "-",
"replace_other" => "-",
"delete_repeat_replace" => "true",
"safe_chars" => "false",
);
$elements = ElementCatalogTable::getList([
'filter' => ['IBLOCK_ID' => $iblockId],
'select' => ['ID', 'NAME', 'CODE']
]);
while ($element = $elements->fetch())
{
$elementID = $element['ID'];
$oldCode = $element['CODE'];
$elementName = $element['NAME'];
// Формируем новый код на основе имени
$newCode = Cutil::translit($elementName, "ru", $params);
// Меняем код
$result = ElementCatalogTable::update($elementID, ['CODE' => $newCode]);
if ($result->isSuccess())
{
AddMessage2Log("D7. Элемент ID {$elementID}: код изменён с [{$oldCode}] на [{$newCode}]");
}
else
{
AddMessage2Log("D7. Элемент ID {$elementID}: ошибка при обновлении -> " . implode(', ', $result->getErrorMessages()));
}
}
?>
Таким образом, мы обновляем уже существующие коды, даже если они были заданы ранее.
Дополнения и советы
- Фильтр по разделам: Если нужно обрабатывать только элементы конкретного раздела (с учётом вложенных), в фильтре указывайте:
Аналогично и в D7-методе. Либо используйте зависимость от структуры вашего ORM-класса.'filter' => [ 'IBLOCK_ID' => $iblockId, 'SECTION_ID' => $sectionId, 'INCLUDE_SUBSECTIONS' => 'Y' ]
- Оптимизация: При большом объёме элементов (тысячи и десятки тысяч) используйте постраничную выборку (параметры limit, offset) или batch-обработку. Иначе скрипт может превысить время выполнения.
- Уникальность: Если в инфоблоке необходимо, чтобы коды были уникальными, стоит дополнительно проверять конфликты. По умолчанию 1С-Битрикс иногда сам добавляет суффиксы вида -1, -2 и т.д. Но если хотите контролировать это программно, придётся писать дополнительную логику.
- Логирование: Функция AddMessage2Log() отлично подходит для отладки. Результаты можно смотреть в /bitrix/logs/ (или другом месте, в зависимости от конфигурации). Для продакшн-среды имеет смысл реализовать более гибкий механизм, если данных очень много, чтобы не раздувать файлы логов.
Итоги
Мы продемонстрировали, как массово обработать символьные коды у элементов целого инфоблока (или его раздела) в 1С-Битрикс:
- Старое ядро (CIBlockElement) — два примера кода:
- Если у элемента код есть, мы не трогаем его, если нет — формируем транслитом из названия.
- Если код есть — обновляем по новым правилам (транслитерируем заново).
- Новое ядро D7 — аналогичные два примера:
- Логика «код есть — не меняем».
- Логика «всегда обновляем код» (перезаписываем).
Везде задействованы массив $params для CUtil::translit() и функция AddMessage2Log() для журналирования хода выполнения. При необходимости вы легко можете адаптировать эти скрипты под свои нужды: фильтровать нужный инфоблок, нужный раздел, модифицировать или ужесточать правила генерации символьного кода.