Есть множество кусков кода, которые мы повторяем вновь и вновь. Одно и тоже. Однотипные кусочки, которые уже выучили наизусть. Однако, юный программист Василий считает, что копипасты - это зло. И что можно выделить универсальный метод, который позволит выполнить тоже самое, но с меньшим количеством строк кода и усилий разработчика.
1. Постановка цели
У программиста Васи простая задача - вывести программно СКД. Что делает среднестатистический разработчик? Копипастит в код заготовленный шаблон программного вывода. Когда нужно сделать таких выводов несколько штук с разными условиями? Делает несколько кусков однотипного кода, где меняется буквально пара параметров.
Но Вася не такой. Он ещё юн и свеж и полон решимости улучшать всё вокруг.
"Я делаю это, потому что копипасты - Зло!"
И для начала он копипастит пишет этот самый стандартный кусок кода.
//Формируем макет, с помощью компоновщика макета КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; //Передаем в макет компоновки схему, настройки и данные расшифровки МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки); //Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки); //Выводим результат в табличный документ ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент; ПроцессорВывода.УстановитьДокумент(Результат); ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
"Ну всё" - думает Вася.
И действительно, если обернуть данный код в процедуру, то её использование уже поможет убрать из конфигурации несколько кучек стандартного вывода СКД.
Процедура СкомпоноватьРезультатОтчета(Результат, СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки = Неопределено) Экспорт //Формируем макет, с помощью компоновщика макета КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; //Передаем в макет компоновки схему, настройки и данные расшифровки МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки); //Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки); //Выводим результат в табличный документ ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент; ПроцессорВывода.УстановитьДокумент(Результат); ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных); КонецПроцедуры
Этот код достаточно распространён и ещё не раз потребуется в разработке.
Однако, Вася идёт дальше...
2. Варианты применения
"А что, если потребуется вывести результат в таблицу значений?"
Для этого используется немного другой кусок кода.
Вася нашёл его в гугле памяти и выделил для себя те участки, которые отличаются от предыдущего.
//Формируем макет, с помощью компоновщика макета КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; //Передаем в макет компоновки схему, настройки и данные расшифровки МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений")); //Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки); //Выводим результат в табличный документ ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений; ПроцессорВывода.УстановитьОбъект(Результат); ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
Отличия минимальные и юный разработчик берётся за доработку своего метода.
"Я делаю это, потому что нужен умный метод!"
Для этого Вася сначала решает, как метод будет определять необходимость вывода в табличный документ или в коллекцию.
Можно, конечно, сделать просто - добавить параметр в процедуру. Однако, Васин метод должен быть максимально "умным"!
Решено. Будем смотреть на тип параметра "Результат".
//Определяем тип генератора Если ТипЗнч(Результат) = Тип("ТаблицаЗначений") ИЛИ ТипЗнч(Результат) = Тип("ДеревоЗначений") Тогда ВыводВКоллекциюЗначений = Истина; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"); Иначе ВыводВКоллекциюЗначений = Ложь; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанных"); КонецЕсли;
А далее, в зависимости от значения переменной ВыводВКоллекциюЗначений, используем тот или иной код. Вася оглядывает получившийся метод:
Процедура СкомпоноватьРезультатОтчета(Результат, СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки) Экспорт //Определяем тип генератора Если ТипЗнч(Результат) = Тип("ТаблицаЗначений") ИЛИ ТипЗнч(Результат) = Тип("ДеревоЗначений") Тогда ВыводВКоллекциюЗначений = Истина; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"); Иначе ВыводВКоллекциюЗначений = Ложь; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанных"); КонецЕсли; //Формируем макет, с помощью компоновщика макета КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; //Передаем в макет компоновки схему, настройки и данные расшифровки МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки,,ТипГенератораВывода); //Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки); //Выводим результат Если ВыводВКоллекциюЗначений Тогда ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений; ПроцессорВывода.УстановитьОбъект(Результат); Иначе ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент; ПроцессорВывода.УстановитьДокумент(Результат); КонецЕсли; ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных); КонецПроцедуры
Ну вот, теперь наша процедура пригодится ещё в большей части случаев. Василий, откладывает подальше кисть мышку, но вдруг вспоминает, что в его задаче в СКД есть "набор данных объект"...
3. Распространенные параметры
Что мы делаем, когда нужно выполнить СКД с внешним набором данных? Формируем программно точно так же, но с передачей ещё одного параметра:
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
Вот и Василий вспомнил об этом. И решил доработать свою процедуру.
"Я делаю это, потому что никто другой делать не захочет"
Он просто так не сдастся! Тем более, что тут всего лишь пара штрихов.
Процедура СкомпоноватьРезультатОтчета(Результат, СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки = Неопределено, ВнешниеНаборыДанных = Неопределено) Экспорт //Определяем тип генератора Если ТипЗнч(Результат) = Тип("ТаблицаЗначений") ИЛИ ТипЗнч(Результат) = Тип("ДеревоЗначений") Тогда ВыводВКоллекциюЗначений = Истина; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"); Иначе ВыводВКоллекциюЗначений = Ложь; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанных"); КонецЕсли; //Формируем макет, с помощью компоновщика макета КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; //Передаем в макет компоновки схему, настройки и данные расшифровки МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки,,ТипГенератораВывода); //Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки); //Выводим результат Если ВыводВКоллекциюЗначений Тогда ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений; ПроцессорВывода.УстановитьОбъект(Результат); Иначе ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент; ПроцессорВывода.УстановитьДокумент(Результат); КонецЕсли; ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных); КонецПроцедуры
Красота! Всё, этот метод уже покроет большую часть необходимых программных выводов СКД.
Но почему-то Василий недоволен. Ему кажется, что что-то можно улучшить. Но что?
4. Дополнительные параметры
Какая-то неведанная сила толкнула юного разработчика открыть Синтаксис-Помощник...
Взгляните сами
<МакетОформления> (необязательный)
Тип: МакетОформленияКомпоновкиДанных.
Макет оформления, в соответствии с которым необходимо оформлять макет компоновки данных. Если не указан, будет использоваться макет оформления по умолчанию.
<ПроверятьДоступностьПолей> (необязательный)
Тип: Булево.
Определяет, выполнять ли проверку прав на просмотр полей и проверку доступности поля во включенных функциональных возможностях.
Значение по умолчанию: Истина.
<ПараметрыФункциональныхОпций> (необязательный)
Тип: Структура.
Содержит параметры функциональных опций, используемые при исполнении отчета.
<ВозможностьИспользованияВнешнихФункций> (необязательный)
Тип: Булево.
Указывает возможность использования функции общих модулей конфигурации в выражениях компоновки данных.
Значение по умолчанию: Ложь.
<ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр> (необязательный)
Тип: Булево.
Если значение параметра равно Истина, то при отображении результата запроса учитывается право пользователя "Просмотр" на таблицы и поля, участвующие в запросе. Если в отчете или динамическом списке присутствует значение поля недоступного по праву "Просмотр", то выводится пустая ячейка.
Если значение параметра равно Ложь и параметр ПроверятьДоступностьПолей установлен в Истина, то значение выводится, даже если у пользователя нет права "Просмотр".
Значение по умолчанию: Истина.
Василий узнал много нового. И теперь он жаждет открыть это для других.
"Я это делаю, чтобы нести знания!".
Для начала он вставил все найденные параметры в методы.
//Передаем в макет компоновки схему, настройки и данные расшифровки МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки, МакетОформления, ТипГенератораВывода, ПроверятьДоступностьПолей, ПараметрыФункциональныхОпций); //Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, ВозможностьИспользованияВнешнихФункций);
На входе в процедуру он решил выделить для всех новых параметров одну структуру "ДополнительныеПараметры".
Процедура СкомпоноватьРезультатОтчета(Результат, СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки = Неопределено, ВнешниеНаборыДанных = Неопределено, ДополнительныеПараметры = Неопределено) Экспорт
Василий вообще любит структуры. Он сделал отдельную "ПараметрыВывода", где прописал все используемые дополнительные параметры с их стандартными значениями. А потом просто дозаполняет эту структуру.
//Инициализируем дополнительные параметры вывода ПараметрыВывода = Новый Структура; ПараметрыВывода.Вставить("МакетОформления" , Неопределено); ПараметрыВывода.Вставить("ПроверятьДоступностьПолей" , Истина); ПараметрыВывода.Вставить("ПараметрыФункциональныхОпций" , Новый Структура); ПараметрыВывода.Вставить("ВозможностьИспользованияВнешнихФункций" , Ложь); Если НЕ ДополнительныеПараметры = Неопределено Тогда ЗаполнитьЗначенияСвойств(ПараметрыВывода, ДополнительныеПараметры); КонецЕсли;
Вася доволен тем, что получилось:
Процедура СкомпоноватьРезультатОтчета(Результат, СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки = Неопределено, ВнешниеНаборыДанных = Неопределено, ДополнительныеПараметры = Неопределено) Экспорт //Инициализируем дополнительные параметры вывода ПараметрыВывода = Новый Структура; ПараметрыВывода.Вставить("МакетОформления" , Неопределено); ПараметрыВывода.Вставить("ПроверятьДоступностьПолей" , Истина); ПараметрыВывода.Вставить("ПараметрыФункциональныхОпций" , Новый Структура); ПараметрыВывода.Вставить("ВозможностьИспользованияВнешнихФункций" , Ложь); Если НЕ ДополнительныеПараметры = Неопределено Тогда ЗаполнитьЗначенияСвойств(ПараметрыВывода, ДополнительныеПараметры); КонецЕсли; //Определяем тип генератора Если ТипЗнч(Результат) = Тип("ТаблицаЗначений") ИЛИ ТипЗнч(Результат) = Тип("ДеревоЗначений") Тогда ВыводВКоллекциюЗначений = Истина; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"); Иначе ВыводВКоллекциюЗначений = Ложь; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанных"); КонецЕсли; //Формируем макет, с помощью компоновщика макета КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; //Передаем в макет компоновки схему, настройки и данные расшифровки МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки, ПараметрыВывода.МакетОформления, ТипГенератораВывода, ПараметрыВывода.ПроверятьДоступностьПолей, ПараметрыВывода.ПараметрыФункциональныхОпций); //Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, ПараметрыВывода.ВозможностьИспользованияВнешнихФункций); //Выводим результат Если ВыводВКоллекциюЗначений Тогда ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений; ПроцессорВывода.УстановитьОбъект(Результат); Иначе ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент; ПроцессорВывода.УстановитьДокумент(Результат); КонецЕсли; ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных); КонецПроцедуры
Метод, который полностью повторяет возможности платформенных, но при этом удобно обёрнут в универсальную процедуру.
"Ну теперь точно всё!".
И решил добавить ещё хотелочку...
5. Прихоть в мелочах
Метод готов. Но Васе хочется, чтобы он был ещё чуть по-умнее.
"Я делаю это, потому что хочу!"
И юный разработчик добавляет в начало процедуры обработку параметра с настройками.
//Инициализируем настройки Если ТипЗнч(НастройкиКомпоновки) = Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда ВыполняемыеНастройки = НастройкиКомпоновки.ПолучитьНастройки(); ИначеЕсли ТипЗнч(НастройкиКомпоновки) = Тип("Строка") И ЭтоАдресВременногоХранилища(НастройкиКомпоновки) Тогда ВыполняемыеНастройки = ПолучитьИзВременногоХранилища(НастройкиКомпоновки); Иначе ВыполняемыеНастройки = НастройкиКомпоновки; КонецЕсли; Если НЕ ТипЗнч(ВыполняемыеНастройки) = Тип("НастройкиКомпоновкиДанных") Тогда Возврат; КонецЕсли;
Это позволит в метод передавать не только сами настройки, но и, к примеру, компоновщик настроек. Или же адрес хранилища, где настройки хранятся. Дополнительный штрих, который добавляет небольшую возможность.
Теперь, например, когда Васе потребуется вызывать методы из модуля отчёта, то он просто передаст КомпоновщикНастроек, а процедура сама уже возьмёт из него настройки. В результате код вызова этой процедуры немного, но уменьшится.
Процедура СкомпоноватьРезультатОтчета(Результат, СхемаКомпоновкиДанных, НастройкиКомпоновки, ДанныеРасшифровки = Неопределено, ВнешниеНаборыДанных = Неопределено, ДополнительныеПараметры = Неопределено) Экспорт //Инициализируем настройки Если ТипЗнч(НастройкиКомпоновки) = Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда ВыполняемыеНастройки = НастройкиКомпоновки.ПолучитьНастройки(); ИначеЕсли ТипЗнч(НастройкиКомпоновки) = Тип("Строка") И ЭтоАдресВременногоХранилища(НастройкиКомпоновки) Тогда ВыполняемыеНастройки = ПолучитьИзВременногоХранилища(НастройкиКомпоновки); Иначе ВыполняемыеНастройки = НастройкиКомпоновки; КонецЕсли; Если НЕ ТипЗнч(ВыполняемыеНастройки) = Тип("НастройкиКомпоновкиДанных") Тогда Возврат; КонецЕсли; //Инициализируем дополнительные параметры вывода ПараметрыВывода = Новый Структура; ПараметрыВывода.Вставить("МакетОформления" , Неопределено); ПараметрыВывода.Вставить("ПроверятьДоступностьПолей" , Истина); ПараметрыВывода.Вставить("ПараметрыФункциональныхОпций" , Новый Структура); ПараметрыВывода.Вставить("ВозможностьИспользованияВнешнихФункций" , Ложь); Если НЕ ДополнительныеПараметры = Неопределено Тогда ЗаполнитьЗначенияСвойств(ПараметрыВывода, ДополнительныеПараметры); КонецЕсли; //Определяем тип генератора Если ТипЗнч(Результат) = Тип("ТаблицаЗначений") ИЛИ ТипЗнч(Результат) = Тип("ДеревоЗначений") Тогда ВыводВКоллекциюЗначений = Истина; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"); Иначе ВыводВКоллекциюЗначений = Ложь; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанных"); КонецЕсли; //Формируем макет, с помощью компоновщика макета КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; //Передаем в макет компоновки схему, настройки и данные расшифровки МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, ВыполняемыеНастройки, ДанныеРасшифровки, ПараметрыВывода.МакетОформления, ТипГенератораВывода, ПараметрыВывода.ПроверятьДоступностьПолей, ПараметрыВывода.ПараметрыФункциональныхОпций); //Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, ПараметрыВывода.ВозможностьИспользованияВнешнихФункций); //Выводим результат Если ВыводВКоллекциюЗначений Тогда ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений; ПроцессорВывода.УстановитьОбъект(Результат); Иначе ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент; ПроцессорВывода.УстановитьДокумент(Результат); КонецЕсли; ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных); КонецПроцедуры
И вот Васина универсальная "обёртка" для вывода СКД. С ней он может не вставлять шаблонный набор строк, а просто вызвать заготовленную процедуру из общего модуля. Осталось теперь добавить описание...
6. Документирование
Василий добавляет описание к своему методу. Старается соблюдать "шаблоны" и рекомендации. Чтобы контекстная подсказка отображалась красиво и подхватывала и типы и описания.
// Выполняет компоновку СКД по переданным настройкам // // Параметры: // Результат - ТабличныйДокумент,ТаблицаЗначений,ДеревоЗначений - результат выполнения // СхемаКомпоновкиДанных - СхемаКомпоновкиДанных - выполняемая СКД // НастройкиКомпоновки - НастройкиКомпоновкиДанных,КомпоновщикНастроекКомпоновкиДанных,Строка - выполняемые настройки или адрес временного хранилища или компоновщик с настройками // ДанныеРасшифровки - ДанныеРасшифровкиКомпоновкиДанных, Неопределено - данные расшифровки // ВнешниеНаборыДанных - Структура, Неопределено - коллекция внешних наборов данных // ДополнительныеПараметры - Структура, Неопределено - коллекция внешних наборов данных // * МакетОформления - МакетОформленияКомпоновкиДанных - Макет оформления, в соответствии с которым необходимо оформлять макет компоновки данных. // * ПроверятьДоступностьПолей - Булево - Определяет, выполнять ли проверку прав на просмотр полей и проверку доступности поля во включенных функциональных возможностях. // * ПараметрыФункциональныхОпций - Булево - Содержит параметры функциональных опций, используемые при исполнении отчета. // * ВозможностьИспользованияВнешнихФункций - Булево - Указывает возможность использования функции общих модулей конфигурации в выражениях компоновки данных. //
Приходит время опробовать метод на практике.
7. Примеры использования
"Нужно сделать банальный програмный вывод СКД? Нате!"
//Стандартный программный вывод СкомпоноватьРезультатОтчета(ДокументРезультат, СхемаКомпоновкиДанных, КомпоновщикНастроек, ДанныеРасшифровки);
Или же вывести результат в таблицу значений?
//Вывод в коллекцию значений ДанныеРезультата = Новый ТаблицаЗначений; СкомпоноватьРезультатОтчета(ДанныеРезультата, СхемаКомпоновкиДанных, КомпоновщикНастроек);
А может наоборот вывести СКД, используя содержимое таблицы значений?
//Программный вывод с внешними наборами данных ВнешниеНаборыДанных = Новый Структура("ТаблицаДанных", ТаблицаДанных); СкомпоноватьРезультатОтчета(ДокументРезультат, СхемаКомпоновкиДанных, КомпоновщикНастроек, ДанныеРасшифровки, ВнешниеНаборыДанных);
Можно сделать стандартный вывод, но с возможностью использования "внешних функций"
//Вывод с возможностью использования внешних функций ПараметрыВывода = Новый Структура("ВозможностьИспользованияВнешнихФункций", Истина); СкомпоноватьРезультатОтчета(ДокументРезультат, СхемаКомпоновкиДанных, КомпоновщикНастроек, ДанныеРасшифровки,, ПараметрыВывода);
Или, например, со своим макетом оформления
//Вывод с использованием своего макета оформления ПараметрыВывода = Новый Структура("МакетОформления", ПолучитьМакет("МакетОформления")); СкомпоноватьРезультатОтчета(ДокументРезультат, СхемаКомпоновкиДанных, КомпоновщикНастроек, ДанныеРасшифровки,, ПараметрыВывода);
Васе нравится метод. Возможно, он не идеален. Возможно, эту процедуру никто и не заметит в закоулках модулей этой покрытой костылями и багами конфигурации. Но Вася всё равно доволен своей работой. Ведь на самом деле:
"Я делаю это, потому что мне просто нравится"
Вася похвалил себя, почесал ЧСВ и пошёл дальше заниматься своей работой. Ещё столько всего нужно скопипастить...
8. Поддержка (UPDATE 29.06.2021)
Прошло время. Вася с удовольствием пользовался своей универсальной процедуркой. Использовал её где только можно - и в отчетах, и в обработках, и в расширениях.
А тем временем платформа развивалась и наделила программный вывод СКД новой возможностью. Передавать при формировании менеджер временных таблиц.
Ранее в запросах СКД нельзя было использовать заранее подготовленные временные таблицы. И приходилось использовать костыли и связи наборов в СКД.
О, ужас! Хорошо, что это время прошло!
Но вот незадача. Текущая Васина процедура не позволяет использовать менеджер временных.
Пришло время доработки!
И так, для начала начала программист оглядел синтаксис-помощник. Что именно появилось нового?
ПроцессорКомпоновкиДанных.Инициализировать(<Макет>, <ВнешниеНаборыДанных>, <ДанныеРасшифровки>, <ВозможностьИспользованияВнешнихФункций>, <ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр>, <МенеджерВременныхТаблиц>)
<ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр> (необязательный)
Тип: Булево.
Если значение параметра равно Истина, то при отображении результата запроса учитывается право пользователя "Просмотр" на таблицы и поля, участвующие в запросе. Если в отчете или динамическом списке присутствует значение поля недоступного по праву "Просмотр", то выводится пустая ячейка.
Если значение параметра равно Ложь и параметр ПроверятьДоступностьПолей установлен в Истина, то значение выводится, даже если у пользователя нет права "Просмотр".
Значение по умолчанию: Истина.
<МенеджерВременныхТаблиц> (необязательный)
Тип: МенеджерВременныхТаблиц.
Менеджер временных таблиц, который будет установлен для исполняемых запросов.
В процессе работы процессора компоновки данных таблицы из этого менеджера могут быть получены, но не могут быть удалены или добавлены новые.
Значение по умолчанию: Неопределено.
1С всё расширяет количество параметров метода. А вот у Васи есть для этого структура ДополнительныеПараметры =)
//Инициализируем дополнительные параметры вывода ПараметрыВывода = Новый Структура; ПараметрыВывода.Вставить("МакетОформления" , Неопределено); ПараметрыВывода.Вставить("ПроверятьДоступностьПолей" , Истина); ПараметрыВывода.Вставить("ПараметрыФункциональныхОпций" , Новый Структура); ПараметрыВывода.Вставить("ВозможностьИспользованияВнешнихФункций" , Ложь); ПараметрыВывода.Вставить("МенеджерВременныхТаблиц" , Неопределено); ПараметрыВывода.Вставить("ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр" , Истина); Если НЕ ДополнительныеПараметры = Неопределено Тогда ЗаполнитьЗначенияСвойств(ПараметрыВывода, ДополнительныеПараметры); КонецЕсли;
Вот и всё, теперь в ДополнительныеПараметры можно передать новые параметры компоновки.
Осталось только передать их в сам метод платформы:
//Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать( МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, ПараметрыВывода.ВозможностьИспользованияВнешнихФункций, ПараметрыВывода.ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр, ПараметрыВывода.МенеджерВременныхТаблиц);
Этого уже достаточно, чтобы Васин универсальный метод соответствовал новым возможностям платформы.
Но юный программист чувствует, что этого недостаточно...
Так ли удобно передавать в СКД менеджер временных таблиц? А вот и не всегда.
Иногда просто хочется передать таблицу значений, которую сформировали программно \ прочитали из файла \ получили из хранилища \ <ваш вариант>
Для этого разработчику придется: создавать запрос с менеджером временных таблиц, описывать текст запроса с выборкой всех полей таблицы, передавать эту таблицу и выполнять запрос.
Это нужно автоматизировать!
И Вася взялся за дело:
Если ТипЗнч(ПараметрыВывода.МенеджерВременныхТаблиц) = Тип("Структура") Тогда МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц; Для Каждого КлючИЗначение Из ПараметрыВывода.МенеджерВременныхТаблиц Цикл //Здесь мы будем добавлять таблицу в МВТ КонецЦикла; ПараметрыВывода.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; КонецЕсли;
Теперь, в доп. параметре МенеджерВременныхТаблиц можно передать и структуру. А на основе её мы сделаем МВТ.
Ключем этой структуры будет Имя временной таблицы, которую нужно создать в менеджере. А значением будет сама таблица.
И тут наш 1Сник решил сделать отдельный метод, в котором он будет добавлять таблицу в менеджер.
В этой процедуре запрос генерируется сам. И через него в МВТ попадают нужные данные.
Процедура ДобавитьТаблицуВМенеджерВременныхТаблиц(МенеджерВременныхТаблиц, ИмяТаблицы, ДанныеТаблицы) Экспорт ИменаКолонок = Новый Массив; Для Каждого Колонка Из ДанныеТаблицы.Колонки Цикл ИменаКолонок.Добавить(Колонка.Имя); КонецЦикла; ИменаКолонок = СтрСоединить(ИменаКолонок, ","); ТекстЗапроса = "ВЫБРАТЬ %1 ПОМЕСТИТЬ %2 ИЗ &ТЗ КАК ТЗ"; ТекстЗапроса = СтрШаблон(ТекстЗапроса, ИменаКолонок, ИмяТаблицы); Запрос = Новый Запрос(ТекстЗапроса); Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; Запрос.УстановитьПараметр("ТЗ", ДанныеТаблицы); Запрос.Выполнить(); КонецПроцедуры
Теперь нужно этот новый метод вызвать:
Если ТипЗнч(ПараметрыВывода.МенеджерВременныхТаблиц) = Тип("Структура") Тогда МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц; Для Каждого КлючИЗначение Из ПараметрыВывода.МенеджерВременныхТаблиц Цикл ДобавитьТаблицуВМенеджерВременныхТаблиц(МенеджерВременныхТаблиц, КлючИЗначение.Ключ, КлючИЗначение.Значение); КонецЦикла; ПараметрыВывода.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; КонецЕсли;
Можно код из метода "встроить" внутрь основного. Тогда будет так:
Если ТипЗнч(ПараметрыВывода.МенеджерВременныхТаблиц) = Тип("Структура") Тогда МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц; Для Каждого КлючИЗначение Из ПараметрыВывода.МенеджерВременныхТаблиц Цикл ИмяТаблицы = КлючИЗначение.Ключ; ДанныеТаблицы = КлючИЗначение.Значение; ИменаКолонок = Новый Массив; Для Каждого Колонка Из ДанныеТаблицы.Колонки Цикл ИменаКолонок.Добавить(Колонка.Имя); КонецЦикла; ИменаКолонок = СтрСоединить(ИменаКолонок, ","); ТекстЗапроса = "ВЫБРАТЬ %1 ПОМЕСТИТЬ %2 ИЗ &ТЗ КАК ТЗ"; ТекстЗапроса = СтрШаблон(ТекстЗапроса, ИменаКолонок, ИмяТаблицы); Запрос = Новый Запрос(ТекстЗапроса); Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; Запрос.УстановитьПараметр("ТЗ", ДанныеТаблицы); Запрос.Выполнить(); КонецЦикла; ПараметрыВывода.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; КонецЕсли;
Дело сделано! Осталось подправить описание.
// Выполняет компоновку СКД по переданным настройкам // // Параметры: // Результат - ТабличныйДокумент,ТаблицаЗначений,ДеревоЗначений - результат выполнения // СхемаКомпоновкиДанных - СхемаКомпоновкиДанных - выполняемая СКД // НастройкиКомпоновки - НастройкиКомпоновкиДанных,КомпоновщикНастроекКомпоновкиДанных,Строка - выполняемые настройки или адрес временного хранилища или компоновщик с настройками // ДанныеРасшифровки - ДанныеРасшифровкиКомпоновкиДанных, Неопределено - данные расшифровки // ВнешниеНаборыДанных - Структура, Неопределено - коллекция внешних наборов данных // ДополнительныеПараметры - Структура, Неопределено - коллекция внешних наборов данных // * МакетОформления - МакетОформленияКомпоновкиДанных - Макет оформления, в соответствии с которым необходимо оформлять макет компоновки данных. // * МенеджерВременныхТаблиц - МенеджерВременныхТаблиц, Структура - Временные таблицы, которые будут доступны в запросе СКД. Или МВТ или структура, где Ключ - Имя, а Значение - Таблица // * ПроверятьДоступностьПолей - Булево - Определяет, выполнять ли проверку прав на просмотр полей и проверку доступности поля во включенных функциональных возможностях. // * ПараметрыФункциональныхОпций - Булево - Содержит параметры функциональных опций, используемые при исполнении отчета. // * ВозможностьИспользованияВнешнихФункций - Булево - Указывает возможность использования функции общих модулей конфигурации в выражениях компоновки данных. // * ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр - Булево - Указывает обязательность наличия роли Просмотр для используемых метаданных в запросе СКД
И, конечно же, закрепить примерами использования:
//Вывод с передачей менеджера временных таблиц ПараметрыВывода = Новый Структура("МенеджерВременныхТаблиц", Запрос.МенеджерВременныхТаблиц); СкомпоноватьРезультатОтчета(ДокументРезультат, СхемаКомпоновкиДанных, КомпоновщикНастроек, ДанныеРасшифровки,, ПараметрыВывода);
//Вывод с передачей таблиц, которые попадут в МВТ ПараметрыВывода = Новый Структура("МенеджерВременныхТаблиц", Новый Структура); ПараметрыВывода.МенеджерВременныхТаблиц.Вставить("МояВТ", МояТЗ); СкомпоноватьРезультатОтчета(ДокументРезультат, СхемаКомпоновкиДанных, КомпоновщикНастроек, ДанныеРасшифровки,, ПараметрыВывода);
Теперь Вася прошел весь цикл. Идея, релиализация и поддержка универсальной процедуры. И доволен окончательно. Или же нет?
Надо сделать общий модуль с гибкими методами по работе с СКД!
Понравилась статья?
Не стойте в стороне! Не будьте равнодушными. Каждый поставленный вами "лайк" покажет автору, что он не зря пропустил возможность пропустить по стаканчику, когда писал эту статью.
И переходите к другим работам:
Сервис регистрации ошибок 1С (пример создания)
История формирования отчетов (расширение для типовых конфигураций)
P.S.: И вот вдогонку под спойлером окончательный вариант процедуры. Авось, кому пригодится.
Окончательная Васина процедура
// Выполняет компоновку СКД по переданным настройкам // // Параметры: // Результат - ТабличныйДокумент,ТаблицаЗначений,ДеревоЗначений - результат выполнения // СхемаКомпоновкиДанных - СхемаКомпоновкиДанных - выполняемая СКД // НастройкиКомпоновки - НастройкиКомпоновкиДанных,КомпоновщикНастроекКомпоновкиДанных,Строка - выполняемые настройки или адрес временного хранилища или компоновщик с настройками // ДанныеРасшифровки - ДанныеРасшифровкиКомпоновкиДанных, Неопределено - данные расшифровки // ВнешниеНаборыДанных - Структура, Неопределено - коллекция внешних наборов данных // ДополнительныеПараметры - Структура, Неопределено - коллекция внешних наборов данных // * МакетОформления - МакетОформленияКомпоновкиДанных - Макет оформления, в соответствии с которым необходимо оформлять макет компоновки данных. // * МенеджерВременныхТаблиц - МенеджерВременныхТаблиц,Структура - Временные таблицы, которые будут доступны в запросе СКД. Или МВТ или структура, где Ключ - Имя, а Значение - Таблица // * ПроверятьДоступностьПолей - Булево - Определяет, выполнять ли проверку прав на просмотр полей и проверку доступности поля во включенных функциональных возможностях. // * ПараметрыФункциональныхОпций - Булево - Содержит параметры функциональных опций, используемые при исполнении отчета. // * ВозможностьИспользованияВнешнихФункций - Булево - Указывает возможность использования функции общих модулей конфигурации в выражениях компоновки данных. // * ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр - Булево - Указывает обязательность наличия роли Просмотр для используемых метаданных в запросе СКД // //Подробнее об использовании метода: //infostart.ru/public/1082944/?ref=1159 // Процедура СкомпоноватьРезультатОтчета(Результат, СхемаКомпоновки, НастройкиКомпоновки, ДанныеРасшифровки = Неопределено, ВнешниеНаборыДанных = Неопределено, ДополнительныеПараметры = Неопределено) Экспорт //Инициализируем настройки Если ТипЗнч(НастройкиКомпоновки) = Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда ВыполняемыеНастройки = НастройкиКомпоновки.ПолучитьНастройки(); ИначеЕсли ТипЗнч(НастройкиКомпоновки) = Тип("Строка") И ЭтоАдресВременногоХранилища(НастройкиКомпоновки) Тогда ВыполняемыеНастройки = ПолучитьИзВременногоХранилища(НастройкиКомпоновки); Иначе ВыполняемыеНастройки = НастройкиКомпоновки; КонецЕсли; Если НЕ ТипЗнч(ВыполняемыеНастройки) = Тип("НастройкиКомпоновкиДанных") Тогда Возврат; КонецЕсли; //Инициализируем дополнительные параметры вывода ПараметрыВывода = Новый Структура; ПараметрыВывода.Вставить("МакетОформления" , Неопределено); ПараметрыВывода.Вставить("ПроверятьДоступностьПолей" , Истина); ПараметрыВывода.Вставить("ПараметрыФункциональныхОпций" , Новый Структура); ПараметрыВывода.Вставить("ВозможностьИспользованияВнешнихФункций" , Ложь); ПараметрыВывода.Вставить("МенеджерВременныхТаблиц" , Неопределено); ПараметрыВывода.Вставить("ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр" , Истина); Если НЕ ДополнительныеПараметры = Неопределено Тогда ЗаполнитьЗначенияСвойств(ПараметрыВывода, ДополнительныеПараметры); КонецЕсли; Если ТипЗнч(ПараметрыВывода.МенеджерВременныхТаблиц) = Тип("Структура") Тогда МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц; Для Каждого КлючИЗначение Из ПараметрыВывода.МенеджерВременныхТаблиц Цикл ДобавитьТаблицуВМенеджерВременныхТаблиц(МенеджерВременныхТаблиц, КлючИЗначение.Ключ, КлючИЗначение.Значение); КонецЦикла; ПараметрыВывода.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; КонецЕсли; //Определяем тип генератора Если ТипЗнч(Результат) = Тип("ТаблицаЗначений") ИЛИ ТипЗнч(Результат) = Тип("ДеревоЗначений") Тогда ВыводВКоллекциюЗначений = Истина; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"); Иначе ВыводВКоллекциюЗначений = Ложь; ТипГенератораВывода = Тип("ГенераторМакетаКомпоновкиДанных"); КонецЕсли; //Формируем макет, с помощью компоновщика макета КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных; //Передаем в макет компоновки схему, настройки и данные расшифровки МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, ВыполняемыеНастройки, ДанныеРасшифровки, ПараметрыВывода.МакетОформления, ТипГенератораВывода, ПараметрыВывода.ПроверятьДоступностьПолей, ПараметрыВывода.ПараметрыФункциональныхОпций); //Выполним компоновку с помощью процессора компоновки ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных; ПроцессорКомпоновкиДанных.Инициализировать( МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, ПараметрыВывода.ВозможностьИспользованияВнешнихФункций, ПараметрыВывода.ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр, ПараметрыВывода.МенеджерВременныхТаблиц); //Выводим результат Если ВыводВКоллекциюЗначений Тогда ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений; ПроцессорВывода.УстановитьОбъект(Результат); Иначе ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент; ПроцессорВывода.УстановитьДокумент(Результат); КонецЕсли; ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных); КонецПроцедуры // Процедура добавляет таблицу в менеджер временных таблиц // // Параметры: // МенеджерВременныхТаблиц - МенеджерВременныхТаблиц - Менеджер, в который нужно добавить таблицу // ИмяТаблицы - Строка - Имя временной таблицы // ДанныеТаблицы - ТаблицаЗначений - Данные таблицы // Процедура ДобавитьТаблицуВМенеджерВременныхТаблиц(МенеджерВременныхТаблиц, ИмяТаблицы, ДанныеТаблицы) Экспорт ИменаКолонок = Новый Массив; Для Каждого Колонка Из ДанныеТаблицы.Колонки Цикл ИменаКолонок.Добавить(Колонка.Имя); КонецЦикла; ИменаКолонок = СтрСоединить(ИменаКолонок, ","); ТекстЗапроса = "ВЫБРАТЬ %1 ПОМЕСТИТЬ %2 ИЗ &ТЗ КАК ТЗ"; ТекстЗапроса = СтрШаблон(ТекстЗапроса, ИменаКолонок, ИмяТаблицы); Запрос = Новый Запрос(ТекстЗапроса); Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; Запрос.УстановитьПараметр("ТЗ", ДанныеТаблицы); Запрос.Выполнить(); КонецПроцедуры