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