Как получить значения реквизитов формы 1С на сервере?

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

Мы с вами часто сталкиваемся с необходимостью получить доступ к значениям реквизитов формы из серверного кода. Это может быть нужно для выполнения сложных расчетов, проверки данных перед записью или взаимодействия с другими объектами базы данных. Однако, архитектура 1С:Предприятия с разделением на клиент и сервер накладывает свои особенности на этот процесс. В этом материале мы подробно разберем, как получить реквизиты формы на сервере, рассмотрим различные подходы и выясним, какой из них оптимален в той или иной ситуации.

Прямой доступ к реквизитам формы через контекстный серверный вызов

Самый простой и очевидный способ получить доступ к реквизитам формы на сервере — это использовать контекстный серверный вызов. Давайте проанализируем, как это работает. Когда мы вызываем серверную процедуру или функцию из модуля формы (например, из клиентской процедуры кнопки) с директивой компиляции &НаСервере, платформа 1С:Предприятие автоматически упаковывает весь контекст формы. Это включает в себя не только ее реквизиты, но и элементы, параметры и другие данные. Упакованный контекст передается на сервер, где создается серверная часть формы, и контекст разворачивается. Только после этого выполняется код нашей серверной процедуры. Благодаря этому механизму, внутри серверной процедуры мы можем обращаться к реквизитам формы напрямую через объект ЭтаФорма.

Важный момент: Необходимо различать реквизиты, принадлежащие непосредственно форме (добавленные в конфигураторе к форме), и реквизиты основного объекта данных формы (например, документа, справочника или другого объекта, который форма редактирует). Реквизиты основного объекта доступны через сам объект данных (например, Объект.ИмяРеквизита) как на клиенте, так и на сервере. Реквизиты формы же "живут" только тогда, когда форма открыта и ее контекст доступен.

Рассмотрим пример:


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

&НаКлиенте
Процедура КнопкаВыполнитьНаСервереНажатие(Команда)
    // Вызываем серверную процедуру
    МояСервернаяПроцедура();
КонецПроцедуры

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

Передача необходимых реквизитов в качестве параметров (внеконтекстный вызов)

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

  1. На клиенте получаем значения необходимых реквизитов формы.
  2. Вызываем серверную процедуру или функцию, помеченную &НаСервереБезКонтекста, передавая полученные значения в качестве параметров.
  3. На сервере работаем только с переданными параметрами, без доступа к объекту ЭтаФорма.

Посмотрим на пример:


// В модуле формы
&НаСервереБезКонтекста
Функция МояСервернаяФункцияБезКонтекста(ЗначениеРеквизита1, ЗначениеРеквизита2)
    // В этой функции у нас нет доступа к ЭтаФорма
    // Мы работаем только с переданными параметрами
    Результат = ЗначениеРеквизита1 + ЗначениеРеквизита2;
    Возврат Результат;
КонецФункции

&НаКлиенте
Процедура КнопкаВыполнитьНаСервереБезКонтекстаНажатие(Команда)
    // Получаем значения реквизитов формы на клиенте
    Значение1 = ЭтаФорма.РеквизитФормы1;
    Значение2 = ЭтаФорма.РеквизитФормы2;
    
    // Вызываем серверную функцию, передавая значения как параметры
    РезультатСервернойРаботы = МояСервернаяФункцияБезКонтекста(Значение1, Значение2);
    
    Сообщить("Результат с сервера: " + РезультатСервернойРаботы);
КонецПроцедуры

Этот подход предпочтителен, когда вам нужны только данные, а не интерактивное взаимодействие с формой на сервере.

Анализ структуры формы через метаданные (на этапе конфигурирования)

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

Получение метаданных текущей формы

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


&НаСервере
Процедура ВывестиМетаданныеРеквизитовТекущейФормы()
    СообщитьНаКлиенте("Метаданные реквизитов текущей формы:");
    Для Каждого РеквизитФормы Из ЭтаФорма.Метаданные().Реквизиты Цикл
        СообщитьНаКлиенте("  Имя: " + РеквизитФормы.Имя + ", Тип: " + РеквизитФормы.Тип.Имя + ", Синоним: " + РеквизитФормы.Синоним);
    КонецЦикла;
