Как обратиться к общему модулю в расширении 1С, если он может отсутствовать в конфигурации?

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

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

Проблема синтаксического контроля в расширениях

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

Решение 1: Использование механизмов БСП

Проанализируем самый надежный и «легальный» способ, который используется в современных типовых конфигурациях. Библиотека стандартных подсистем (БСП) предоставляет готовый инструментарий для таких случаев. Разберем работу функции ОбщегоНазначения.ОбщийМодуль().

Этот метод позволяет получить объект модуля по его имени в виде строки. Проанализируем пример использования:


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

Почему это работает? Внутри метода ОбщийМодуль() используется функция Вычислить(). Однако, поскольку этот код находится внутри состава БСП, которая уже прошла аудит и является доверенной, использование динамического вычисления там разрешено. Для вашего расширения это безопасный «шлюз».

Решение 2: Безопасное использование Вычислить() и Выполнить()

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

Рассмотрим, как правильно оформить такой вызов:


// Это пройдет аудит, так как строка константная
Модуль = Вычислить("МойСпециальныйМодуль");
Модуль.ВыполнитьПроцедуру();

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


Попытка
    // Получаем ссылку на модуль через литерал
    ОбъектМодуля = Вычислить("ДлительныеОперации");
    Результат = ОбъектМодуля.ПроверитьВыполнение(Идентификатор);
Исключение
    // Модуля не существует или к нему нет доступа
    Результат = Неопределено;
КонецПопытки;

Решение 3: Проверка существования через метаданные

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

Использование коллекции Метаданные.ОбщиеМодули позволяет проверить наличие объекта, не вызывая ошибок компиляции. Посмотрим на пример функции-проверки:


Функция МодульСуществует(ИмяМодуля) Экспорт
    Если Метаданные.ОбщиеМодули.Найти(ИмяМодуля) <> Неопределено Тогда
        Возврат Истина;
    КонецЕсли;
    Возврат Ложь;
КонецФункции

Более универсальный и быстрый способ, подходящий для проверки любых объектов — метод НайтиПоПолномуИмени. Рассмотрим его применение:


Если Метаданные.НайтиПоПолномуИмени("ОбщийМодуль.ЭлектроннаяПодпись") <> Неопределено Тогда
    // Мы точно знаем, что модуль есть, можем безопасно использовать Вычислить()
    МодульЭП = Вычислить("ЭлектроннаяПодпись");
КонецЕсли;

Решение 4: Создание «заглушек» для прохождения синтаксического контроля

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

  1. В расширении создается новый общий модуль с тем же самым именем, что и в целевой конфигурации (например, УправлениеШтрихкодами).
  2. Этот модуль оставляется пустым или в нем создаются пустые функции-заглушки.
  3. В свойствах модуля в расширении НЕ указывается связь с основной конфигурацией (не «вместо», а просто создание).

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

Решение 5: Обработки-посредники (Интерфейсный подход)

Если логика взаимодействия с отсутствующими модулями велика, разберем более архитектурно правильный подход. Мы можем создать в расширении вспомогательную обработку. В модуле менеджера этой обработки мы инкапсулируем все «опасные» вызовы.

Это позволяет:

Резюме и рекомендации

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

  1. Всегда проверяйте наличие модуля перед вызовом с помощью Метаданные.НайтиПоПолномуИмени(). Это самый быстрый и безопасный способ, который никогда не вызывает ошибок системы.
  2. Если в конфигурации гарантированно есть БСП, используйте ОбщегоНазначения.ОбщийМодуль("ИмяМодуля"). Это стандарт платформенных решений 1С.
  3. При отсутствии БСП используйте Вычислить("ИмяМодуля"), строго передавая строковый литерал. Избегайте конструкций типа Вычислить(Префикс + "Модуль"), так как они с высокой вероятностью будут отклонены аудитом 1С:Фреш.
  4. Для вызова процедур (которые не возвращают значения) можно использовать Выполнить("ИмяМодуля.ИмяПроцедуры()"), соблюдая те же правила работы со строками.

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

← На главную