Статья не претендует на оригинальность. В ней я собрал несколько приемов, которые часто использую при доработке функционала типовых конфигурация 1С:Предприятие 8.3 без внесения изменений в конфигурации поставщика. Материал будет полезен как начинающему программисту 1С, так, возможно, и профессиональному разработчику.
На практике, при разработке какого-нибудь дополнительного функционала с использованием механизма расширений или дополнительных обработок, возникает необходимость хранения каких-либо данных. Например, для внешней обработки загрузки данных товарной накладной из файла необходимо использовать одного и того же контрагента или группу номенклатуры. Можно конечно сразу прописать эти значения в коде используя метод менеджера справочника НайтиПоКоду() или использовать механизм Хранилища настроек. При использовании расширения можно создать Константу, Справочник или Регистр сведений, в которых можно хранить значения любого типа. Однако все описанные способы имеют свои недостатки: первый привязан к конкретной ИБ, второй к пользователю, данные расширения можно потерять в случае случайного удаления расширения.
В своей практике я использую другой способ: в конфигурациях, использующих Библиотеку стандартных подсистем, есть встроенные объекты и процедуры для хранения каких либо данных настроек. Это два регистра сведений - БезопасноеХранилищеДанных и БезопасноеХранилищеДанныхОбластейДанных.
Эти регистры предназначены для хранения какой-либо конфиденциальной информации. В качестве измерения Владелец можно использовать ссылку на элемент Плана обмена, Справочника или использовать строку до 128 символов. Тип ресурса Данные - ХранилищеЗначения, в который обычно записывается данные типа Структура. Данные такого регистра просто не "вытащить" в пользовательском режиме универсальным отчетом или консолью запросов. Конечно, кроме паролей и токенов, можно хранить данные других типов.
Чтобы не разбираться какой из регистров когда использовать, для работы с этими регистрами сведений имеется программный интерфейс - процедура и функция общего модуля ОбщегоНазначения:
Процедура ЗаписатьДанныеВБезопасноеХранилище(Владелец, Данные, Ключ = "Пароль") Экспорт
Функция ПрочитатьДанныеИзБезопасногоХранилища(Владелец, Ключи = "Пароль", ОбщиеДанные = Неопределено) Экспорт
В качестве Владельца, как уже писалось выше, можно передать ссылку на элемент Плана обмена или Справочника, или просто строку. Ключ должен соответствовать правилам, установленным для идентификаторов. В качестве Данных передается значение произвольного типа, обычно строка или структура.
Пример реализации
Рассмотрим пример сохранения каких-либо настроек Дополнительной обработки. Для этого создадим форму Настройки. В форме создадим команду ЗаписатьИЗакрыть и выведем ее в виде кнопки по умолчанию.
Форма будет иметь реквизиты для редактирования: ГруппаНоменклатуры и Контр, и два служебных: агентКлючДанных и ДополнительнаяОбработкаСсылка.
Поместим в модуль формы следующий код:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ДополнительнаяОбработкаСсылка = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ДополнительнаяОбработкаСсылка");
Если не ЗначениеЗаполнено(ДополнительнаяОбработкаСсылка) Тогда
ДополнительнаяОбработкаСсылка=РеквизитФормыВЗначение("Объект").Метаданные().ПолноеИмя();
КонецЕсли;
КлючДанных="Настройки";
Данные=ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ДополнительнаяОбработкаСсылка,КлючДанных);
Если ТипЗнч(Данные)=Тип("Структура") Тогда
ЗаполнитьЗначенияСвойств(ЭтаФорма, Данные);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ЗаписатьИЗакрытьНаСервере()
Данные=Новый Структура;
Для Каждого Элемент из Элементы Цикл
Если ТипЗнч(Элемент)=Тип("ПолеФормы") Тогда
Данные.Вставить(Элемент.Имя, ЭтаФорма[Элемент.Имя])
КонецЕсли;
КонецЦикла;
ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ДополнительнаяОбработкаСсылка, Данные, КлючДанных);
КонецПроцедуры
&НаКлиенте
Процедура ЗаписатьИЗакрыть(Команда)
ЗаписатьИЗакрытьНаСервере();
Закрыть();
КонецПроцедуры
В процедуре ПриСозданииНаСервере проверяются параметры, переданные в форму. Если параметры содержат свойство ДополнительнаяОбработкаСсылка, то это значит что форма открыта с использованием подсистемы ДополнительныеОтчетыИОбработки и в качестве владельца настроек будет использован элемент справочника ДополнительныеОтчетыИОбработки. В противном случае владельцем будет строка - полное имя обработки. После определения владельца считываем данные из регистра с использованием функции программного интерфейса, и, если сохранённые данные редставляют собой структуру, заполняем ими значения реквизитов формы. Теперь при создании формы в значения реквизитов будут установлены ранее сохранённые значения.
Обработку команды ЗаписатьИЗакрыть передадим на сервер. Там сформируем структуру из значений всех полей, которые выведены на форму. И эту структуру запишем в регистр, используя процедуру программного интерфейса Библиотеки стандартных подсистем.
Собственно, с формой настроек дополнительной обработки всё. Подобный механизм можно использовать и для хранения дополнительных данных справочника, если для него не включен механизм ДополнительныеРеквизитыИСведения, либо нет подходящего типа значения дополнительного реквизита.
Дополнительная обработка
Бонусом добавлю пример использования описанного механизма в дополнительной обработке, который можно использовать в качестве шаблона. В модуль объекта вставим следующий код:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации=ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке();
ПараметрыРегистрации.Вид=ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
ПараметрыРегистрации.Версия="1.0.0.1";
ПараметрыРегистрации.Наименование="ДемоСохранениеНастроек";
ПараметрыРегистрации.Информация="Описание способа хранения данных расширения или дополнительной обработки в информационной базе с использованием функционала Библиотеки стандартных подсистем.";
Команда=ПараметрыРегистрации.Команды.Добавить();
Команда.Идентификатор="Настройка";
Команда.Представление="Настройка";
Команда.Использование=ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
Команда=ПараметрыРегистрации.Команды.Добавить();
Команда.Идентификатор="Выполнить";
Команда.Представление="Прочитать настройки";
Команда.Использование=ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
Возврат ПараметрыРегистрации;
КонецФункции
Дополнительная обработка будет выполнять две команды на клиенте: Настройка и Выполнить. Для обработки логики этих команд создадим еще одну форму нашей обработки - ОсновнаяФорма и сделаем ее формой обработки по умолчанию.
Конечно, для данного примера можно было использовать только форму Настройки, однако я хочу продемонстрировать открытие разных форм одной Дополнительной обработки. Необходимо так же, как и в форме Настройки, создать служебный реквизит формы ДополнительнаяОбработкаСсылка. В модуле формы создадим следующие процедуры и функции:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
МД=РеквизитФормыВЗначение("Объект").Метаданные();
ИмяОбработки=МД.Имя;
ДополнительнаяОбработкаСсылка = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ДополнительнаяОбработкаСсылка");
Если не ЗначениеЗаполнено(ДополнительнаяОбработкаСсылка) Тогда
ДополнительнаяОбработкаСсылка=МД.ПолноеИмя();
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьКоманду(Идентификатор) Экспорт
Если Идентификатор="Настройка" Тогда
ОткрытьФорму("ВнешняяОбработка."+ИмяОбработки+".Форма.Настройки", Новый Структура("ДополнительнаяОбработкаСсылка",ДополнительнаяОбработкаСсылка));
ИначеЕсли Идентификатор="Выполнить" Тогда
Сообщить(СохраненыеДанные())
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция СохраненыеДанные()
УстановитьПривилегированныйРежим(Истина);
Данные=ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ДополнительнаяОбработкаСсылка, "Настройки");
МассивПолей=Новый Массив;
Если ТипЗнч(Данные)=Тип("Структура") Тогда
Для каждого КлючИЗначение из Данные Цикл
МассивПолей.Добавить(КлючИЗначение.Ключ+": "+КлючИЗначение.Значение);
КонецЦикла;
КонецЕсли;
Возврат СтрСоединить(МассивПолей, Символы.ПС);
КонецФункции
В процедуре ПриСозданииНаСервере производится чтение переданного через параметры формы свойства ДополнительнаяОбработкаСсылка, которое указывает на элемент справочника ДополнительныеОтчетыИОбработки. Экспортная процедура ВыполнитьКоманду вызывается программным интерфейсом подсистемы ДополнительныеОтчетыИОбработк. В ней, в зависимости от переданного параметра - идентификатора команды, открывается либо форма настроек, либо производится чтение отображение и настроек. Поскольку в БСП права на чтение и запись описываемых регистров хранения настроек доступны только для роли ПолныеПрава, то перед чтением сохраненных данных в функции Сохранены установим еДанныепривилегированный режим. В этом случае доступ к настройкам может получить пользователь, в независимости от установленных прав. Хочу обратить внимание, как в функции Сохранены реализовано соединение строк. В отличие от традиционного соединения строк в цикле вида еДанныеСтр=Стр+Значение, строки сначала помещаются в массив, а затем с помощью функции СтрСоединить соединяются. Этот вариант рекомендован для сложения строк в цикле с большим числом итераций, так как дает ощутимый выигрыш в производительности при крупных многопользовательских системах.
Описанные механизмы и процедуры можно использовать для собственных дополнительных обработок, поэтому файл я не прилагаю.