КонецПроцедуры

&НаКлиенте
Процедура КнопкаПоказатьМетаданныеНажатие(Команда)
    ВывестиМетаданныеРеквизитовТекущейФормы();
КонецПроцедуры

Получение метаданных произвольной формы

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


&НаСервереБезКонтекста
Функция ПолучитьОписаниеРеквизитовФормыДокумента(ИмяДокумента, ИмяФормы)
    КоллекцияОписанийРеквизитов = Новый Массив;
    
    // Проверяем существование документа
    Если Метаданные.Документы.Найти(ИмяДокумента) Тогда
        ДокументМетаданные = Метаданные.Документы[ИмяДокумента];
        
        // Проверяем существование формы для этого документа
        Если ДокументМетаданные.Формы.Найти(ИмяФормы) Тогда
            ФормаМетаданные = ДокументМетаданные.Формы[ИмяФормы];
            
            // Перебираем реквизиты формы
            Для Каждого Реквизит Из ФормаМетаданные.Реквизиты Цикл
                КоллекцияОписанийРеквизитов.Добавить("Имя: " + Реквизит.Имя + ", Тип: " + Реквизит.Тип.Имя + ", Синоним: " + Реквизит.Синоним);
            КонецЦикла;
        КонецЕсли;
    КонецЕсли;
    Возврат КоллекцияОписанийРеквизитов;
КонецФункции

&НаКлиенте
Процедура КнопкаПолучитьМетаданныеПроизвольнойФормыНажатие(Команда)
    ОписаниеРеквизитов = ПолучитьОписаниеРеквизитовФормыДокумента("РеализацияТоваровУслуг", "ФормаДокумента");
    Если ОписаниеРеквизитов.Количество() > 0 Тогда
        Сообщить("Реквизиты формы документа 'РеализацияТоваровУслуг.ФормаДокумента':");
        Для Каждого ОписаниеРеквизита Из ОписаниеРеквизитов Цикл
            Сообщить("  " + ОписаниеРеквизита);
        КонецЦикла;
    Иначе
        Сообщить("Форма или документ не найдены, или у формы нет реквизитов.");
    КонецЕсли;
КонецПроцедуры

Этот подход позволяет анализировать структуру формы, но не дает доступа к текущим значениям реквизитов незапущенной или произвольной формы на сервере, так как эти значения существуют только в контексте открытой формы.

Получение значений реквизитов формы без её визуального открытия (сложные сценарии)

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

Вариант 1: Использование регистра сведений для кеширования

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

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

Этот подход подходит, если данные реквизитов формы не меняются слишком часто или если небольшая задержка между изменением и доступностью на сервере допустима. Он также полезен для хранения настроек формы для конкретного пользователя.


// Пример структуры регистра сведений "НастройкиФормПользователей"
// Измерения: Пользователь (Справочник.Пользователи), ИмяФормы (Строка), ИмяРеквизита (Строка)
// Ресурсы: ЗначениеРеквизита (Тип: Характеристика, чтобы хранить разные типы данных)

// В модуле формы (НаСервере или НаКлиенте с вызовом НаСервере)
&НаСервере
Процедура СохранитьРеквизитыФормыВРегистр()
    НаборЗаписей = РегистрыСведений.НастройкиФормПользователей.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Пользователь.Установить(Пользователи.ТекущийПользователь());
    НаборЗаписей.Отбор.ИмяФормы.Установить("МояФормаДокумента"); // Или ЭтаФорма.Имя
    
    // Пример сохранения нескольких реквизитов
    Запись = НаборЗаписей.Добавить();
    Запись.Пользователь = Пользователи.ТекущийПользователь();
    Запись.ИмяФормы = "МояФормаДокумента";
    Запись.ИмяРеквизита = "МойРеквизит1";
    Запись.ЗначениеРеквизита = ЭтаФорма.МойРеквизит1;
    
    Запись = НаборЗаписей.Добавить();
    Запись.Пользователь = Пользователи.ТекущийПользователь();
    Запись.ИмяФормы = "МояФормаДокумента";
    Запись.ИмяРеквизита = "МойРеквизит2";
    Запись.ЗначениеРеквизита = ЭтаФорма.МойРеквизит2;
    
    НаборЗаписей.Записать();
    СообщитьНаКлиенте("Реквизиты формы сохранены в регистр.");
