На сайте клиента должны появляться все нововведения, пришедшие в обновлениях продукта.
Доработки должны быть максимально изолированы от процесса импорта. Чтобы можно было их отключить, подтвердить, что проблема не у нас на канале, и отправить баг-репорт в саппорт.
Работы по мержингу доработок с обновлённым сайтом должны либо отсутствовать, либо быть минимальными в особо критичных ситуациях.
Из этих требований вытекают условия — совсем не трогать класс CIBlockCMLImport и стараться не трогать catalog.import.1c. Практически во всех наших задачах этого можно достичь с помощью обработчиков.
iblock.OnStartIBlockElementAdd / iblock.OnStartIBlockElementUpdate Знакомые, наверное, почти каждому события. Вызываются перед добавлением/обновлением элемента инфоблока до валидации полей и свойств, первым аргументом передаётся &$arFields. С помощью них можно назначать обязательные, но отсутствующие значения характеристик товаров, давать уникальные символьные коды по своим алгоритмам и менять привязку к разделам.
iblock.OnAfterIBlockElementAdd / iblock.OnAfterIBlockElementUpdate События вызываются после создания/обновления элемента инфоблока. В обработчик первым аргументом передаётся &$arFields. При использовании OnAfterIBlockElementAdd стоит помнить, что оно вызывается в любом случае — хоть при успешно созданном элементе, хоть при ошибке. Поэтому надо обязательно проверять ключ RESULT и корректировать логику в зависимости от него. Через эти обработчики можно производить действия постфактум — создать вспомогательные записи в БД, что-то где-то обновить и т.п. Например, создать элемент в ИБ «Производители» и привязать к нему товар, если в выгрузке значение свойства — строка, а не ссылка на справочник. Или пронаследовать некоторые характеристики всех торговых предложений в основной товар для более быстрой фильтрации в каталоге.
catalog.OnSuccessCatalogImport1C Самое вкусное оставил напоследок. Данное событие появилось около года назад. Вызывается оно в компоненте catalog.import.1c в самом конце импорта — перед отдачей строки success, сигнализирующей 1Ске об успешном окончании обмена. С помощью этого события можно организовать пост-обработку импортированных товаров/ТП - перегенерировать неуправляемый кеш, вычислить диапазон цен для товара с торговыми предложениями, импортировать скидки как нативные битриксовые скидки. Стоит заметить, что на этом шаге весь xml-файл ещё доступен в таблице b_xml_tree, поэтому потенциал события огромен. А если прибавить к этому ещё и возможность реализации пошаговости, то можно сделать свой маленький изолированный импорт без каких-либо модификаций основного так, что 1Ска ничего и не заподозрит:-) Собственно, это событие и его обсуждение тут и сподвигло написать данный пост — показать, как можно на основе этого события реализовать пошаговость. Пример (с подсветкой):
AddEventHandler('catalog', 'OnSuccessCatalogImport1C', 'customCatalogImportStep');
function customCatalogImportStep()
{
$stepInterval = (int) COption::GetOptionString("catalog", "1C_INTERVAL", "-");
$startTime = time();
// Флаг импорта файла торговых предложений
$isOffers = strpos($_REQUEST['filename'], 'offers') !== false;
$NS = &$_SESSION["BX_CML2_IMPORT"]["NS"];
if (!isset($NS['custom']['lastId'])) {
// Последний отработанный элемент для пошаговости.
$NS['custom']['lastId'] = 0;
$NS['custom']['counter'] = 0;
}
// Условия выборки элементов для обработки
$arFilter = array(
'IBLOCK_ID' => 1024,
'ACTIVE' => 'Y',
);
$res = CIBlockElement::GetList(array('ID' => 'ASC'), array_merge($arFilter, array('>ID' => $NS['custom']['lastId'])));
$errorMessage = null;
while ($arItem = $res->Fetch()) {
/*
// Что-нибудь делаем
if (updateElement($arItem['ID']) === false) {
$error = true;
}
*/
if ($error === true) {
$errorMessage = 'Что-то случилось.';
break;
}
$NS['custom']['lastId'] = $arItem['ID'];
$NS['custom']['counter']++;
// Прерывание по времени шага
if ($stepInterval > 0 && (time() - $startTime) > $stepInterval) {
break;
}
}
if ($arItem != false) {
if ($errorMessage === null) {
print "progress\n";
print "Обработано " . $NS['custom']['counter'] . ' элементов, осталось ' . $res->SelectedRowsCount();
} else {
print "failure\n" . $errorMessage;
}
$contents = ob_get_contents();
ob_end_clean();
if (toUpper(LANG_CHARSET) != "WINDOWS-1251") {
$contents = $GLOBALS['APPLICATION']->ConvertCharset($contents, LANG_CHARSET, "windows-1251");
}
header("Content-Type: text/html; charset=windows-1251");
print $contents;
exit;
}
}
В примере происходит выборка из некоего инфоблока и совершение действий над элементами этого инфоблока. Если при обновлении произошла ошибка, 1Ске вернётся статус failure с текстом ошибки. Если всё успешно прошло, происходит выход из обработчика и компонент catalog.import.1c завершает работу (обнуляет сессию и возвращает success).
Заключение Вот как-то так мы и работаем с 1ской — пишем тз, рисуем таблички, генерим примеры и изворачиваемся подобными способами в особых ситуациях:-)
Скоропупов Вячеслав, вы пишите некую выборку, на каждой итерации обрабатываете по одному элементу из этой выборки. Если время работы хита после очередной итерации превысило длительность шага, обработка прерывается и отдаётся команда в 1с на выполнение следующего шага. Понять принцип детальнее можно, ознакомившись с кодом функции customCatalogImportStep().
А какой событие отвечает за добавление элемента в HighLoad-блок? Мне нужно при создании записи в хайлоад справочнике, получать и обрабатывать поля записи.
Андрей Нейман, добрый день. Предстоит решение задачи кастомизации импорта из 1С. Подскажите пожалуйста: 1) метод указанный в данном блоге по-прежнему самый актуальный? Ничего другого за это время не придумали? 2) подойдет ли данный метод если после стандартного обмена 1С необходимо обработать произвольный другой xml файл? Поясню как я это вижу сейчас - в файле товаров заведен новый реквизит Изготовитель, в котором ID указан из произвольного файла, условно manufactures.xml. Данный файл также придет из 1С в результате обмена. Т.е. надо обработать файл manucfactures.xml, сохранить данные в highload блок, а потом пробежаться по импортированным товарам, из таблицы b_xml_tree дернуть рекзвизит Изговитель и обновить товары - привязать изготовителя по этому рекзвизиту.
Нейман Андрей, я правильно понимаю - даже если заканчивается отведенный интервал времени и скрипт выдает progress\n"; print "Обработано " . $NS['custom']['counter'] . ' элементов, осталось ' . $res->SelectedRowsCount();
то 1С еще раз отправляет запрос? т.е. каким образом сама пошаговость сделана?
Запустил обмен с 1С. 1С получил success 5 раз. Скрипт выполнился 5 раз. Ну а мне нужно выгружать каталог маркет только при полном завершении обмена 1С .
Виталий, используйте тогда событие catalog:OnCompleteCatalogImport1C. Но с большой долей вероятности фокус с progress там не сработает, надо использовать событие только как флаг, а пошаговую обработку вести, например, по крону.
Там проверяется наличие определенного свойства и либо деактвируется элемент ($arFields['ACTIVE'] = 'N';) либо перемещается в другой раздел ($arFields['IBLOCK_SECTION'] = ******)
Так вот самое интересное в том, что эти обработчики выполняются при редактировании/добавлении элементов через админку. Но если выполнить полный импорт из 1С, то дата изменения элементов меняется, но никаких действий по обработчикам не выполнено. Элементы не переместились и не деактивировались
Не могли бы подсказать происходит ли запуск событий указанных выше при импорте?
День добрый. Подскажите пожалуйста. В 1Ске позиции поменяю на Снят с продажи, но на сайт все равно данные позиции, после обмена попадают активными, помечаю, на удаление, тоже не спасает особо. Ни программист 1С ни программисты на сайте не могут мне, помочь, как корректно выгружать данные из 1С на сайт(
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».