Данная проблема очень актуальна для проектов в которых каталоги состоят из тысяч позиций. Примером может послужить каталог автозапчастей для всех марок, годов и т.д.
При использовании стандартного компонента bitrix:catalog.section.list на таком большом количестве элементов в секциях с определенным параметром вызова "COUNT_ELEMENTS" => "Y" возможна ситуация при которой формируется достаточно ресурсоемкий запрос с подсчетом всех элементов в секциях. [spoiler]
Решением в данной ситуации может стать хранение количества элементов в пользовательском свойстве секции. Это существенно снизит нагрузку на сервер и повысит скорость загрузки страницы.
В нашем случае мы рассмотрим работу компонента на каталоге товаров, который можно с генерировать на сайте с помощью мастера создания демо сайта. Для более наглядной демонстрации создадим в нем дополнительные позиции.
По итогам диагностики в режиме отладки видим, что время выполнения компонента не допустимо велико.
Разобьем решение задачи на 3 этапа: 1 Подготовка компонента для вывода значений пользовательского свойства 2 Подготовка обработчика для обновления пользовательского свойства 3 Подготовка страницы административного раздела для пересчета количества элементов во всех секциях каталога.
Подготовка компонента для вывода значений элементов в секции.
При формировании вызова API добавляем четвертый параметр для вывода заранее зарезервированного нами пользовательского свойства в котором будем хранить количество элементов в секции - UF_BX_ELEMENT_CNT.
Далее создаем в шаблоне нашего компонента файл, который позволяет модифицировать результат выполнения компонента перед его выводом на страницу result_modifier.php и размещаем его по адресу bitrix\components\my_site\catalog.section.list\templates\tree\result_modifier.php
В данном файле размещаем обработку результирующего массива компонента
if($arParams["COUNT_ELEMENTS"]):
foreach($arResult[SECTIONS] as $k=>$arrResult):
$arResult[SECTIONS][$k][ELEMENT_CNT] = $arrResult[UF_BX_ELEMENT_CNT];
endforeach;
endif;
При желание в фале result_modifier.php не изменяя самого компонента можно получать значения пользовательских полей, но данный подход увеличит общее количество запросов на странице. В данной реализации задачи мы рассматриваем вариант, когда с помощью одного вызова API мы можем получить все необходимые поля.
На этом подготовка компонента для вывода значений элементов в секции закончена.
Подготовка обработчика для обновления пользовательского свойства.
Рассмотрим вариант для не большого каталога и заранее известного ID информационного блока в котором находится каталог.
Обновление значений пользовательский полей необходимо производить через обработчик добавления и обновления элемента в раздел. Для примера опишем обработчик на добавления и обновления элемента, который вызывается после успешной попытки добавления элемента. Предположим, что пользовательское поле UF_BX_ELEMENT_CNT уже существует для данного информационного блока.
В случаи удачной попытки создания элемента или его обновления получаем список всех секций для которых нам необходимо обновить значения пользовательского свойства и производим обновление значений
При чем производится обновление свойства и пересчет элементов, как для текущей секции так и для секции родителя, если такая существует. Данный обработчик позволяет сравнительно для небольшого каталога обновлять данные о количестве элементов, создавая нагрузку на сервер только в момент добавления/обновления элемента
Для большого каталога целесообразнее проводить единовременное обновление данных всего каталога, не создавая нагрузку на сервер каждый раз, когда необходимо добавит или изменить значения пользовательского свойства. Для этого создадим раздел в административной части сайта.
Подготовка страницы административного раздела для пересчета значений элементов всех секциях каталога
Далее необходимо создать страницу в административном разделе системы с которой нам предстоит работать. Рассмотри случай для перерасчета всех элементов для всего каталога
При построение ниспадающего списка формируем следующий вызов
в котором в порядке полного развернутого дерева разделов выводим структуру каталогов.
Далее в теле страницы производим перебор всего полученного дерева, считаем количество элементов в секциях и обновляем наше пользовательское поле UF_BX_ELEMENT_CNT
Для определенного каталога операция пересчета производится в целом та же , только мы не обращаемся к дереву каталогов, а формируем вызовы API с уже предустановленными значениям
$ar_result['ID'] = intval($_REQUEST[select_search]);
$nav = CIBlockSection::GetNavChain($IBLOCK_ID, $ar_result[ID]);
while ($arNav=$nav->GetNext()):
$CNT = CIBlockSection::GetSectionElementsCount($arNav["ID"]);
$bs = new CIBlockSection;
...
Необходимо заметить, что в случае когда нами выбраны для пересчета дочерний раздел каталога значения пересчитываются, как для выбранного дочернего каталога так и для каталога родителя. В первом рассмотренном варианте пересчитываются элементы каждого раздела из дерева каталогов без повторного обновления пользовательских свойств родительских разделов.
После выполнения каждой операции обновления свойства производится подготовка и сбор данных для формирования отчета, который доступен после работы скрипта.
Преимущества данной реализации заключаются в единовременном пересчете всего каталога, не выполняя операцию каждый раз при добавление или обновлении элемента.
Данный способ пересчета можно использовать как для решение задач на каталогах с малым объемом информации так и с большим. Данный способ также может успешно использовать вместе с обработчиками, которые ранее были предложены на втором этапе решения задачи.
В итоге если были выполнены все рекомендации при вызове компонента my_site:catalog.section.list на странице с установленным параметром "COUNT_ELEMENTS" => "Y" получаем общее время выполнения компонента значительно меньше, чем показал нам до этого системный.
Архив для скачивания включает в себя файлы component.php - файл модифицированного компонента init.php - файл с обработчиками событий result_modifier.php - файл позволяющий модифицировать результат компонента перед выводом в шаблон cnt_element.php - страница административного раздела
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».