Перейти к содержанию

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

Используйте класс Bitrix\DocumentGenerator\Template, чтобы загрузить шаблон и получить его тело, поля и связанные провайдеры. Для создания документа передайте подготовленный объект шаблона в метод Document::createByTemplate(), как показано в статье Документы.

Модель шаблона

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

Обязательные свойства обозначены *.

|

|| Свойство | Тип | Назначение || || ID | int | Идентификатор шаблона || || NAME* | string | Название шаблона длиной от 1 до 100 символов || || CODE | string | Символьный код шаблона || || MODULE_ID* | string | Идентификатор модуля, который зарегистрировал шаблон || || FILE_ID* | int | Идентификатор исходного файла в хранилище модуля || || BODY_TYPE* | class-string<Body> | Класс тела документа. Если загруженное значение отсутствует или не наследует Body, объект Template использует Body\Docx || || REGION | string | Регион, по которому модуль выбирает язык и региональные настройки форматирования || || WITH_STAMPS | string | Управляет обработкой полей STAMP.

  • Y — включить подписи и печати,
  • N — не добавлять подписи и печати.

Значение по умолчанию — N || || PRODUCTS_TABLE_VARIANT | string | Вариант табличной части: все позиции, только товары или только услуги. Значение по умолчанию — пустая строка || |#

Класс Body разбирает содержимое конкретного формата. Класс Body\Docx выполняет несколько действий:

  • обрабатывает основной документ, колонтитулы и другие части DOCX,

  • извлекает плейсхолдеры,

  • заменяет значения и изображения.

Получить сохраненный шаблон и его поля

Чтобы получить объект шаблона и его поля, сначала сохраните DOCX-шаблон в модуле генератора документов. Например, для CRM-шаблона откройте раздел CRM > Настройки > Настройки CRM > Другое > Шаблоны документов или перейдите по адресу /crm/documents/templates/. Нажмите Добавить шаблон, загрузите DOCX и выберите разделы CRM, в которых он будет доступен. После сохранения идентификатор шаблона появится в столбце ID списка шаблонов.

Шаблон также можно добавить через REST API методом documentgenerator.template.add. Такой шаблон относится к REST-приложению и использует REST-провайдер.

Чтобы получить сохраненный шаблон по идентификатору в коде, подключите модуль documentgenerator и вызовите метод Template::loadById(). Метод возвращает объект Template или null, если запись не найдена или идентификатор некорректен. Повторно загружать DOCX-файл не нужно.

Если поля зависят от основного провайдера, передайте его класс в setSourceType() до первого вызова getFields(). Объект шаблона кеширует рассчитанный список полей в памяти.

<?php

use Bitrix\DocumentGenerator\DataProvider;
use Bitrix\DocumentGenerator\Template;
use Bitrix\Main\Loader;

if (!Loader::includeModule('documentgenerator'))
{
    throw new \RuntimeException('Модуль documentgenerator не установлен');
}

$templateId = 17;
/** @var class-string<DataProvider> $providerClass */
// Замените классом провайдера из вашего модуля
$providerClass = Acme\Documents\OrderDataProvider::class;

$template = Template::loadById($templateId);
if ($template === null)
{
    throw new \RuntimeException('Шаблон не найден');
}

$template->setSourceType($providerClass);
if ($template->getSourceType() === null)
{
    throw new \RuntimeException('Класс провайдера недоступен для шаблона');
}

$body = $template->getBody();
if ($body === null)
{
    throw new \RuntimeException('Не удалось получить тело шаблона');
}

$placeholders = $body->getPlaceholders();
$fields = $template->getFields();

После выполнения кода переменные содержат:

  • $template — сохраненный шаблон по его идентификатору.

  • $body — объект, который представляет содержимое DOCX.

  • $placeholders — коды плейсхолдеров, найденные в теле DOCX.

  • $fields — описания доступных полей основного и служебного провайдеров.

В $fields входят не только поля, которые использованы в DOCX, но и все поля, доступные для выбранного провайдера. Массив также содержит служебные поля DOCUMENT и SOURCE.

Выбрать основной провайдер

У шаблона может быть несколько доступных провайдеров. Метод getDataProviders() возвращает их классы:

$providerClasses = $template->getDataProviders(true);

При первом вызове передайте true, чтобы метод преобразовал сохраненные фильтры в имена классов. Метод сохраняет результат в объекте Template. Поэтому вызовите getDataProviders(true) раньше getDataProviders() без аргумента.

Выберите из полученного списка класс, который соответствует исходному объекту документа. Затем выполните два действия:

  1. Передайте класс в метод setSourceType() до вызова getFields().

  2. Проверьте результат через getSourceType(). Если класс не зарегистрирован в DataProviderManager, метод вернет null.

