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

Contracts / Документ

Домен документа включает контракты, с помощью которых вы формируете вывод в Portable Document Format (PDF): PdfDocumentInterface для содержимого, DocumentFactoryInterface для безопасного для воркеров создания, контракты реестров шрифтов и изображений, а также три перечисления для доставки и макета. Все они имеют статус stable с 1.0.0 или 1.7.0.

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

PdfDocumentInterface — основная поверхность API. Он определяет управление страницами, выбор шрифта, размещение текста в ячейках и многострочных ячейках, отрисовку Hypertext Markup Language (HTML), встраивание изображений и итоговый вывод. Каждый метод возвращает static, поэтому вы можете объединять вызовы в цепочку. Document::createStandalone() возвращает конкретный экземпляр, соответствующий интерфейсу. Типизируйте свои сервисы этим интерфейсом, чтобы внутренние компоненты движка оставались заменяемыми.

Есть два пути создания документа. В классическом запросе PHP FastCGI Process Manager (PHP-FPM) createStandalone() создает самодостаточный документ с приватными реестрами. Долгоживущие воркеры, включая RoadRunner, Swoole и Laravel Octane, используют другой путь. Там DocumentFactoryInterface::create() возвращает новый одноразовый Document. Документ читает реестры уровня процесса, но никогда их не изменяет. Фабрика держит синглтоны FontRegistryInterface и ImageRegistryInterface. Каждый документ получает собственный контекст отрисовки и писатель. Это изолирует сбои: один документ не может повредить общее состояние, от которого зависит другой документ.

Контракты реестров поддерживают производительность воркеров. FontRegistryInterface разбирает файл шрифта один раз и кэширует разобранные метаданные на время жизни процесса. Вы можете заблокировать реестр после прогрева, чтобы рабочий трафик не мог его изменить. ImageRegistryInterface кэширует декодированные двоичные данные изображений по ограниченной политике вытеснения наименее недавно использованных (LRU). Метаданные изображений остаются в памяти даже после вытеснения двоичных данных. Оба реестра предоставляют memoryUsage() для планирования ёмкости. ImageRegistryInterface расширяет ResettableService, который вытесняет кэшированные данные, не разрушая структурные метаданные. При нехватке памяти воркер может сбросить кэши изображений и продолжать обслуживание.

Домен дополняют три перечисления. OutputDestination выбирает встроенный показ, принудительную загрузку, запись в файловую систему или возврат строки как есть. Orientation выбирает книжную или альбомную ориентацию. Alignment выбирает выравнивание текста по левому краю, по центру, по правому краю или по ширине. Каждое перечисление использует устаревший код TCPDF как своё значение, поэтому мост compat-tcpdf сопоставляет их без коллизий. Обещание обратной совместимости для этих перечислений аддитивно. Ни один вариант не удаляется. Новые варианты могут появиться в минорном выпуске.

ТипВидКлючевые членыСтабильностьС версии
PdfDocumentInterfaceинтерфейсaddPage(), setMargins(), setFont(), cell(), multiCell(), writeHtml(), image(), output(), save()stable1.0.0
DocumentFactoryInterfaceинтерфейсcreate(?Config): Documentstable1.7.0
ResettableServiceинтерфейсreset(): voidstable1.7.0
FontRegistryInterfaceинтерфейсregister(), get(), warmup(), lock(), isLocked(), registerFromBinary(), memoryUsage()stable1.7.0
ImageRegistryInterfaceинтерфейсload(), loadFromString(), getMetadata(), memoryUsage() (расширяет ResettableService)stable2.0.0
OutputDestinationenum (string)Inline, Download, File, Stringstable1.0.0
Orientationenum (string)Portrait, Landscapestable1.0.0
Alignmentenum (string)Left, Center, Right, Justifystable1.0.0

Страница типографики полностью документирует FontRegistryInterface и ImageRegistryInterface. Эта страница описывает их роль в жизненном цикле создания.

