Перейти к содержимому

Навигация: аннотации, ссылки, закладки, действия и вложения

Модуль Navigation формирует интерактивный слой формата Portable Document Format (PDF). Он охватывает аннотации, ссылочные аннотации и Uniform Resource Locator (URL), структуру документа (закладки), оглавление, действия и цепочки триггеров, переходы между страницами, а также встроенные файлы-вложения и их связи ассоциированных файлов.

Окно терминала
composer require nextpdf/core:^3

ISO 32000-2 §12 определяет интерактивные возможности PDF-документа: аннотации, действия, точки назначения и структуру документа. Этот модуль кодирует этот слой для движка. Менеджеры собирают намерения, а объекты-значения несут данные, которые эти менеджеры выдают.

AnnotationManager — самая общая точка входа. Он добавляет текстовые аннотации, аннотации свободного текста, линии, квадраты, окружности, многоугольники, ломаные линии, рукописные аннотации, а также аннотации разметки текста (выделение и подчёркивание). Он защищён от враждебного ввода: неизвестный подтип аннотации заменяется безопасным значением по умолчанию, имя значка, которое не является допустимым токеном имени PDF, заменяется, а QuadPoints для разметки текста должны передаваться наборами, кратными восьми числам с плавающей точкой; иначе они отбрасываются. Эти проверки защищают от PDF-инъекций, а не служат удобной валидацией. LinkManager обрабатывает внутренние ссылки, именованные точки назначения и аннотации URL. Он заранее выделяет объекты аннотаций, чтобы Writer мог ссылаться на них до сериализации.

BookmarkManager и TocBuilder формируют навигационную иерархию. Структура документа — это дерево закладок, которое программа просмотра показывает на боковой панели. TocBuilder отрисовывает оглавление на странице и может использовать FontMetrics для расчёта макета leader/width. OutlineAutoGenerator формирует навигационную структуру на основе структуры документа.

Иерархия Action в пространстве имён NextPDF\Navigation\Action моделирует поведение, управляемое триггерами: GoTo (удалённый и встроенный), launch, named, hide, reset/submit формы и установку состояния необязательного содержимого. Реализация действия воспроизведения экранной аннотации из §13 отложена; это будущая работа, сейчас такое действие не подключено. Не полагайтесь на него как на поддерживаемое действие. Action::withNext() строит цепочку действий, которая выполняется для одного события-триггера. PageTransition моделирует переход в режиме презентации. FileAttachment встраивает файл по пути или из байтовой строки и помечает его значением AFRelationship (перечисление связи ассоциированного файла). Метод возвращает FileAttachmentResult; запись выполняется через writeAttachments(). Основные менеджеры доступны @since 1.0.0. Иерархия действий доступна @since 2.1.0. Конструктор FileAttachment и AFRelationship появились в @since 1.8.0 / @since 1.1.0.

КлассКлючевые членыРоль
AnnotationManageraddAnnotation(), addFreeText(), addLine(), addSquare(), addCircle(), addPolygon(), addInk(), addHighlight(), addUnderline()Построитель аннотаций с защищёнными от инъекций входными данными (@since 1.0.0)
LinkManageraddLink(), setLink(), setDestination(), addLinkAnnotation(), addUrlAnnotation(), preallocateAnnotationObjects()Внутренние ссылки, именованные точки назначения, аннотации URL (@since 1.0.0)
BookmarkManageraddBookmark(), hasBookmarks(), write()Дерево структуры документа (закладок) (@since 1.0.0)
TocBuilderaddEntry(), hasEntries(), render(), getEntries()Оглавление на странице (@since 1.0.0)
Action (интерфейс)subtype(), toDictionary(), withNext(), nextChain()Действие-триггер + цепочка действий (@since 2.1.0)
PageTransitiontoDict(), toInlineDict()Переход между страницами в режиме презентации (@since 1.2.0)
FileAttachmentembedFile(), embedFileFromString(), hasAttachments(), getCount(), writeAttachments()Встроенные файлы-вложения (@since 1.0.0)
AFRelationship (перечисление)toPdfName()Связь ассоциированного файла (@since 1.1.0)
AnnotationFlagswith(), without(), has(), toInt()Неизменяемый набор флагов аннотации (@since 1.2.0)

