Встраивание документов в интерфейс

Для внешнего получателя используйте публичную ссылку на документ. В авторизованном интерфейсе получайте документ через PHP API модуля documentgenerator и передавайте подготовленные данные в собственный компонент.

Стандартные компоненты модуля — внутренние. Не подключайте их в своих доработках. Для встраивания используйте API и собственный компонент.

Выбрать способ встраивания

Способ зависит от пользователя, задачи и требуемого уровня доступа.

Задача

Способ

Что проверить

Показать документ внешнему получателю

Включить публичную ссылку методом Document::enablePublicUrl() и получить ее через Document::getPublicUrl()

Право на публикацию, актуальность документа и возможность отозвать ссылку

Показать документ авторизованному пользователю

Создать собственный компонент в /local/components/, получить документ через PHP API и передать ссылки в шаблон компонента

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

Добавить действие в интерфейс другого модуля

Разместить кнопку или ссылку в точке расширения этого модуля, а генерацию и проверку прав выполнить на сервере

Правила расширения исходного модуля, защита запроса и обработка Result

Компонент отвечает за подготовку данных для интерфейса и вывод. Создание документа, получение файлов и проверку доступа выполняйте через классы модуля. Общие правила размещения, именования и подключения пользовательских компонентов приведены в статье Компоненты.

Открыть документ по публичной ссылке

Публичная ссылка позволяет открыть документ без учетной записи в продукте. Метод Document::getPublicUrl() возвращает готовый URL для передачи внешнему получателю.

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

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

Проверить публичный просмотр

Проверьте весь жизненный цикл ссылки.

  1. Сформируйте и сохраните документ.

  2. Проверьте право текущего пользователя на исходный объект и операцию публикации.

  3. Включите публичную ссылку и убедитесь, что getPublicUrl() вернул URL.

  4. Откройте URL в браузере без авторизации и проверьте доступность ожидаемого файла.

  5. Отключите ссылку через enablePublicUrl(false) и убедитесь, что прежний URL больше не открывает документ.

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

Встроить документ в авторизованный интерфейс

Для собственного раздела создайте компонент в пространстве имен приложения внутри /local/components/. Компонент должен получать только необходимые идентификаторы, проверять доступ на сервере и передавать в шаблон подготовленные данные.

Подготовить входные параметры

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

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

Проверить два уровня доступа

До получения файла выполните две независимые проверки:

  • Driver::getInstance()->getUserPermissions($userId)->canViewDocuments() проверяет разрешение пользователя на просмотр документов модуля.

  • Document::hasAccess($userId) проверяет доступ пользователя к исходным данным через провайдер документа.

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

Подробнее о разделении разрешений читайте в статье Права доступа.

Получить данные для шаблона

Загрузите документ методом Document::loadById(). Для сохраненного документа вызовите getFile(false), чтобы получить текущие ссылки без постановки новой задачи преобразования.

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

  • downloadUrl — ссылка на исходный файл,

  • pdfUrl — ссылка на PDF, если преобразование завершено,

  • imageUrl — ссылка на изображение, если оно создано,

  • printUrl — маршрут представления для печати, если PDF готов,

  • идентификатор и безопасное название документа.

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

Реализовать логику компонента

Создайте компонент приложения, например /local/components/mycompany/document.view/class.php. Замените mycompany на пространство имен своего проекта.

Пример. Компонент получает идентификатор документа, проверяет оба уровня доступа и передает текущие ссылки в собственный шаблон.

<?php

use Bitrix\DocumentGenerator\Document;
use Bitrix\DocumentGenerator\Driver;
use Bitrix\Main\Engine\CurrentUser;
use Bitrix\Main\Loader;

if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
{
    die();
}

