Прикрепление файлов к объектам информационной базы через управляемую форму в веб-клиенте 1С – это частая задача, которая имеет свои особенности, обусловленные ограничениями веб-среды и клиент-серверной архитектурой платформы 1С. Мы разберем основные принципы, распространенные ошибки и предоставим пошаговое руководство для реализации такого функционала.
Наш читатель столкнулся с проблемой при попытке реализовать прикрепление файлов, используя, возможно, устаревший или некорректно адаптированный код. Давайте проанализируем его ситуацию и предложим современное и надежное решение.
Когда вы переносите код из одного места в другое, особенно в контексте 1С, где тесно связаны форма, сервер и клиент, часто возникают ошибки, если не учитывать контекст выполнения. Основные проблемы, с которыми столкнулся автор:
НачатьПомещениеФайлов без должного понимания его работы или в условиях, когда уже существуют более современные и предпочтительные подходы.Запись определенного типа) или предполагал наличие определенных переменных (вроде ВладелецФормы.Объект.Ссылка), которые отсутствуют в новой форме.В веб-клиенте 1С, в отличие от тонкого клиента, существуют ограничения на прямой доступ к файловой системе пользователя. Все операции с файлами должны выполняться через специальные асинхронные методы платформы, которые обеспечивают безопасное взаимодействие между клиентом и сервером.
Прежде чем перейти к решению, давайте рассмотрим ключевые моменты, которые необходимо учитывать при работе с файлами в веб-клиенте:
Ждать и асинхронные процедуры (Асинх).ХранилищеЗначения в объектах данных (например, справочниках, документах), либо стандартная подсистема "Работа с файлами" из Библиотеки стандартных подсистем (БСП), которая предоставляет более гибкие механизмы, включая версионирование и хранение файлов в томах.Рассмотрим, какие методы используются для помещения файлов с клиента на сервер, и какие из них предпочтительны в современных версиях платформы 1С.
НачатьПомещениеФайла / НачатьПомещениеФайловИзначально автор использовал следующий код:
&НаКлиенте
Процедура ЗагрузитьФайл(Команда)
ОписаниеОповещения = Новый ОписаниеОповещения("ОбработатьВыборФайла", ЭтаФорма);
ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
ДиалогОткрытияФайла.МножественныйВыбор = Ложь;
НачатьПомещениеФайлов(ОписаниеОповещения, , ДиалогОткрытияФайла, Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьВыборФайла(ПомещенныеФайлы,ДополнительныеПараметры) Экспорт
Если ПомещенныеФайлы = Неопределено Тогда
Возврат;
КонецЕсли;
Для каждого ПереданныйФайл Из ПомещенныеФайлы Цикл
ПутьКФайлу = ПереданныйФайл.Имя;
Запись.ИмяФайла = РазборСтроки(ПутьКФайлу, "\"); // <-- Здесь первая проблема
Элементы.ОткрытьФайл.Заголовок = Запись.ИмяФайла;
Адрес = ПереданныйФайл.Хранение;
КонецЦикла;
КонецПроцедуры
Этот подход использует метод НачатьПомещениеФайлов, который является немодальным и вызывает процедуру оповещения после выбора файла. В процедуру оповещения ОбработатьВыборФайла передается коллекция ПомещенныеФайлы, где каждый элемент содержит имя файла и адрес во временном хранилище. Проблема этого кода в том, что переменные Запись, РазборСтроки, Элементы.ОткрытьФайл не существуют в контексте новой формы автора, что приводит к ошибкам. Кроме того, метод НачатьПомещениеФайла не рекомендуется к использованию с платформы 8.3.15, так как появились более унифицированные и удобные методы.
ПоместитьФайлНаСерверАсинх / НачатьПомещениеФайловНаСерверС версии 8.3.15 платформы 1С рекомендуется использовать методы ПоместитьФайлНаСерверАсинх или НачатьПомещениеФайловНаСервер. Они также асинхронны, но предоставляют более гибкие возможности настройки диалога выбора файлов и возвращают результат, который можно обработать с помощью оператора Ждать.
Именно такой подход был предложен нашим читателям в ответ на его проблему. Давайте подробно разберем этот вариант решения.
ПоместитьФайлНаСерверАсинхМы будем использовать предложенный в обсуждении код и объясним каждый его шаг, а также как адаптировать его под вашу конкретную задачу.
На клиенте мы запускаем процесс выбора файла. Этот процесс должен быть асинхронным, чтобы не блокировать интерфейс пользователя.
&НаКлиенте
Асинх Процедура ВыбратьФото(Команда)
// Дополнительная проверка, если нужно
Если НЕ ЗначениеЗаполнено(ЭтотОбъект.Комментарий) Тогда
ПоказатьПредупреждение(,"Заполните комментарий !!!");
Возврат;
КонецЕсли;
// Вызываем асинхронный метод для помещения файла на сервер
Результат = Ждать ПоместитьФайлНаСерверАсинх;
// Проверяем результат операции
Если Результат <> Неопределено И Не Результат.ПомещениеФайлаОтменено Тогда
Попытка
// Передаем данные на сервер для сохранения
ВыбратьФотоНаСервере(ВладелецФормы.Объект.Ссылка, Результат.Адрес, Результат.СсылкаНаФайл.Имя); // <-- Здесь была проблема
ЭтаФорма.Закрыть(); // Возможно, закрытие формы после выбора
Исключение
ТекстСообщения = КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
ПоказатьПредупреждение(,ТекстСообщения);
КонецПопытки;
КонецЕсли;
КонецПроцедуры
&НаКлиенте Асинх Процедура ВыбратьФото(Команда): Объявляем клиентскую процедуру, которая будет вызываться, например, по нажатию кнопки. Ключевое слово Асинх указывает на асинхронный характер процедуры, что позволяет использовать оператор Ждать.ЗначениеЗаполнено(ЭтотОбъект.Комментарий) являются примером дополнительной логики, которая может быть вам не нужна или должна быть адаптирована под ваши реквизиты.Результат = Ждать ПоместитьФайлНаСерверАсинх;: Это центральная часть. Метод ПоместитьФайлНаСерверАсинх открывает диалог выбора файла для пользователя. Оператор Ждать заставляет выполнение кода приостановиться до тех пор, пока пользователь не выберет файл или не отменит операцию. Результатом является объект, содержащий информацию о выбранном файле.Результат <> Неопределено: Проверяем, что операция не была прервана системой.Не Результат.ПомещениеФайлаОтменено: Проверяем, что пользователь не отменил выбор файла в диалоге.ВыбратьФотоНаСервере, передавая ей необходимые параметры. Здесь и возникает основная проблема автора с ВладелецФормы.Объект.Ссылка, которую мы рассмотрим далее.После того как файл помещен во временное хранилище на сервере, нам нужно его оттуда забрать и сохранить в постоянном месте – в информационной базе.
&НаСервере
Процедура ВыбратьФотоНаСервере(Док, СсылкаНаФайлВХранилище, ИмяФайла)
Попытка
// Получаем объект документа/справочника, к которому прикрепляем файл
// ВладелецФормы.Объект.Ссылка должна быть заменена на корректный объект
ОбъектВладелец = Док.ПолучитьОбъект(); // "Док" теперь корректная ссылка
// Добавляем новую строку в табличную часть для хранения информации о файле
НоваяСтрокаФайла = ОбъектВладелец.СписокФото.Добавить(); // "СписокФото" - пример табличной части
НоваяСтрокаФайла.ИмяФайла = ИмяФайла;
// НовСтр.Комментарий = СокрЛП(ЭтотОбъект.Комментарий); // Если комментарий передан как параметр
// Или берется из реквизитов формы-владельца
// Получаем двоичные данные файла из временного хранилища
НоваяСтрокаФайла.Фото = Новый ХранилищеЗначения(ПолучитьИзВременногоХранилища(СсылкаНаФайлВХранилище));
// Записываем изменения в объект
ОбъектВладелец.Записать();
Исключение
ВызватьИсключение "Ошибка сохранения файла на сервере: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Давайте разберем эту серверную процедуру:
&НаСервере Процедура ВыбратьФотоНаСервере(...): Это серверная процедура, которая выполняется на сервере 1С.Док: Это ссылка на объект (например, документ или элемент справочника), к которому мы хотим прикрепить файл. В исходном примере автора была ошибка с ВладелецФормы.Объект.Ссылка. Критически важно: Если ваша текущая форма не является формой элемента справочника или документа, то ВладелецФормы.Объект.Ссылка не будет существовать. Вам нужно определить, к какому объекту в базе вы хотите привязать файл, и передать его ссылку (или сам объект) в эту процедуру в качестве параметра Док. Например, если форма открыта для нового документа, вы можете передать пустую ссылку, а после записи документа обновить ссылку. Если форма открыта для уже существующего объекта, передайте Объект.Ссылка текущей формы.СсылкаНаФайлВХранилище: Этот параметр соответствует Результат.Адрес из клиентской процедуры. Это адрес, по которому файл временно хранится на сервере.ИмяФайла: Этот параметр соответствует Результат.СсылкаНаФайл.Имя из клиентской процедуры. Это имя, которое выбрал пользователь на клиенте.ОбъектВладелец = Док.ПолучитьОбъект();: Мы получаем объект (документ, справочник), к которому будет прикреплен файл, чтобы работать с его реквизитами.НоваяСтрокаФайла = ОбъектВладелец.СписокФото.Добавить();: Здесь предполагается, что у вашего объекта ОбъектВладелец есть табличная часть, например, с именем СписокФото, куда вы будете добавлять информацию о прикрепленных файлах. Если у вас нет такой табличной части, вам нужно ее создать или использовать другой механизм хранения (например, отдельный справочник "ПрисоединенныеФайлы").НоваяСтрокаФайла.ИмяФайла = ИмяФайла;: Сохраняем имя файла.НоваяСтрокаФайла.Фото = Новый ХранилищеЗначения(ПолучитьИзВременногоХранилища(СсылкаНаФайлВХранилище));: Это самый важный шаг для сохранения данных файла.
ПолучитьИзВременногоХранилища(СсылкаНаФайлВХранилище): Эта функция возвращает двоичные данные файла, используя переданный адрес из временного хранилища.Новый ХранилищеЗначения(...): Полученные двоичные данные помещаются в объект ХранилищеЗначения. Это стандартный механизм 1С для хранения произвольных двоичных данных (файлов, изображений) непосредственно в информационной базе.ОбъектВладелец.Записать();: Сохраняем измененный объект (документ, справочник) в базе данных.ВладелецФормы.Объект.СсылкаОсновная причина ошибки автора заключалась в непонимании, что такое ВладелецФормы.Объект.Ссылка. Давайте рассмотрим подробнее.
Когда вы видите ВладелецФормы.Объект.Ссылка в примере кода, это означает, что форма, в которой этот код выполняется, должна иметь "владельца", и у этого владельца должен быть реквизит Объект (обычно это происходит, когда форма является формой элемента справочника или документа, и свойство Объект содержит данные этого элемента), и у этого Объекта должно быть свойство Ссылка.
В вашей ситуации, если форма является формой документа или справочника, вы можете передать ее собственную ссылку:
// Вместо ВладелецФормы.Объект.Ссылка
ВыбратьФотоНаСервере(Объект.Ссылка, Результат.Адрес, Результат.СсылкаНаФайл.Имя);
Если же ваша форма не является формой объекта (например, это форма обработки или какой-то вспомогательной формы), и вы хотите привязать файл к определенному документу или элементу справочника, то вам нужно сначала получить ссылку на этот объект, а затем передать ее в серверную процедуру. Например:
// Если ссылка на документ хранится в реквизите формы "ДокументДляПрикрепления"
ВыбратьФотоНаСервере(РеквизитФормы.ДокументДляПрикрепления, Результат.Адрес, Результат.СсылкаНаФайл.Имя);
Самое главное – это корректно определить, к какому именно объекту информационной базы вы хотите прикрепить файл, и передать его ссылку в серверную процедуру в качестве первого параметра. В приведенном примере ВыбратьФотоНаСервере этот параметр назван Док.
Как мы уже выяснили, файлы нельзя хранить в реквизитах формы. Их необходимо сохранять в информационной базе.
ХранилищеЗначенияЭто самый простой способ, который мы использовали в примере выше. В объекте базы данных (например, в справочнике или документе) создается реквизит типа ХранилищеЗначения. В него записываются двоичные данные файла. Дополнительно можно создать реквизиты для хранения имени файла, размера, даты создания и т.д. Если к одному объекту может быть прикреплено несколько файлов, тогда создается табличная часть, каждая строка которой содержит реквизиты для одного файла, включая ХранилищеЗначения.
Для более сложных сценариев, когда требуется версионирование файлов, разграничение прав доступа, хранение файлов в томах на диске (чтобы не раздувать базу данных), или просто унифицированный интерфейс, настоятельно рекомендуется использовать стандартную подсистему "Присоединенные файлы" из Библиотеки стандартных подсистем (БСП) от 1С.
Подключение этой подсистемы требует определенных шагов по интеграции в вашу конфигурацию, включая:
ВладелецПрисоединенныхФайлов для ваших объектов, к которым будут прикрепляться файлы.БСП предоставляет готовые механизмы как для хранения файлов непосредственно в базе данных, так и для хранения во внешних томах (на файловом сервере), что очень важно для больших объемов данных.
Результат после Ждать ПоместитьФайлНаСерверАсинх, или почему ВладелецФормы оказался неопределенным) и точно локализовать причину ошибки.Результат.Адрес и Результат.СсылкаНаФайл.Имя:
Результат.Адрес: Это строка, содержащая адрес файла во временном хранилище на сервере. Именно этот адрес нужно передавать в серверную функцию ПолучитьИзВременногоХранилища().Результат.СсылкаНаФайл.Имя: Это полное имя файла, выбранное пользователем на клиенте (например, "Документ.pdf"). Вы можете использовать его для сохранения файла с оригинальным именем.Надеемся, это подробное объяснение поможет вам успешно реализовать функционал прикрепления файлов в ваших управляемых формах на веб-клиенте 1С.