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