Как реализовать присоединение файлов к объектам из расширения в 1С?

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

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

Суть проблемы: почему стандартный механизм не работает сразу?

Типовая подсистема "Работа с файлами" опирается на Определяемые типы. Для того чтобы ваш новый справочник (например, расш_Кандидаты) мог хранить файлы, его тип должен быть включен в определяемый тип ВладелецФайлов. На старых версиях платформы (до 8.3.15) изменять определяемые типы в расширениях было невозможно. Даже на новых версиях платформы часто возникают конфликты при обновлении или специфические ошибки записи в регистры сведений.

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

Шаг 1. Создание справочника хранения файлов

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

Шаг 2. Регистрация справочника в подсистеме

Чтобы система "увидела" ваш справочник как хранилище, необходимо расширить общий модуль РаботаСФайламиПереопределяемый. Рассмотрим код, который позволяет зарегистрировать связь между владельцем и справочником файлов:


&После("ПриОпределенииСправочниковХраненияФайлов")
Процедура расш_ПриОпределенииСправочниковХраненияФайлов(ТипВладелецФайла, ИменаСправочников)
    Если ТипВладелецФайла = Тип("СправочникСсылка.расш_Кандидаты") Тогда
        ИменаСправочников.Вставить("Файлы", Истина);
    КонецЕсли;
КонецПроцедуры

Обратите внимание: если ваш справочник назван по стандарту БСП (ИмяВладельца + "ПрисоединенныеФайлы"), система может найти его автоматически. Если же возникла ошибка, как в сообщении 10 форума, проверьте точность именования — даже одна пропущенная буква в названии расш_КандидатПрисоединенныеФайлы приведет к тому, что ИменаСправочников.Количество() будет равно 0.

Шаг 3. Обход ограничения определяемых типов через дублирующий регистр

Если ваша платформа не позволяет расширить определяемый тип ПрисоединенныйФайл, единственным надежным способом является создание собственного регистра сведений в расширении. Назовем его ДвоичныеДанныеФайловДоп. Рассмотрим его структуру:

  1. Измерение: Файл. Тип: СправочникСсылка.расш_КандидатыПрисоединенныеФайлы.
  2. Ресурс: ДвоичныеДанныеФайла. Тип: ХранилищеЗначения.

Теперь нам нужно заставить систему записывать данные именно в этот регистр, если файл относится к нашему новому справочнику. Для этого используем аннотацию &Вместо для процедуры ЗаписатьФайлВИнформационнуюБазу в общем модуле РаботаСФайламиСлужебный.


&Вместо("ЗаписатьФайлВИнформационнуюБазу")
Процедура расш_ЗаписатьФайлВИнформационнуюБазу(Знач ПрисоединенныйФайл, Знач ДвоичныеДанные)
    Если ТипЗнч(ПрисоединенныйФайл) = Тип("СправочникСсылка.расш_КандидатыПрисоединенныеФайлы") Тогда
        УстановитьПривилегированныйРежим(Истина);
        МенеджерЗаписи = РегистрыСведений.ДвоичныеДанныеФайловДоп.СоздатьМенеджерЗаписи();
        МенеджерЗаписи.Файл = ПрисоединенныйФайл;
        МенеджерЗаписи.ДвоичныеДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
        МенеджерЗаписи.Записать(Истина);
    Иначе
        // Вызов стандартной логики для типовых справочников
        ПродолжитьВызов(ПрисоединенныйФайл, ДвоичныеДанные);
    КонецЕсли;
КонецПроцедуры

Шаг 4. Чтение данных из расширенного регистра

Записать файл — это только половина дела. Нам нужно обеспечить корректное чтение файла, чтобы пользователь мог его открыть. Проанализируем функции общего модуля РаботаСФайлами. Нам потребуется перехватить функцию ХранилищеФайлаИзИнформационнойБазы.

Разберем пример реализации, который подменяет запрос к регистру в зависимости от типа ссылки:


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

    // В остальных случаях вызываем типовой механизм
    Возврат ПродолжитьВызов(ФайлСсылка);
КонецФункции

Рекомендации по использованию современных платформ

Если вы работаете на платформе 8.3.15 и выше, мы рекомендуем избегать создания дублирующих регистров. Вместо этого:

  1. Добавьте в расширение определяемый тип ВладелецФайлов и включите в него ваш основной справочник.
  2. Добавьте в расширение определяемый тип ПрисоединенныйФайл и включите в него ваш справочник хранения файлов.
  3. Добавьте в расширение определяемый тип ПрисоединенныйФайлОбъект.

В этом случае типовой регистр ДвоичныеДанныеФайлов начнет принимать ссылки вашего нового типа автоматически, и необходимость в написании кода через &Вместо отпадет. Это более "чистый" метод, который сохраняет целостность базы данных и упрощает будущие обновления конфигурации.

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

← На главную