В процессе разработки отчетов на базе Системы компоновки данных (СКД) часто возникает необходимость вмешаться в процесс формирования данных. Типичный сценарий: нам нужно получить значение, которое пользователь установил в отборах на форме, чтобы передать его во внешнюю функцию или использовать для формирования временной таблицы в модуле объекта. Поскольку настройки компоновщика представляют собой сложную структуру, прямое обращение к значениям может вызвать затруднения.
В этой статье мы подробно разберем, как правильно извлекать значения отборов, почему поиск по индексу — это плохая практика, и как обработать сложные случаи, такие как вложенные группы отборов.
Прежде чем переходить к коду, проанализируем, где именно хранятся настройки. В объекте КомпоновщикНастроек есть три важные коллекции:
Для получения итогового результата, который учитывает все три источника, необходимо использовать метод КомпоновщикНастроек.ПолучитьНастройки(). Именно этот метод возвращает "финальный" вариант настроек, который будет применен при выполнении компоновки.
Если структура отчетов простая и вы уверены, что пользователь не создает вложенных групп (И/ИЛИ), можно использовать цикл для поиска нужного поля. Рассмотрим пример получения значения отбора по полю ДоговорКлиента.
Выясним причину, почему поиск по индексу (например, Получить(0)) опасен: пользователь может изменить порядок отборов, добавить новые или удалить старые. В этом случае ваш код либо упадет с ошибкой, либо получит неверные данные.
Правильный подход выглядит следующим образом:
// В модуле объекта отчета (например, в событии ПриКомпоновкеРезультата)
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
ТребуемоеПоле = Новый ПолеКомпоновкиДанных("ДоговорКлиента");
ЗначениеДоговора = Неопределено;
Для Каждого Элемент Из Настройки.Отбор.Элементы Цикл
// Проверяем, является ли элемент обычным отбором (не группой)
Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
Если Элемент.ЛевоеЗначение = ТребуемоеПоле И Элемент.Использование Тогда
ЗначениеДоговора = Элемент.ПравоеЗначение;
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если ЗначениеДоговора = Неопределено Тогда
// Обработка ситуации, когда отбор не заполнен или не найден
КонецЕсли;
Рассмотрим более сложную ситуацию. Пользователь может сгруппировать отборы (например, "Договор = А ИЛИ Договор = Б"). В этом случае линейный цикл из предыдущего примера не найдет поле, так как оно будет находиться внутри объекта ГруппаЭлементовОтбораКомпоновкиДанных.
Разберем по шагам, как реализовать универсальную функцию поиска:
Функция НайтиЗначениеОтбора(КоллекцияЭлементов, ИмяПоля) Экспорт
ПолеПоиска = Новый ПолеКомпоновкиДанных(ИмяПоля);
Для Каждого Элемент Из КоллекцияЭлементов Цикл
Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
Если Элемент.ЛевоеЗначение = ПолеПоиска И Элемент.Использование Тогда
Возврат Элемент.ПравоеЗначение;
КонецЕсли;
ИначеЕсли ТипЗнч(Элемент) = Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
// Рекурсивно заходим в группу
РезультатПоиска = НайтиЗначениеОтбора(Элемент.Элементы, ИмяПоля);
Если РезультатПоиска <> Неопределено Тогда
Возврат РезультатПоиска;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункции
Использование этой функции в модуле объекта:
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
ДоговорКлиента = НайтиЗначениеОтбора(Настройки.Отбор.Элементы, "ДоговорКлиента");
Проанализируем профессиональный прием, который часто используют опытные разработчики 1С. Чтобы не "бегать" по коллекции отборов, можно связать отбор с параметром СКД.
В схеме СКД на закладке "Параметры" создайте параметр ДоговорКлиента. Затем на закладке "Настройки" -> "Отбор" добавьте отбор по полю ДоговорКлиента, а в колонке "Использование" укажите, что это поле связано с созданным параметром.
Теперь получить значение гораздо проще, так как параметры доступны по имени:
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
ПараметрДоговор = Настройки.ПараметрыДанных.Элементы.Найти("ДоговорКлиента");
Если ПараметрДоговор <> Неопределено И ПараметрДоговор.Использование Тогда
ЗначениеДоговора = ПараметрДоговор.Значение;
КонецЕсли;
При программном извлечении значения отбора важно учитывать ВидСравнения. Посмотрим на пример: если пользователь выбрал вид сравнения В списке, то в свойстве ПравоеЗначение будет находиться не ссылка на один объект, а объект типа СписокЗначений.
Рекомендация: всегда проверяйте тип полученного значения перед использованием в запросах или передачей в другие модули. Если ваш алгоритм ожидает только одну ссылку, добавьте проверку ТипЗнч(ДоговорКлиента).
Также стоит помнить о методе КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(). Это встроенный метод платформы, который позволяет быстро найти объект параметра по его имени (типа ПараметрКомпоновкиДанных), что гораздо эффективнее ручного перебора коллекций.
Мы рассмотрели несколько способов получения значений отборов в СКД. Для простых задач подойдет линейный перебор через ПолучитьНастройки(), для сложных иерархических настроек лучше использовать рекурсию, а для наиболее стабильной работы рекомендуется использовать связку отбора с параметром. Выбор метода зависит от архитектуры вашего отчета и требований к гибкости настроек для пользователя.