Уже достаточно давно у битрикса появился новый тип свойств инфоблоков, "Справочник", основанный на привязке элементов инфоблока к элементам хайлоад-инфоблоков. Как известно, данный вид свойств имеет связку не по ИД значения справочника, а по полю "UF_XML_ID". Иногда может возникнуть ситуация, когда в справочнике дублируются значения с одинаковым внешним кодом (при не очень грамотно построенном механизме добавления новых значений в справочник). Тогда на помощь в очистке справочника может прити данный скрипт.
Уже достаточно давно у битрикса появился новый тип свойств инфоблоков, "Справочник", основанный на привязке
элементов инфоблока к элементам хайлоад-инфоблоков. Как известно, данный вид свойств имеет связку не по ИД значения
справочника, а по полю "UF_XML_ID". Иногда может возникнуть ситуация, когда в справочнике дублируются значения с
одинаковым внешним кодом (при не очень грамотно построенном механизме добавления новых значений в справочник). Тогда
на помощь в очистке справочника может прити данный скрипт.
Я для каждого проекта создаю отдельный модуль, в который помещаю все функции и константы проекта, поэтому в коде будут появляться некоторые методы абстрактного класса `siteclass` из модуля `sitemodule`.
Начнем с подключения модуля:
<? require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php'); \Bitrix\Main\Loader::includeModule('sitemodule');
Далее - определяем сущность класса и выбираем ИД хайлоад-инфоблока со справочником:
$mainEntity = new siteclass(); $entityID = $mainEntity::ATC; // ATC - константа с ИД хайлоад-инфоблока
и выбираем все значения из справочника:
$tmp = $mainEntity->GetAllInVacabulary($entityID); $arRows = array(); foreach ($tmp['ITEMS'] as $arRow) { $arRows[] = $arRow; }
Метод, выбирающий все значения из справочника имеет вид:
function GetAllInVacabulary($entity){ return self::SearchInHLVacabulary('', $entity); } function SearchInHLVacabulary($code, $VHlblock, $groupKey = 'UF_XML_ID'){ $code = trim($code); $cacheParams = array( 'code' => $code, 'entity_id' => $VHlblock, 'module' => 'HighloadIblock', 'function' => __FUNCTION__ ); $cache_id = md5(serialize($cacheParams)); $cache_dir = __CLASS__ . '/' . $cacheParams['module']; $obCache = new CPHPCache; if ($obCache->InitCache(36000, $cache_id, $cache_dir)) { $arResult = $obCache->GetVars(); $arResult['CACHE'] = 'Y'; } elseif (\Bitrix\Main\Loader::includeModule('highloadblock') && $obCache->StartDataCache()) { global $CACHE_MANAGER; $CACHE_MANAGER->StartTagCache($cache_dir); $hlblock_requests = HL\HighloadBlockTable::getById($VHlblock)->fetch();//requests $entity_requests = HL\HighloadBlockTable::compileEntity($hlblock_requests); $entity_requests_data_class = $entity_requests->getDataClass(); $main_query_requests = new Entity\Query($entity_requests_data_class); $main_query_requests->setSelect(array('ID', 'UF_NAME', 'UF_XML_ID')); if (strlen($code) > 0) { $main_query_requests->setFilter(array('UF_XML_ID' => $code)); } $result_requests = $main_query_requests->exec(); $result_requests = new CDBResult($result_requests); $arResult['ITEMS'] = array(); while ($row_requests = $result_requests->Fetch()) { $arResult['ITEMS'][$row_requests[$groupKey]] = $row_requests; $CACHE_MANAGER->RegisterTag('hl' . $cacheParams['entity_id'] . $row_requests[$groupKey]); } $CACHE_MANAGER->RegisterTag('hl' . $cacheParams['entity_id']); $CACHE_MANAGER->EndTagCache(); $obCache->EndDataCache($arResult); } else { $arResult['ITEMS'] = array(); } return $arResult; }
Далее пишем пошаговый аяксовый js-обработчик/ Контейнер для информации о ходе обработки:
<div id="loading"><p class="persents"> Обработка: <span class="pv">0</span>% (Строка: <span class="rv">1</span>/<?= count($arRows) ?>) </p> </div>
И сам js-скрипт (простите за смесь jquery и битриксовой JS-библиотеки - я ленивый и очень не хочется имеющийся в битриксе прелоадер переписывать):
<script type="text/javascript"> var ajaxurl = '/bitrix/admin/sitemodule_ajax.php'; // url to pass ajax requests var Rows = <?=json_encode($arRows);?>; var countRows = <?=count($arRows);?>; function work_with_row(num, callback, triesCount) { var Persents = (parseInt(num) + 1) * 100 / parseInt(countRows); $('p.persents').find('span.pv').html(Math.round(Persents)); $('p.persents').find('span.rv').html(parseInt(num) + 1); $.ajax({ type: "POST", url: ajaxurl, data: {action: 'ClearVacabulary', Row: Rows[num],entity:<?=$entityID?>}, dataType: "json", async: false, success: function () { callback(num + 1); }, error: function () { triesCount = triesCount || 0; if (triesCount > 5) { callback(num + 1); } else { setTimeout(function () { work_with_row(num, callback, triesCount + 1); }, 5000); } } }); } $(document).ready(function () { var wait = BX.showWait('loading'); var maxIndex = Rows.length; var run = function (index) { if (index < maxIndex) { setTimeout(function () { work_with_row(index, run); }, index > 0 ? 200 : 0) } else { $('p.persents').html('Обработка завершена'); BX.closeWait('loading', wait); } }; run(0); }); </script>
немного по коду: Сначала определяем путь к файлу-обработчику аяксовых-запросов.
Далее - определяем переменные с набором полученных значений справочника и с количеством этих значений.
Функция work_with_row
обрабатывает одно конкретное значение справочника. Подробнее о функции - ниже.
Работа скрипта начинается с показа битриксового прелоадера и определения значения, когда обработчику пора остановиться.
Дальше - вызываем функцию-обработчик шага, которая с таймаутом в 200 милисекунд запускает обработку выбранного шага с рекурсией.
Когда все строки обработаны - показываем пользователю соответствующее сообщение.
Теперь по функции обработки каждой строки. Сначала функция меняет индикатор работы скрипта. После этого, идет отправка аякс-запроса на сервер. В случае успешно отработавшего запроса, запускается обработка следующего шага. Если же обработка аякс-запроса не отработала (сервер, например свалился, или интернет-соединение пропало), делаем еще 5 попыток с увеличенным таймаутом (5 сек.). Если за 5 попыток так и не удалось произвести запрос - пропускаем его.
Последний штрих - обработчик аякс-запроса. В принимающем файле прописываем:
\Bitrix\Main\Loader::includeModule('sitemodule'); $mainEntity = new siteclass(); $arRow = $_POST['Row']; $entityID = $_POST['entity']; if(!empty($arRow) && intval($arRow['ID'])>0 && intval($entityID)>0){ $tmp=$mainEntity->SearchInHLVacabulary($arRow['UF_XML_ID'],$entityID,'ID'); if(count($tmp['ITEMS'])>1){ $isFirst = true; $arResult['ITEMS'] = $tmp['ITEMS']; foreach ($tmp['ITEMS'] as $arSubRow) { if($isFirst){ $isFirst = false; continue; } $arResult['RES'] = $mainEntity->RemoveFromHlVacabulary(intval($arSubRow['ID']),$entityID); } } } echo json_encode($arResult);
Снова подключаем класс, определяем сущность, получаем инфомрацию о строке. Далее - ищем информацию в справочнике по значению XML_ID - результатом будет
список всех значений справочника с одинаковым внешним кодом. Далее - запускаем обработку по полученным значениям (если значений больше 1).
Первое значение пропускаем, а все остальные - удаляем. Метод SearchInHLVacabulary
имеет вид:
function RemoveFromHlVacabulary($arValueID, $VHlblock){ if (!\Bitrix\Main\Loader::includeModule('highloadblock')) return false; if(intval($arValueID)<=0) return false; global $CACHE_MANAGER; $rsData = HL\HighloadBlockTable::getList(array('filter' => array('ID' => $VHlblock))); if (!($arData = $rsData->fetch())) { return 'Инфоблок не найден'; } $Entity = HL\HighloadBlockTable::compileEntity($arData); $DataClass = $Entity->getDataClass(); $result = $DataClass::delete($arValueID); if (!$result->isSuccess()) return array('error' => $result->getErrorMessages()); else { $CACHE_MANAGER->ClearByTag('hl' . $VHlblock . $arValueID); $CACHE_MANAGER->ClearByTag('hl' . $VHlblock); return 'OK!'; } }
Вот такой вот маленький пример:) Понимаю, что для удаления можно было бы и более оптимальный код написать, с меньшим количеством отправок данных на сервер, но на примере этого кода можно делать не только удаление, но и более тяжелые обработки данных
Разработка сайта
Подайте заявку на разработку сайта на базе готового решения от компании 1С-Битрикс или одного из партнеров компании. Максимально подробно опишите, чему будет посвящен сайт, если это интернет-магазин - что он будет продавать, нужна ли мультиязычность, будут ли разные типы цен (розница, опт, крупный опт), будет ли интеграция с 1С, будет ли выгрузка товаров на различные торговые площадки...
Сопровождение сайта
Вы можете подать заявку на сопровождение вашего сайта на базе 1С-Битрикс. Сопровождение включает в себя: проверка актуальности обновлений сайта, проверка актуальности резервной копии, консультации по сайту. Опишите в заявке, какие еще объемы планируются на сопровождении и на какой срок вы планируете заключить договор на сопровождение - мы подберем подходящий вам бюджет на сопровождение
Работы по сайту
Вы можете подать заявку на выполнение определенного объема работ по сайту. Опишите в заявке объем работ. Это может быть разработка какого-то нового функционала, доработки по имеющемуся функционалу, доработки под требования сео-специалистов. На основании заявки вам будет сформирован бюджет работ, а также названы сроки на выполнение тех или иных работ.