Документация для разработчиков
Темная тема

Создание своего провайдера

Описание

Провайдер должен наследовать класс \Bitrix\DocumentGenerator\DataProvider.

При желании можно наследовать существующий провайдер, переопределить нужные методы, добавить его в список и он будет фигурировать там наравне с предустановленными.

У класса \Bitrix\DocumentGenerator\DataProvider есть несколько вспомогательных наследников:

  • \Bitrix\DocumentGenerator\DataProvider\EntityDataProvider - для работы с таблетами ORM;
  • \Bitrix\DocumentGenerator\DataProvider\HashDataProvider - для работы с простыми провайдерами в виде хеша;
  • \Bitrix\DocumentGenerator\DataProvider\ArrayDataProvider - предоставляет доступ к множественным значениям одного поля.

Цепочка провайдеров

У каждого провайдера может быть указан родительский провайдер. Если провайдер был инициализирован автоматически из описания поля, то у него будет указан родительский провайдер. Или его можно указать вручную через \Bitrix\DocumentGenerator\DataProvider::setParentProvider($dataProvider);.

Проверки

Проверка прав доступа

Проверка прав осуществляется методом \Bitrix\DocumentGenerator\DataProvider::hasAccess($userId);.

Проверка доступа вызывается в \Bitrix\DocumentGenerator\Document::hasAccess() каждый раз при работе с документом. Это не абстрактный метод. Если метод не определен, но у текущего провайдера есть родитель - этот метод будет вызван у родительского провайдера. Если родителя нет - вернет false.

Проверка успешной загрузки данных провайдера

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

  1. До загрузки данных. В этом состоянии провайдер отдает список своих полей "обезличенно".
  2. После загрузки данных. В этом состоянии провайдер может отдать "актуальный" список своих полей и их значения.

В исходном классе нет метода для получения данных (но есть в наследнике \Bitrix\DocumentGenerator\DataProvider\EntityDataProvider).

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

Для хранения данных есть атрибут $data. Исходный метод определения загруженности провайдера:

    /**
	 * @return bool
	 */
	public function isLoaded()
	{
		return $this->data !== null;
	}

Этот метод вызывается в методе проверки прав и при получении значения. Если на момент обращения к этим методам провайдер не будет загружен - проверка прав вернет false, а значение не будет получено.

Поля провайдера

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

public function getFields()
{
    if($this->fields === null)
    {
        parent::getFields();
        $this->fields['MY_FIELD'] = ['TITLE' => 'My Field Title',];
    }

    return $this->fields;
}

Он должен возвращать массив, где ключ - название поля (лучше использовать английские буквы в верхнем регистре + подчеркивание), а значение - его описание. Описание поля может содержать следующие ключи (все они не обязательны, можно оставить пустой массив):

  • TITLE - заголовок поля (если его нет - выводится название)
  • TYPE - тип поля. Может принимать значения:
    • IMAGE - поле является путем к файлу-картинке
    • STAMP - аналогично IMAGE, но это поле является подписью или печатью
    • DATE - будет сформирован объект класса \Bitrix\DocumentGenerator\Value\DateTime
    • TEXT - обычное поле, но на странице изменения документа вместо input будет textarea
    • NAME - будет сформирован объект класса \Bitrix\DocumentGenerator\Value\Name
    • PHONE - будет сформирован объект класса \Bitrix\DocumentGenerator\Value\PhoneNumber
    • также сюда можно в явном виде передать полное имя класса-наследника \Bitrix\DocumentGenerator\Value
  • FORMAT - формат по умолчанию для наследников \Bitrix\DocumentGenerator\Value
  • VALUE - описание способа получения значения. Само значение по умолчанию берётся из $data. В качестве значения может выступать:
    • собственно, само значение поля в виде числа или строки
    • строка, содержащая название другого поля - в этом случае будет сделана попытка получить значение этого поля из другого поля с соответствующим названием. (пример - поле COMPANY_NAME из \Bitrix\Crm\Integration\DocumentGenerator\DataProvider\Lead)
    • callable-конструкция. В этом случае для получения значения будет вызван этот метод/функция
    • Closure (анонимная функция). Аналогично предыдущему пункту будет вызвана при получении значения. Но если вы пишете значения полей в атрибуты объекта, то придётся отказаться от этого варианта, лучше сделать соответствующий метод и указать его имя в явном виде
    • массив значений. В этом случае в шаблон попадёт объект \Bitrix\DocumentGenerator\Value\Multiple
  • PROVIDER - если значение поля должно быть другим провайдером, то здесь надо указать полное имя соответствующего класса.
  • OPTIONS - массив $options, который будет передан в конструктор провайдера.
    • VALUES - массив значений, которые будут переданые в созданный по этому описанию провайдер и переопределят его значения.
    • COPY - указатель на описание другого поля. Если вы хотите иметь несколько полей с одинаковым содержимым, но разным названием, то можно сделать это с помощью этого ключа. Например, у вас есть основное поле, это провайдер с множеством опций. Вы хотите, чтобы доступ к этому полю мог быть получен через разные названия полей. В этом случае создаются новые поля, где указываются только TITLE, VALUE и OPTIONS[COPY], равные названию основного поля.