КонецПроцедуры

// Пример чтения реквизитов из регистра на сервере (в любом серверном модуле)
&НаСервереБезКонтекста
Функция ПолучитьЗначениеРеквизитаИзРегистра(ИмяФормы, ИмяРеквизита)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    НастройкиФормПользователей.ЗначениеРеквизита
        |ИЗ
        |    РегистрСведений.НастройкиФормПользователей КАК НастройкиФормПользователей
        |ГДЕ
        |    НастройкиФормПользователей.Пользователь = &Пользователь
        |    И НастройкиФормПользователей.ИмяФормы = &ИмяФормы
        |    И НастройкиФормПользователей.ИмяРеквизита = &ИмяРеквизита";
    
    Запрос.УстановитьПараметр("Пользователь", Пользователи.ТекущийПользователь());
    Запрос.УстановитьПараметр("ИмяФормы", ИмяФормы);
    Запрос.УстановитьПараметр("ИмяРеквизита", ИмяРеквизита);
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат Выборка.ЗначениеРеквизита;
    Иначе
        Возврат Неопределено;
    КонецЕсли;
КонецФункции

Вариант 2: Пакетный запуск конфигуратора и анализ выгрузки в XML (сложный, для метаданных)

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

  1. Пакетный запуск конфигуратора: Запускаем конфигуратор в пакетном режиме с ключом для выгрузки конфигурации в XML-файлы.
  2. Анализ XML: После выгрузки, мы получаем набор XML-файлов, описывающих все объекты конфигурации, включая формы и их реквизиты.
  3. Запись результата: Специализированное внешнее приложение или скрипт может проанализировать эти XML-файлы и записать полученные метаданные (например, имена реквизитов, их типы) в РегистрСведений 1С.
  4. Использование данных: Далее, в фоновом задании или любом серверном коде, мы оперируем уже записанными в регистр данными.

Этот вариант является достаточно сложным и применяется для задач, связанных с анализом метаданных конфигурации, а не с текущими значениями реквизитов открытой формы. Он не предоставляет способ получить *значения* реквизитов формы, которая не открыта.

Вариант 3: Чтение таблиц метаданных конфигурации напрямую из БД (очень сложный, не рекомендуется)

Этот вариант является самым сложным и требует глубоких знаний внутренней структуры базы данных 1С, что связано с риском нарушения целостности данных и потерей поддержки со стороны 1С. Мы рассмотрим его исключительно в ознакомительных целях, но категорически не рекомендуем использовать его в реальных проектах. Суть в том, чтобы читать файлы, описывающие метаданные, напрямую из таблиц базы данных 1С (например, таблица Config, Params). Эти файлы упакованы (например, deflate) и имеют специфический внутренний формат.

  1. Чтение файла *.si из таблицы Params: В этом файле содержатся имена записей в таблице Config (метаданных) и GUID типа объекта метаданных.
  2. Сопоставление имен: Необходимо создать соответствие между полным именем объекта метаданного и именем записи в таблице Config (формы в этой таблице могут иметь постфикс ".0").
  3. Чтение и разбор файла хранения формы: Файл хранения формы находится во внутреннем "скобко-файле". Его нужно разобрать, чтобы получить все необходимые реквизиты. Разбор такого формата является крайне нетривиальной задачей.

Этот метод является крайне низкоуровневым, не поддерживается платформой и требует постоянной адаптации при обновлении версий 1С. Он может быть оправдан только в очень специфических задачах, где все другие варианты неприемлемы.

Заключение

Мы с вами подробно рассмотрели различные подходы к получению реквизитов формы на сервере в 1С:Предприятии.

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

← К списку