Как вынести серверную логику управляемой формы в общий модуль 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке конфигураций на платформе 1С:Предприятие 8.3 программисты часто стремятся избежать дублирования кода в модулях форм. Естественное желание разработчика — вынести одинаковые алгоритмы обработки в общий модуль. Однако при попытке вызвать серверный общий модуль напрямую из клиентской процедуры и передать туда форму в качестве параметра возникает ошибка преобразования данных. Разберем, почему возникает эта ошибка и какими способами можно правильно организовать вызов общих процедур с сохранением или передачей контекста формы.

Почему возникает ошибка при передаче формы на сервер?

Проанализируем причину ошибки платформы. На стороне клиента объект формы имеет тип УправляемаяФорма. Этот тип не сериализуется через протокол обмена между тонким клиентом и сервером. Если попытаться передать переменную ЭтаФорма напрямую из клиентского метода в процедуру общего модуля с признаком Сервер, платформа 1С выдаст исключение о невозможности сериализации типа данных.

Механизм контекстного вызова модуля формы устроен иначе: когда в модуле формы вызывается метод с директивой &НаСервере, платформа сама выполняет сериализацию данных формы (ее реквизитов), передает их на сервер и воссоздает там серверный контекст формы. Оказавшись внутри серверного контекста формы, мы получаем полноценный объект УправляемаяФорма на сервере. В пределах самого сервера передавать этот объект в любые общие серверные модули можно без каких-либо ограничений.

Способ 1. Передача контекста формы через серверную процедуру-посредник

Рассмотрим базовый прием, который позволяет вынести логику в общий модуль, если необходимо напрямую управлять элементами интерфейса или реквизитами формы из общего кода. Для этого создадим связку из клиентской процедуры, серверной процедуры формы и метода общего модуля.

Разберем по шагам реализацию данного варианта. В модуле управляемой формы создаем вызов серверной процедуры формы, а уже из нее передаем форму целиком в серверный общий модуль:


&НаКлиенте
Процедура ВыполнитьДействие(Команда)
    ВыполнитьДействиеНаСервере();
КонецПроцедуры

&НаСервере
Процедура ВыполнитьДействиеНаСервере()
    ОбщегоНазначенияСервер.ОбработатьФорму(ЭтаФорма);
КонецПроцедуры

В общем модуле с установленным флажком Сервер создаем процедуру, принимающую форму как входящий параметр:


Процедура ОбработатьФорму(Форма) Экспорт
    // Доступны элементы формы, реквизиты и команды
    Форма.Элементы.ГруппаРеквизитов.Видимость = Ложь;
    Форма.Модифицированность = Истина;
КонецПроцедуры

Этот способ оправдан, когда в общем модуле действительно требуется динамически управлять свойствами элементов формы (видимостью, доступностью), коллекциями Форма.Элементы или вызывать метод Форма.ИзменитьРеквизиты().

Способ 2. Отказ от передачи контекста: использование структур параметров

Посмотрим на более производительную и архитектурно правильную альтернативу. Контекстный вызов &НаСервере передает по сети все реквизиты формы на сервер и возвращает их обратно на клиент, что создает избыточную нагрузку на канал связи и снижает скорость работы интерфейса.

Если для работы серверного алгоритма требуется только часть данных формы, стандарты разработки 1С рекомендуют применять вызовы &НаСервереБезКонтекста. В этом случае необходимые реквизиты упаковываются в структуру на клиенте, передаются в общий модуль, а результат возвращается обратно:


&НаКлиенте
Процедура ОбработатьДанныеКоманда(Команда)
    ПараметрыОбработки = Новый Структура;
    ПараметрыОбработки.Вставить("Организация", Объект.Организация);
    ПараметрыОбработки.Вставить("СуммаДокумента", Объект.СуммаДокумента);

    Результат = ОбщегоНазначенияСервер.РассчитатьПоказатели(ПараметрыОбработки);
    
    // Применяем результат на клиенте
    Объект.ИтоговаяСумма = Результат.ИтоговаяСумма;
КонецПроцедуры

В общем модуле описываем процедуру или функцию, которая не зависит от формы и работает только с чистыми данными:


Функция РассчитатьПоказатели(ПараметрыОбработки) Экспорт
    Результат = Новый Структура;
    // Выполнение бизнес-логики и запросов к базе данных
    Результат.Вставить("ИтоговаяСумма", ПараметрыОбработки.СуммаДокумента * 1.2);
    Возврат Результат;
КонецФункции

Способ 3. Работа с прикладным объектом через РеквизитФормыВЗначение

Проанализируем ситуацию, когда процедура общего модуля должна выполнить типовые действия над документом или справочником (например, заполнить табличную часть по сложному алгоритму или выполнить движения). Держать форму как параметр в такой бизнес-логике не требуется.

Для отделения логики объекта от формы применяются платформенные методы преобразования:

  1. В контекстной серверной процедуре формы преобразуем данные формы в реальный прикладной объект при помощи метода РеквизитФормыВЗначение("Объект").
  2. Передаем полученный объект (например, ДокументОбъект) в процедуру общего модуля или метод менеджера объекта.
  3. После обработки возвращаем обновленные данные в форму с помощью ЗначениеВРеквизитФормы(ДокументОбъект, "Объект").

Посмотрим на пример реализации данного подхода:


&НаСервере
Процедура ЗаполнитьДокументНаСервере()
    // Преобразуем данные формы в объект
    ДокументОбъект = РеквизитФормыВЗначение("Объект");
    
    // Обрабатываем объект в общем модуле
    ДокументыСервер.ЗаполнитьТабличныеЧасти(ДокументОбъект);
    
    // Возвращаем измененные данные обратно в форму
    ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");
КонецПроцедуры

Способ 4. Вынос интерфейсной логики в клиентские общие модули

Если процедура общего модуля предназначена исключительно для настройки отображения элементов (например, циклическая установка доступности полей по условию) и не требует запросов к базе данных, серверный вызов не нужен вовсе.

В таком случае создается общий модуль с признаком Клиент (управляемое приложение). На стороне клиента объект ЭтаФорма без ошибок передается в процедуры клиентского общего модуля в качестве параметра:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ИнтерфейсКлиент.НастроитьВидимостьПолей(ЭтаФорма);
КонецПроцедуры

Итоги и рекомендации

Выбор варианта выноса кода зависит от решаемой задачи:

  1. Если необходимо массово модифицировать элементы и состав формы на сервере, используем вызов серверного метода формы, откуда передаем ЭтаФорма в общий модуль на сервере.
  2. Если выполняются расчеты или получение данных из базы, используем неконтекстные серверные вызовы и передаем параметры через структуры.
  3. Если алгоритм изменяет реквизиты и табличные части объекта, конвертируем форму через РеквизитФормыВЗначение и обрабатываем прикладной объект в общем модуле.
← На главную