Итоговое значение

За получение значений полей отвечает метод \Bitrix\DocumentGenerator\DataProvider::getValue().

Если по каким-то причинам не устраивает получение значения поля из его описания, то можно переопределить этот метод. Например, так:

public function getValue($name)
{
    if($name == 'myComplexFieldValue')
    {
        return 'complexValue';
    }
    
    return parent::getValue($name);
}

Но класс спроектирован таким образом, что метод получения значения можно указать в описании поля, поэтому переопределять этот метод не рекомендуется.

Исходная реализация сначала ищет значение поля в $this->data и если его нет - пытается его получить из описания поля.

Само вычисление значения выполняет \Bitrix\DocumentGenerator\DataProviderManager::getDataProviderValue().

Порядок получения значения следующий:

  1. Считывается описание поля из \Bitrix\DocumentGenerator\DataProvider::getFields(). Если такого поля нет - вернется false.
  2. Если в $options провайдера есть ключ VALUES и в нём есть значение этого поля, то значение берется оттуда.
  3. Если в VALUE описании поля строка - значение берется как getValue() текущего провайдера с этой строкой
  4. Если в VALUE - callable-конструкция, то она вызывается для получения значения. На вход этого метода/функции всегда идёт название поля
  5. Если в описании поля есть PROVIDER, то создается новый экземпляр этого класса, на вход ему передается вычисленное значеие, а в $options - передаются OPTIONS из описания поля

После получения значения над ним вызывается \Bitrix\DocumentGenerator\DataProviderManager::prepareValue().

Этот метод преобразует полученное значение к соответствующему типу из описания поля. Если вычисленное значение уже экземпляр \Bitrix\DocumentGenerator\Value, то он возвращается как есть.

Множественное значение

Возможна ситуация, когда в значении одного поля может быть несколько вариантов. Особенно это актуально для полей-провайдеров. Например, поле "моя компания" в провайдерах CRM. Моих компаний может быть несколько, и пользователь должен иметь возможность быстро сменить используемую компанию в документе.

Результат вычисления значения (обычно это результат выполнения callable-конструкции в описании поля) должен иметь вид простого массива, где каждое значение - это массив вида:

array(
    'VALUE' => $value, // само значение
    'TITLE' => $title, // заголовок, который будет выводиться в форме изменения документа для этого пункта
    'SELECTED' => $selected, // true - если должно использоваться это значение по умолчанию
);

Если SELECTED у всех false, то при формировании документа будет выбран первый вариант из списка.

Значения в виде массивов

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

В этом случае описание поля должно быть сформировано следующим образом:

$this->fields['LIST'] = [
    'PROVIDER' => \Bitrix\DocumentGenerator\DataProvider\ArrayDataProvider::class,
    'TITLE' => 'My List',
    'OPTIONS' => [
        'ITEM_PROVIDER' => 'MyItemDataProvider::class', // полное имя класса-провайдера отдельного элемента 
        'ITEM_NAME' => 'ITEM', // название поля, по которому будет идти обращение к элементу
        'ITEM_TITLE' => 'My Item', // заголовок элемента
    ],
    'VALUE' => [$this, 'loadItems'],
];

Метод loadItems должен вернуть простой массив сформированных провайдеров.



© «Битрикс», 2001-2022, «1С-Битрикс», 2022
Наверх