Выбранный класс становится основным провайдером текущего документа. Через поле SOURCE документ получает данные исходного объекта. Служебный провайдер DOCUMENT использует тот же источник.

Связанные провайдеры хранятся в настройках шаблона. Не добавляйте эту связь напрямую через Model\TemplateProviderTable. Настраивайте область применения шаблона через штатный интерфейс модуля, а структуру собственного провайдера формируйте по правилам статьи Провайдеры данных.

Устройство полей шаблона

Ключ массива, который возвращает Template::getFields(), совпадает с кодом плейсхолдера. Описание поля определяет источник, тип представления и поведение при пустом значении.

|

|| Ключ | Тип | Назначение || || TITLE | string | Понятное пользователю название поля || || VALUE | mixed | Путь к значению в дереве провайдеров, скалярное значение или обработчик, который возвращает значение || || TYPE | string или class-string<Value> | Один из типов IMAGE, STAMP, DATE, TEXT, NAME, PHONE или класс-наследник Value, который подготовит значение || || PROVIDER | class-string<DataProvider> | Класс вложенного провайдера || || PROVIDER_NAME | string | Имя класса провайдера, которое модуль проверяет перед использованием || || REQUIRED | string | Признак обязательного значения: Y или N. Для сохраненной настройки значение по умолчанию — N || || HIDE_ROW | string | Признак удаления строки таблицы или абзаца: Y или N. Для сохраненной настройки значение по умолчанию — N || || OPTIONS | array | Дополнительные настройки поля и провайдера. Состав зависит от типа поля || |#

Шаблон выбирает описание каждого плейсхолдера по приоритету:

  1. Настройка для конкретного шаблона.

  2. Настройка для основного провайдера шаблона.

  3. Общая настройка без шаблона и провайдера.

  4. Описание поля, которое DataProviderManager получил из основного или служебного провайдера.

Метод getFields() всегда добавляет два служебных корневых поля: SOURCE и DOCUMENT.

  • SOURCE открывает данные исходного объекта.

  • DOCUMENT открывает дату создания, название и номер документа, а также исходный объект через вложенное поле SOURCE.

Внимание

Не сохраняйте настройки полей напрямую через Model\FieldTable. Этот ORM-класс обслуживает внутреннее хранение. Формируйте структуру полей в провайдере или используйте интерфейс настройки шаблона.

Добавить плейсхолдеры в DOCX

Добавьте текстовые плейсхолдеры в DOCX самостоятельно и заключите каждый код в фигурные скобки. Код может содержать латинские буквы, цифры, точки, символы _ и -.

{DOCUMENT.DOCUMENT_NUMBER}
{DOCUMENT.DOCUMENT_CREATE_TIME}
{SOURCE.CLIENT.NAME}

Точка разделяет уровни провайдеров. Например, путь SOURCE.CLIENT.NAME последовательно обращается к полю CLIENT основного провайдера и полю NAME вложенного провайдера.

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

Во время обработки модуль заменяет неизвестный плейсхолдер пустой строкой. До генерации проверьте, что для каждого кода из $body->getPlaceholders() есть ключ с таким же именем в $template->getFields(). Отсутствующий ключ указывает на опечатку в плейсхолдере или на недоступное поле провайдера.

Форматировать значения

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

{DOCUMENT.DOCUMENT_CREATE_TIME~format=DD.MM.YYYY}
{SOURCE.CLIENT.NAME~letterCase=upper}

Правила записи параметров:

  • Разделяйте несколько параметров запятыми.

  • Используйте Y и N для логических значений.

  • Учитывайте, что доступный набор параметров зависит от класса Value.

  • Сохраняйте регистр в именах параметров. Например, используйте CurId, а не curid.

Регистр итоговой строки

После основного форматирования модуль преобразует результат через Value\PlaneString. Поэтому модификатор letterCase можно применить к итоговой строке любого поля, например к названию месяца в отформатированной дате. Для исходной строки или числа Value\PlaneString выполняет и основное преобразование.

Модификатор letterCase поддерживает три значения:

|

|| Значение | Результат || || lower | Нижний регистр || || upper | Верхний регистр || || title | Верхний регистр для первых букв слов || |#

Массив или объект без класса Value и без строкового представления нельзя вставить как обычный текст. Опишите для такого поля подходящий тип или вложенный провайдер.

Дата и время

Тип DATE использует Value\DateTime. По умолчанию класс берет формат даты из региональных настроек текущего контекста генерации. Параметр format переопределяет его для одного плейсхолдера.

{DOCUMENT.DOCUMENT_CREATE_TIME~format=DD.MM.YYYY}

Класс принимает объект Bitrix\Main\Type\Date, дату и время или строку, которую может разобрать Framework. Если строку преобразовать не удалось, результат будет пустым.

Имя

