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