Можно ли сделать расширение для объекта, который находится в другом расширении?

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

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

Проблема видимости объектов между расширениями

Разберем стандартную ситуацию: в Расширении1 создан новый Документ1. Мы создаем Расширение2 и хотим захватить в него форму этого документа, чтобы добавить на нее закладку. Однако при попытке сделать это через дерево метаданных мы обнаруживаем, что Расширение2 просто «не видит» объекты, созданные в Расширении1. Они не отображаются в списке доступных для заимствования объектов основной конфигурации.

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

Решение 1: Настройка зависимостей (для платформы 8.3.16 и выше)

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

  1. Откроем свойства Расширения2 (которое должно дополнять функционал).
  2. Найдем пункт Требуемые расширения.
  3. Добавим в этот список имя Расширения1.

Что это нам дает? Теперь Расширение2 «знает» о существовании типов данных первого расширения. Это позволяет нам программно обращаться к документам, справочникам и экспортным методам общих модулей первого расширения. Однако важно помнить: визуально «захватить» форму объекта из первого расширения во второе (через контекстное меню «Добавить в расширение») все равно не получится. Взаимодействие будет строиться исключительно через код.

Решение 2: Программное изменение формы через общие модули

Если нам нужно добавить кнопку или закладку на форму документа, созданного в Расширении1, мы воспользуемся методом программного изменения состава элементов. Рассмотрим ситуацию, когда мы не можем или не хотим менять код первого расширения.

Проанализируем алгоритм: мы будем использовать «перехват» процедур в основной конфигурации, которые вызываются при создании формы. Рассмотрим пример кода, который нужно разместить в Расширении2. Допустим, форма документа из первого расширения при открытии вызывает какой-то стандартный механизм основной конфигурации (например, общие модули БСП).


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

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

Решение 3: Архитектурный подход «Метаданные в корне»

Рассмотрим более надежный вариант, который часто обсуждается опытными разработчиками. Чтобы избежать «ректальных» методов (как выразились участники форума), при возможности стоит придерживаться следующего правила:

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

Если вы добавите Документ1 в основную конфигурацию (даже если она на поддержке, это допустимо), то любые расширения (и первое, и второе, и десятое) будут видеть этот объект в дереве метаданных. В этом случае:

  1. Расширение1 добавит свою логику проведения.
  2. Расширение2 добавит свои кнопки и формы.
  3. Конфликтов видимости не возникнет, так как оба расширения опираются на общий базис — основную конфигурацию.

Управление порядком применения расширений

Выясним, как платформа определяет, чей код выполнится первым, если оба расширения модифицируют один и тот же метод. Для этого существует свойство Порядок в списке расширений.

Разберем пример: если Расширение1 имеет порядок 10, а Расширение2 — порядок 20, то при использовании аннотации &После сначала выполнится код первого расширения, а затем — второго. Это критично, если ваше второе расширение полагается на элементы, которые должны быть созданы кодом первого расширения.

Программный обработчик кнопок

Частый вопрос: «Как в Расширении2 обработать нажатие кнопки, добавленной на форму документа из Расширения1?». Поскольку мы создаем кнопку программно, нам нужно также программно назначить ей действие. Выполним это следующим образом:


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

&НаКлиенте
Процедура Расш2_ОбработчикНажатия(Команда)
    ПоказатьПредупреждение(,"Кнопка из второго расширения успешно сработала!");
КонецПроцедуры

Резюме

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

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

← На главную