Запустите composer docs:generate-api-php -- --module=Navigation, чтобы сгенерировать полную таблицу PHPDoc.

examples/12-bookmarks-and-toc.php строит структуру документа через высокоуровневый фасад поверх BookmarkManager. Чтобы использовать менеджер напрямую:

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Navigation\BookmarkManager;
$bookmarks = new BookmarkManager();
$bookmarks->addBookmark(title: 'Chapter 1', level: 0, pageIndex: 0);
$bookmarks->addBookmark(title: '1.1 Overview', level: 1, pageIndex: 0);
$bookmarks->addBookmark(title: 'Chapter 2', level: 0, pageIndex: 4);
if ($bookmarks->hasBookmarks()) {
// The Writer calls $bookmarks->write(...) during catalog serialization.
}

Встройте вложение с явно заданной связью ассоциированного файла, затем проверьте результат перед завершением формирования документа.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Navigation\AFRelationship;
use NextPDF\Navigation\FileAttachment;
$attachments = new FileAttachment();
$attachments->embedFile(
path: '/srv/invoices/INV-2026-0042.xml',
description: 'Structured invoice source (Factur-X)',
afRelationship: AFRelationship::Source,
);
if ($attachments->hasAttachments()) {
// writeAttachments() is invoked by the Writer with a live ObjectRegistry;
// getCount() lets the application assert the expected attachment count.
assert($attachments->getCount() === 1);
}
  • AnnotationManager молча нормализует враждебный ввод: недопустимый подтип заменяется значением по умолчанию, значок, не являющийся PDF-именем, заменяется значком по умолчанию, а некорректные QuadPoints отбрасываются. Аннотация всё равно создаётся; проверяйте входные данные на стороне источника, если требуется строго сохранить их значения.
  • LinkManager::preallocateAnnotationObjects() нужно выполнить до того, как Writer сериализует ссылки, иначе цели ссылок останутся неразрешёнными.
  • Action::withNext() возвращает новое действие с присоединённой цепочкой; интерфейс поддерживает неизменяемое связывание в цепочку, а не изменение на месте.
  • FileAttachment::writeAttachments() требует действующего ObjectRegistry от Writer. Если вызвать его изолированно, менеджер накопит намерения, но ничего не запишет, пока им не управляет Writer.
  • AnnotationFlags — это неизменяемый набор флагов. with()/without() возвращают новый экземпляр; исходный остаётся без изменений.

Накопление аннотаций, ссылок и закладок имеет сложность O(n) по числу элементов и не выполняет перекомпоновку. Стоимость встраивания файла-вложения определяется размером встраиваемых байтов, а не накладными расходами менеджера. Эталонная нагрузка по умолчанию укладывается в бюджет 1500 мс времени / 64 МБ пиковой памяти. Профиль воспроизводимости — structural: номера объектов и значение /ID в трейлере различаются между запусками. Два документа с одинаковыми навигационными намерениями структурно равны, но не идентичны побайтово.

AnnotationManager рассматривает подтип аннотации, значок и QuadPoints как недоверенные. Он проверяет каждое значение по списку разрешённых или шаблону и заменяет недопустимое значение вместо того, чтобы записать его как есть. Это закрывает вектор инъекции PDF-имени. LinkManager::addUrlAnnotation() кодирует URL в ссылочное действие. URL остаётся границей доверия на стороне потребителя: враждебный URL по-прежнему может быть корректным, поэтому очищайте точки назначения перед их добавлением. FileAttachment встраивает произвольные байты. Ограничьте размер встраиваемых данных и рассматривайте любой источник вложения, предоставленный пользователем, как недоверенный. См. модель угроз движка в /modules/core/security/.

Структуры, формируемые этим модулем, соответствуют ISO 32000-2 §12 в части аннотаций, действий, точек назначения и иерархии структуры документа. Ссылки на разделы для отдельных возможностей (значки аннотаций §12.5.6.4, QuadPoints разметки текста §12.5.6.10, действия §12.6) документированы прямо в src/Navigation/ и проверяются в tests/Unit/Navigation/. Это факты реализации, а не утверждение о сквозном соответствии PDF 2.0. Соответствие на уровне всего документа проверяется оракулом и эталонными наборами, описанными в /modules/core/conformance/.