examples/01-hello-world.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Hello World');
$doc->addPage();
$doc->setFont('helvetica', '', 24);
$doc->cell(0, 15, 'Hello, NextPDF!', newLine: true);
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'This is a minimal PDF generated with NextPDF.', newLine: true);
$doc->save(__DIR__ . '/output/01-hello-world.pdf');
examples/02-pdf-factory.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\PdfFactory;
use NextPDF\ValueObjects\{Margin, PageSize};
$factory = PdfFactory::new()
->withPageSize(PageSize::A4())
->withMargins(new Margin(15.0, 15.0, 15.0, 15.0))
->withCompress(true)
->withLang('en');
// The same configured factory creates independent documents.
$doc = $factory->create();
$doc->setTitle('PdfFactory Example');
$doc->setAuthor('NextPDF');
$doc->addPage();
$doc->setFont('helvetica', '', 16);
$doc->cell(0, 12, 'Created via PdfFactory', newLine: true);
$doc2 = $factory->create();
$doc2->addPage();
$doc2->setFont('helvetica', '', 12);
$doc2->cell(0, 10, 'Second document from the same factory.');
$doc->save(__DIR__ . '/output/02-pdf-factory.pdf');

PdfFactory — неизменяемый строитель. Каждый вызов with*() возвращает новый экземпляр. Внутри он компонует DocumentFactoryInterface, поэтому модель реестров для воркеров из обзора применяется без дополнительной настройки.

  • createStandalone() создает приватные реестры. В цикле воркера из-за этого каждый шрифт разбирается заново при каждом запросе. Вместо этого используйте DocumentFactoryInterface с общими реестрами.
  • Объект Document по конструкции одноразовый. Повторное использование одного экземпляра для разных логических документов приводит к утечке состояния. Вызывайте create() для каждого документа и позвольте сборщику мусора освободить его.
  • FontRegistryInterface::lock() приводит к тому, что register(), addFontDirectory() и warmup() выбрасывают LogicException. Блокируйте после прогрева, никогда во время обработки запроса.
  • OutputDestination::File записывает в файловую систему сервера и возвращает байты как есть. save() — это явный путь к файлу. Не смешивайте эти два варианта для одного документа.
  • cell() ради совместимости с TCPDF принимает bool|string для аргумента границы. Пустая строка — это не то же самое, что false. Передавайте именно то типизированное значение, которое имеете в виду.

Реестры шрифтов и изображений делают домен документа системой с ограничением по памяти, а не системой уровня отдельного запроса. Основная стоимость приходится на разбор шрифта при первом запросе. performance_budget составляет 1500 мс стенового времени и 64 МБ пикового потребления на три документа в примере с воркером. Почти весь этот бюджет уходит на первый разбор шрифта. После прогрева работа, относимая к контракту, на каждый документ остается O(1): поиск в реестре и выделение контекста. memoryUsage() на любом из реестров возвращает MemoryReport для оперативного планирования ёмкости. ResettableService::reset() ограничивает пиковую память при устойчивой нагрузке.

Контракты документа не несут криптографической поверхности, но остаются два эксплуатационных риска. Во-первых, image() принимает путь или единообразный указатель ресурса (URL). Если входные данные недоверенные, ограничивайте удалённую загрузку через ExternalResourcePolicyInterface (см. страницу политики безопасности), а не передавайте напрямую URL, которые контролирует пользователь. Во-вторых, writeHtml() — это точка входа в конвейер HTML. Недоверенная разметка должна пройти через HtmlSecurityPolicyInterface перед отрисовкой. Слой документа сам не выполняет санитизацию. Это задача домена политики безопасности, и, поскольку это контракт, вы можете предоставить более строгую политику без форка.

Контракты документа реализуют структуру документа PDF 2.0, как она определена в ISO 32000-2. Обработка вывода, страниц и шрифтов создает косвенные объекты и поток перекрёстных ссылок согласно ISO 32000-2 §7. Слой писателя выдает содержимое согласно контракту слоя движка и записи об архитектурном решении (ADR-010). Эта страница не заявляет никаких притязаний на уровне пунктов сверх структурного соответствия. Страницы извлечения и доступности документируют соответствие PDF/A и PDF/UA и содержат нормативные таблицы.