При разработке в среде 1С:Предприятие 8.3 на платформе с управляемыми формами начинающие программисты часто сталкиваются с архитектурным барьером. Попытка напрямую обратиться к элементам или реквизитам формы из модуля объекта вызывает ошибку компиляции. В этой статье мы подробно разберем, почему существует это ограничение, как правильно передавать контекст формы в модуль объекта, а также проанализируем частую ошибку "Недостаточно фактических параметров".
Прежде чем перейти к написанию кода, выясним причину такого поведения платформы. В управляемом приложении строго реализовано разделение интерфейса (клиентской части) и бизнес-логики (серверной части):
ЭтаФорма, ее визуальные элементы Элементы, цвета, видимость полей и другие свойства отображения не могут быть сериализованы (оцифрованы) для передачи между контекстами.Именно поэтому любая попытка напрямую прочитать значение элемента формы из модуля объекта является грубой архитектурной ошибкой. Все необходимые данные должны передаваться в модуль объекта в виде параметров или транзитных свойств.
Рассмотрим классический сценарий. У нас есть управляемая форма обработки (или документа), и нам необходимо вызвать процедуру или функцию, которая написана в модуле этого же объекта, передав туда данные из формы.
Для этого в управляемой форме на сервере нам необходимо временно воссоздать прикладной объект из данных формы с помощью платформенного метода РеквизитФормыВЗначение(). Разберем этот процесс по шагам.
Шаг 1. Пишем метод в модуле объекта
В модуле объекта (например, внешней обработки или документа) создаем экспортную функцию. Ключевое слово Экспорт обязательно, иначе метод не будет виден снаружи модуля.
Функция ВыборкаКрупныхЗаказов(ДатаНачала, ДатаОкончания, МинимальнаяСумма) Экспорт
// Здесь размещается логика работы с базой данных, запросы и т.д.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказПокупателя.Ссылка КАК Ссылка,
| ЗаказПокупателя.СуммаДокумента КАК Сумма
|ИЗ
| Документ.ЗаказПокупателя КАК ЗаказПокупателя
|ГДЕ
| ЗаказПокупателя.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
| И ЗаказПокупателя.СуммаДокумента >= &МинимальнаяСумма";
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
Запрос.УстановитьПараметр("МинимальнаяСумма", МинимальнаяСумма);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Шаг 2. Вызываем метод из модуля управляемой формы
В модуле формы вызов серверного метода объекта должен происходить исключительно в серверном контексте (процедуры с директивой &НаСервере). Посмотрим на пример реализации:
&НаСервере
Процедура ВыполнитьАнализНаСервере()
// Конвертируем данные формы (реквизит "Объект") в реальный прикладной объект в памяти сервера
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// Вызываем экспортную функцию модуля объекта и передаем параметры из реквизитов формы
ТаблицаРезультатов = ОбработкаОбъект.ВыборкаКрупныхЗаказов(Объект.ПериодНачала, Объект.ПериодОкончания, Объект.Сумма);
// Выполняем дальнейшую обработку полученных данных
// ...
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьАнализ(Команда)
ВыполнитьАнализНаСервере();
КонецПроцедуры
Проанализируем ситуацию, которая часто возникает у начинающих разработчиков. При вызове метода из формы система может выдать критическую ошибку выполнения: "Недостаточно фактических параметров".
Выясним причину этой ошибки. Она возникает тогда, когда в описании функции в модуле объекта закреплено определенное количество обязательных параметров, а при вызове этой функции из модуля формы передается меньшее количество аргументов (или они не указываются вовсе).
Рассмотрим пример некорректного кода в форме:
// ОШИБОЧНЫЙ КОД
&НаСервере
Процедура ОтправитьНаСервере()
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// Ошибка! Функция ожидает 3 параметра, а мы вызываем ее без параметров
СтруктураМассивов = ОбработкаОбъект.ВыборкаКрупныхЗаказов();
КонецПроцедуры
Чтобы исправить эту ошибку, у нас есть два пути:
СтруктураМассивов = ОбработкаОбъект.ВыборкаКрупныхЗаказов(Объект.ДатаНачала, Объект.ДатаОкончания, Объект.Сумма);
Функция ВыборкаКрупныхЗаказов(ДатаНачала = Неопределено, ДатаОкончания = Неопределено, МинимальнаяСумма = 0) Экспорт
// Если параметры не переданы, они примут значения Неопределено и 0 соответственно
// ...
КонецФункции
Использование явного вызова функций через РеквизитФормыВЗначение() отлично работает, когда мы сами инициируем алгоритм. Но что делать, если нам нужно передать данные из интерфейса во время стандартных транзакционных событий платформы (например, при записи или проведении документа), когда методы ПередЗаписью или ОбработкаПроведения вызываются платформой автоматически?
Для этих целей у любого прикладного объекта 1С (ДокументОбъект, СправочникОбъект и т.д.) существует встроенное свойство-структура ДополнительныеСвойства. Это идеальный транспортный механизм для передачи неявных параметров из формы в модуль объекта.
Реализация в модуле управляемой формы:
Запись дополнительных свойств обычно выполняется в обработчике события ПередЗаписьюНаСервере:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Помещаем в ДополнительныеСвойства признак, который нужен только в момент этой конкретной записи
ТекущийОбъект.ДополнительныеСвойства.Вставить("ЗаписатьБезПроверкиЛимитов", Истина);
КонецПроцедуры
Реализация в модуле объекта:
В предопределенной процедуре ПередЗаписью в модуле объекта мы легко считываем переданные из формы параметры:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверяем, был ли передан параметр из формы
ПроверитьЛимиты = Истина;
Если ДополнительныеСвойства.Свойство("ЗаписатьБезПроверкиЛимитов") Тогда
Если ДополнительныеСвойства.ЗаписатьБезПроверкиЛимитов = Истина Тогда
ПроверитьЛимиты = Ложь;
EndIf;
КонецЕсли;
Если ПроверитьЛимиты Тогда
// Выполняем стандартную проверку лимитов
КонецЕсли;
КонецПроцедуры
Этот способ крайне важен, так как он позволяет передавать любые служебные переменные, которые не требуется сохранять в базу данных в виде реквизитов самого объекта.
Важно помнить, что связка функций РеквизитФормыВЗначение() и обратной ей ЗначениеВРеквизитФормы() — это ресурсоемкие операции. В этот момент платформа осуществляет полную сериализацию XML/JSON всех данных формы, передает их на сервер и собирает там тяжелый объект (особенно если у документа есть табличные части с тысячами строк).
Проанализируем альтернативные варианты оптимизации кода:
Посмотрим на пример вызова оптимизированной процедуры из общего модуля:
// В модуле формы
&НаСервере
Процедура РассчитатьСкидкуНаСервере()
// Создаем легкую структуру параметров вместо конвертации всего объекта
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("Клиент", Объект.Контрагент);
ПараметрыЗапроса.Вставить("СуммаДокумента", Объект.СуммаДокумента);
// Вызываем облегченный метод общего модуля
Объект.СуммаСкидки = РасчетСкидокКлиентовПереопределяемый.ПолучитьСкидку(ПараметрыЗапроса);
КонецПроцедуры
Используя данные рекомендации, вы сможете грамотно проектировать взаимодействие интерфейса управляемых форм и серверных модулей объектов в 1С 8.3, избегая падения производительности и досадных ошибок с параметрами.