Тип NAME использует Value\Name. Исходное значение должно быть массивом с частями имени: TITLE, NAME, SECOND_NAME, LAST_NAME и при необходимости GENDER.

Параметр format задает порядок частей имени. Без него модуль использует формат имен из региональных настроек. В строке формата доступны подстановки:

  • #TITLE# — обращение,

  • #NAME# — имя,

  • #LAST_NAME# — фамилия,

  • #SECOND_NAME# — отчество,

  • #NAME_SHORT# — первая буква имени и точка,

  • #LAST_NAME_SHORT# — первая буква фамилии и точка,

  • #SECOND_NAME_SHORT# — первая буква отчества и точка.

Параметр case изменяет падеж русскоязычного имени:

|

|| Значение | Падеж || || -1 | Именительный || || 0 | Родительный || || 1 | Дательный || || 2 | Винительный || || 3 | Творительный || || 4 | Предложный || |#

Класс изменяет падеж, если непустые части имени содержат только русские буквы, пробелы и дефисы. Пол задает элемент GENDER со значением F или M. Если элемент не задан, класс пытается определить пол по отчеству. Когда пол определить нельзя, части имени остаются в исходном падеже.

{SOURCE.CONTACT.NAME~format=#LAST_NAME# #NAME_SHORT# #SECOND_NAME_SHORT#,case=1}

Имена параметров Format и Case с заглавной буквы работают как псевдонимы для format и case.

Телефон

Тип PHONE использует Value\PhoneNumber. Класс разбирает исходную строку через Bitrix\Main\PhoneNumber\Parser и по умолчанию возвращает номер в международном формате.

Параметр format принимает одно из значений класса Bitrix\Main\PhoneNumber\Format:

  • E.164 — формат E.164, например +74951234567.

  • International — международный формат с разделителями.

  • National — национальный формат.

Значение по умолчанию — International.

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

Для списка простых значений DataProviderManager создает Value\Multiple. По умолчанию класс объединяет непустые элементы через запятую и пробел.

|

|| Модификатор | Значение | Результат || || mseparator | 1 | Разделяет элементы запятой и пробелом || || mseparator | 2 | Разделяет элементы переводом строки || || mfirst | Y | Выводит только первый непустой элемент || |#

{SOURCE.CONTACT.PHONES~mseparator=2}
{SOURCE.CONTACT.EMAILS~mfirst=Y}

Остальные модификаторы применяются к каждому элементу списка. Массивы и объекты без подходящего типа класс пропускает.

Элемент списка провайдеров

Если часть пути возвращает ArrayDataProvider, модуль по умолчанию берет поле первого элемента. Параметр index выбирает элемент по индексу. Нумерация начинается с нуля.

{SOURCE.PRODUCTS.NAME~index=0}
{SOURCE.PRODUCTS.NAME~index=1}

Первый плейсхолдер выведет название первого товара, второй — второго. Если элемента с заданным индексом нет, модуль подставит пустую строку.

Адрес CRM

Поля класса Bitrix\Crm\Integration\DocumentGenerator\Value\Address поддерживают модификаторы формата, разделителя и типа адреса. Модификаторы влияют на значение в виде массива. Строковый адрес класс возвращает без изменений.

|

|| Модификатор | Значение | Результат || || Format | 1 | Европейский формат EU || || Format | 2 | Формат Великобритании UK || || Format | 3 | Формат США USA || || Format | 4 | Российский формат RUS || || Format | 5 | Российский формат RUS2 || || Format | 6 | Формат Узбекистана UZ || || Separator | 1 | Запятая и пробел || || Separator | 2 | Перевод строки || || Separator | 3 | HTML-разделитель <br /> || || ShowType | Y | Добавляет тип адреса в скобках, если он заполнен || |#

Без модификатора Format класс выбирает формат по региональным настройкам контекста генерации. Разделитель по умолчанию — запятая и пробел.

{SOURCE.CLIENT.ADDRESS~Format=4,Separator=2,ShowType=Y}

Деньги CRM

Поля класса Bitrix\Crm\Integration\DocumentGenerator\Value\Money по умолчанию используют базовую валюту CRM.

|

|| Модификатор | Значение | Результат || || CurId | Код валюты | Форматирует сумму в выбранной валюте || || WZ | Y | Сохраняет незначащие нули дробной части || || NS | Y | Не добавляет обозначение валюты || || W | Y | Преобразует сумму в слова, если доступна функция Number2Word_Rus || |#

Если преобразование в слова недоступно или вернуло пустой результат, класс форматирует сумму числом.

{SOURCE.OPPORTUNITY~WZ=Y,NS=Y}
{SOURCE.OPPORTUNITY~CurId=RUB,W=Y}

Обработать пустые и обязательные поля

Результат для пустого значения зависит от настройки и типа поля.

|

|| Условие | Результат || || Плейсхолдер отсутствует в рассчитанных значениях | Body заменяет его пустой строкой || || Значение текстового плейсхолдера равно null или пустой строке | В документ попадает пустая строка || || Поле имеет REQUIRED=Y и возвращает пустое значение | Document::checkFields() включает поле в результат проверки, а обработка документа добавляет ошибку No value for required placeholder ... || || Множественное поле не содержит подходящих элементов | Value\Multiple возвращает пустую строку || || Поле типа IMAGE или STAMP содержит пустое значение либо один пробел | Body\Docx удаляет изображение-заглушку || || Изображение, печать или множественное поле содержит null либо пустую строку и имеет HIDE_ROW=Y | Body\Docx удаляет строку таблицы или ближайший абзац || |#

Проверьте обязательные значения без сохранения файла. Передайте в Document::createByTemplate() идентификатор или объект того типа, который ожидает основной провайдер.

use Bitrix\DocumentGenerator\Document;

$sourceId = 25;
// Замените идентификатором или объектом того типа, который ожидает провайдер
$document = Document::createByTemplate($template, $sourceId);
if ($document === null)
{
    throw new \RuntimeException('Не удалось создать объект документа');
}

$emptyRequiredFields = $document->checkFields();
foreach ($emptyRequiredFields as $placeholder => $field)
{
    $title = $field['TITLE'] ?? $placeholder;
    echo $placeholder . ': ' . $title . PHP_EOL;
}

Пустой массив $emptyRequiredFields означает, что метод не нашел пропущенных обязательных значений. После проверки выполните пробную генерацию. Порядок сохранения файла и обработки объекта Result описан в разделе «Создать и сохранить документ» статьи Документы.

Повторить блок для списка объектов

Для множественного провайдера можно повторить несколько абзацев или строк таблицы. Поместите начало и конец блока в отдельные плейсхолдеры с общим кодом списка.

{SOURCE.PRODUCTS.BLOCK_START}
{SOURCE.PRODUCTS.NAME} — {SOURCE.PRODUCTS.PRICE}
{SOURCE.PRODUCTS.BLOCK_END}

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

Размещайте начало и конец блока не дальше 20 соседних абзацев или других XML-узлов друг от друга. Если конец не найден в этом диапазоне, модуль не создает повторяемый блок.

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

Не вкладывайте блок одного множественного провайдера в другой без отдельной проверки результата. Порядок обхода и структура XML могут дать лишние или потерянные строки.

Вставить изображение или печать

Для типов IMAGE и STAMP одного текстового плейсхолдера недостаточно. Добавьте в DOCX изображение-заглушку и запишите плейсхолдер в альтернативный текст или имя этого изображения. Класс Body\Docx найдет такую фигуру и заменит связанный файл, сохранив размещение изображения в документе.

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

Поле STAMP обрабатывается как изображение, но зависит от настройки шаблона WITH_STAMPS. При значении N документ передает для всех полей STAMP внутренний маркер — строку из одного пробела. Класс Body\Docx удаляет изображение с таким значением, но HIDE_ROW не удаляет содержащую его строку или абзац. При значении Y модуль использует данные провайдера.

Учесть региональные настройки

Свойство шаблона REGION участвует в создании контекста генерации. Класс DataProviderManager выбирает по нему язык региональных фраз и настройки форматов дат и имен.

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

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

Выбрать вариант таблицы товаров

Настройка PRODUCTS_TABLE_VARIANT передается из шаблона в создаваемый документ. Она принимает одно из трех значений:

|

|| Значение | Результат || || Пустая строка | Все позиции || || Dictionary\ProductVariant::GOODS | Только товары || || Dictionary\ProductVariant::SERVICE | Только услуги || |#

Настройка влияет на данные, которые предоставляет интеграционный провайдер товаров. Сам Body\Docx не определяет, является ли позиция товаром или услугой. Если собственный провайдер не учитывает вариант, фильтрацию нужно реализовать в нем.

Проверить шаблон перед генерацией

Проверьте шаблон перед созданием документа с помощью Document::createByTemplate().

  1. Проверьте права пользователя на настройку шаблона и чтение исходного объекта: метод Template::loadById() эти права не проверяет. Подробнее читайте в статье Права доступа.

  2. Убедитесь, что Template::loadById() вернул объект.

  3. Проверьте, что getSourceType() возвращает ожидаемый класс основного провайдера.

  4. Убедитесь, что getBody() вернул объект, а тело поддерживает обработку файла.

  5. Проверьте, что каждый код из getPlaceholders() имеет описание в getFields().

  6. Убедитесь, что обязательные поля имеют источник данных.

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

  8. Убедитесь, что маркеры повторяемого блока имеют одинаковый префикс и расположены рядом.

  9. Проверьте, что регион и вариант таблицы товаров соответствуют сценарию документа.

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

Связанные материалы