1С-Битрикс. Характеристики в отдельные свойства при выгрузке из 1С
При выгрузке товаров из 1С у инфоблока с товарами создаётся поле «Характеристики» типа «Строка» с возможностью множественных значений. Если мы хотим, чтобы значения характеристик участвовали в умном фильтре, то значения каждой характеристики должны быть в отдельных свойствах. «Из коробки» этого не предусмотрено. Написал обработчик, который сделает всё хорошо.
Чем отличается от остальных
На форумах битрикса можно найти похожие обработчики, но они не решают главной проблемы — свойства каждой характеристики должны быть типа «Список». Ну и к тому же у них не очень оптимизированный код.
Код обработчика
$eventManager = \Bitrix\Main\EventManager::getInstance(); $eventManager->addEventHandlerCompatible('iblock', 'OnAfterIBlockElementUpdate', array('ext1cHandler', 'attributeFieldToProps')); $eventManager->addEventHandlerCompatible('iblock', 'OnAfterIBlockElementAdd', array('ext1cHandler', 'attributeFieldToProps')); class ext1cHandler { const CML2_ATTRIBUTES_NAME = 'CML2_ATTRIBUTES'; protected static $iblockProps = null; /** * @param $iblockId * @return array|null */ protected static function getIblockProps($iblockId) { if (self::$iblockProps === null) { $resProps = CIBlock::GetProperties($iblockId, Array(), Array()); if (intval($resProps->SelectedRowsCount()) > 0) { self::$iblockProps = array(); while ($arProp = $resProps->Fetch()) { self::$iblockProps[$arProp['CODE']] = $arProp['ID']; } } } return self::$iblockProps; } /** * @param $arFields */ public static function attributeFieldToProps($arFields) { if (!self::is1cSync()) return true; self::getIblockProps($arFields['IBLOCK_ID']); if (empty(self::$iblockProps) || !is_array(self::$iblockProps)) return; //получаем массив значений множественного свойства CML2_ATTRIBUTES в которое стандартно выгружаются характеристики ТП из 1С $resCml2Attributes = CIBlockElement::GetProperty($arFields['IBLOCK_ID'], $arFields['ID'], array('sort' => 'asc'), array('CODE' => self::CML2_ATTRIBUTES_NAME)); while ($arCml2Attribute = $resCml2Attributes->GetNext()) { $cml2AttributeName = $arCml2Attribute['DESCRIPTION']; //название характеристики $cml2AttributeValue = $arCml2Attribute['VALUE']; //значение характеристики // создание свойства $codeNewProp = self::getTranslit($cml2AttributeName); if (!isset(self::$iblockProps[$codeNewProp])) { $arFieldsProp = array( 'NAME' => $cml2AttributeName, 'ACTIVE' => 'Y', 'SORT' => '500', 'CODE' => $codeNewProp, 'PROPERTY_TYPE' => 'L', 'IBLOCK_ID' => $arFields['IBLOCK_ID'], 'VALUES' => array(), ); $ibp = new CIBlockProperty; if ($propId = $ibp->Add($arFieldsProp)) { self::$iblockProps[$codeNewProp] = $propId; } } if (isset(self::$iblockProps[$codeNewProp])) { self::getEnumListProp($arFields['IBLOCK_ID'], self::$iblockProps[$codeNewProp]); $xmlIdPropValue = self::getTranslit($cml2AttributeValue); if (!isset(self::$enumListProps[self::$iblockProps[$codeNewProp]][$xmlIdPropValue])) { $ibpenum = new CIBlockPropertyEnum; $arFieldsEnum = array( 'XML_ID' => $xmlIdPropValue, 'PROPERTY_ID' => self::$iblockProps[$codeNewProp], 'VALUE' => $cml2AttributeValue ); if ($enumPropValueId = $ibpenum->Add($arFieldsEnum)) { self::$enumListProps[self::$iblockProps[$codeNewProp]][$xmlIdPropValue] = $enumPropValueId; } } if (isset(self::$enumListProps[self::$iblockProps[$codeNewProp]][$xmlIdPropValue])) { CIBlockElement::SetPropertyValues($arFields['ID'], $arFields['IBLOCK_ID'], array( 'VALUE' => self::$enumListProps[self::$iblockProps[$codeNewProp]][$xmlIdPropValue] ), self::$iblockProps[$codeNewProp]); } } } } private static $enumListProps = array(); /** * @param $iblockId * @param $propId * @return array */ protected static function getEnumListProp($iblockId, $propId) { if (!isset(self::$enumListProps[$propId])) { $resEnumField = CIBlockPropertyEnum::GetList(array('SORT' => 'ASC'), array('IBLOCK_ID' => $iblockId, 'PROPERTY_ID' => $propId)); if (intval($resEnumField->SelectedRowsCount()) > 0) { self::$enumListProps[$propId] = array(); while ($arEnumField = $resEnumField->Fetch()) { self::$enumListProps[$propId][$arEnumField['XML_ID']] = $arEnumField['ID']; } } } return self::$enumListProps; } /** * @param $text * @param string $lang * @return string */ private static function getTranslit($text, $lang = 'ru') { $resultString = CUtil::translit($text, $lang, array( 'max_len' => 50, 'change_case' => 'U', 'replace_space' => '_', 'replace_other' => '_', 'delete_repeat_replace' => true, ) ); if (preg_match('/^[0-9]/', $resultString)) { $resultString = '_' . $resultString; } return $resultString; } /** * @return bool */ private static function is1cSync() { static $is1C = null; if ($is1C === null) { $is1C = (isset($_GET['type'], $_GET['mode']) && $_GET['type'] === 'catalog' && $_GET['mode'] === 'import'); } return $is1C; } }
Как обычно код класса надо сохранить в отдельный файл и подключить в init.php.
11 комментариев
Ваш код как и на форуме битрикса будет отрабатывать первый элемент не правильно, вы перезаписываете переменную $arFields
В этой части кода
Нужно заменить переменую $arFields на (к примеру) $arFields_add
для корректной работы.
Но огромное Вам спасибо за эту прелесть, со списками куда удобнее работать :) !
Не первый элемент, а каждый раз когда нужно добавить новое свойства...
Верно подмечено, спасибо! Обновил заметку.
Добрый день. Подключил в init.php через CModule::AddAutoloadClasses( '', array( 'CClass1' => '/bitrix/php_interface/class1.php' ) ); Но теперь инфоблок с предложения совсем не выгружается из 1с. Могли ли произойти какие то изменения в самом битрикс, которые препятствуют выгрузке. Стоит последня редакция бизнес, без каких либо изменений
Михаил, не должны. Проверяйте и дебажте.
Спасибо за решение!
Спасибо за решение! Прошу помощи в подключении, почему-то характеристики автоматически не разбиваются.
Содержимое init.php:
В split_attributes.php точная копия вашего кода. Делаю выгрузку из 1С - создаются товары с одной общей характеристикой, свойства не разбиваются (не создаются). Что я делаю не так? Как запустить шайтан-машину?
Допилить сайт на Битрикс - задача, оказывается, совсем не тривиальная. Олег оперативно помог в решении возникшей проблемы, стоило только обратиться к нему напрямую через форму обратной связи. Профессионал с большой буквы. Спасибо!
Олег, добрый день! У меня та же проблема, что и у Ивана - не создаются новые свойства. Подскажите, что надо подкрутить.
Олег, добрый день! У меня та же проблема, что и у Ивана - не создаются новые свойства. Правда мне не для характеристик а для реквизитов, я изменил: const CML2_ATTRIBUTES_NAME = 'CML2_ATTRIBUTES'; на const CML2_ATTRIBUTES_NAME = 'CML2_TRAITS';
Но все осталось как прежде.
Подскажите, что надо подкрутить.
Заранее спасибо.
спасибо пригодилось!