class MyCompanyDocumentViewComponent extends CBitrixComponent
{
    public function executeComponent(): void
    {
        // Проверяем, что API модуля доступен
        if (!Loader::includeModule('documentgenerator'))
        {
            ShowError('Модуль documentgenerator не установлен');

            return;
        }

        // Получаем входной идентификатор и текущего пользователя
        $documentId = (int)($this->arParams['DOCUMENT_ID'] ?? 0);
        $userId = (int)CurrentUser::get()->getId();

        if ($documentId <= 0)
        {
            ShowError('Не передан идентификатор документа');

            return;
        }

        // Проверяем разрешение модуля до загрузки документа
        $permissions = Driver::getInstance()->getUserPermissions($userId);

        if (!$permissions->canViewDocuments())
        {
            ShowError('Нет разрешения на просмотр документов');

            return;
        }

        // Не различаем отсутствующий документ и отказ провайдера в тексте ошибки
        $document = Document::loadById($documentId);

        if ($document === null || !$document->hasAccess($userId))
        {
            ShowError('Документ не найден или недоступен');

            return;
        }

        // Получаем только готовые ссылки без запуска преобразования
        $result = $document->getFile(false);

        if (!$result->isSuccess())
        {
            ShowError(implode('; ', $result->getErrorMessages()));

            return;
        }

        $data = $result->getData();

        // Передаем в шаблон минимальный набор данных
        $this->arResult = [
            'ID' => (int)$document->ID,
            'TITLE' => $document->getTitle(),
            'DOWNLOAD_URL' => (string)($data['downloadUrl'] ?? ''),
            'PDF_URL' => (string)($data['pdfUrl'] ?? ''),
            'IMAGE_URL' => (string)($data['imageUrl'] ?? ''),
            'PRINT_URL' => (string)($data['printUrl'] ?? ''),
        ];

        $this->includeComponentTemplate();
    }
}

Код объединяет отсутствующий документ и отказ в доступе в одно сообщение. Такой ответ не раскрывает пользователю наличие чужого документа. Если исходный модуль требует дополнительной проверки объекта, выполните ее до Document::loadById().

Компонент не использует общий кеш. Ссылки и результат проверки прав зависят от пользователя и текущего состояния документа. Если интерфейсу нужен кеш, не сохраняйте в общем кеше результат hasAccess() и URL файлов. Повторно проверяйте права и получайте ссылки для каждого запроса.

Подготовить шаблон компонента

Шаблон пользовательского компонента должен работать только с подготовленным $arResult. Экранируйте название документа и другой текст перед выводом. Для URL используйте значения, которые вернул API модуля, и не собирайте пути из FILE_ID, идентификатора документа или имени файла.

Показывайте действие только при наличии соответствующей ссылки. Например, не выводите кнопку PDF, если ключ pdfUrl отсутствует. Ошибки загрузки, доступа и чтения файла показывайте раздельно, чтобы пользователь понимал следующий шаг.

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

Проверить авторизованный интерфейс

Проверьте компонент в нескольких состояниях:

  1. Документ существует, пользователь может просматривать документы и имеет доступ к исходным данным.

  2. Документ не найден или идентификатор некорректен.

  3. У пользователя нет разрешения canViewDocuments().

  4. Провайдер отклоняет доступ к исходному объекту.

  5. Исходный файл доступен, но PDF и изображение еще не созданы.

  6. Хранилище вернуло ошибку чтения файла.

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

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

Добавить действие в интерфейс другого модуля

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

Обработчик должен:

  1. Проверить сессию или другой механизм защиты запроса.

  2. Проверить право пользователя на исходный объект и операцию с документом.

  3. Загрузить шаблон или документ через PHP API.

  4. Выполнить операцию и проверить Result.

  5. Вернуть интерфейсу только нужные данные или безопасный URL.

Типичные ошибки

Ошибка

Признак

Решение

Проверка только одного уровня прав

Код проверяет только разрешение модуля или только доступ провайдера

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

Формирование ссылок вручную

Код собирает адрес из идентификатора документа или имени файла

Получайте ссылки из данных успешного Result или через Document::getPublicUrl()

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