Pular para o conteúdo

Contracts / Document

O domínio de documentos reúne os contratos que você usa para gerar saída em Portable Document Format (PDF): PdfDocumentInterface para o conteúdo, DocumentFactoryInterface para criação segura em workers, os contratos de registro de fontes e imagens e os três enums de entrega e layout. Todos estão stable desde a versão 1.0.0 ou 1.7.0.

Terminal window
composer require nextpdf/core:^3

PdfDocumentInterface é a principal superfície da API (application programming interface). Ela define o gerenciamento de páginas, a seleção de fontes, o layout de texto em célula e multicélula, a renderização de Hypertext Markup Language (HTML), a incorporação de imagens e a saída final. Cada método retorna static, então você pode encadear chamadas. Document::createStandalone() retorna uma instância concreta que satisfaz a interface. Use a interface como type hint nos seus próprios serviços para manter substituíveis os componentes internos do engine.

A criação de documentos segue dois caminhos. Em uma requisição tradicional de PHP FastCGI Process Manager (PHP-FPM), createStandalone() monta um documento autocontido com registros privados. Workers de longa duração, incluindo RoadRunner, Swoole e Laravel Octane, usam o outro caminho. Nesse caminho, DocumentFactoryInterface::create() retorna um Document novo e descartável. O documento lê a partir dos registros com ciclo de vida do processo, mas nunca os modifica. A factory mantém os singletons de FontRegistryInterface e ImageRegistryInterface. Cada documento recebe seu próprio contexto de renderização e seu próprio writer. Isso isola as falhas: um documento não pode corromper o estado compartilhado de que outro documento depende.

Os contratos de registro mantêm os workers rápidos. FontRegistryInterface analisa um arquivo de fonte uma única vez e mantém os metadados analisados em cache durante todo o ciclo de vida do processo. Você pode bloqueá-lo após o warmup para impedir que o tráfego de produção o modifique. ImageRegistryInterface armazena em cache os dados binários decodificados da imagem sob uma política least-recently-used limitada. Os metadados da imagem permanecem residentes mesmo depois que o binário é removido. Ambos os registros expõem memoryUsage() para planejamento de capacidade. ImageRegistryInterface estende ResettableService, que remove os dados em cache sem destruir os metadados estruturais. Um worker pode descartar os caches de imagem quando houver pressão de memória e continuar atendendo.

Três enums completam o domínio. OutputDestination seleciona exibição inline, download forçado, gravação no sistema de arquivos ou retorno de string bruta. Orientation seleciona retrato ou paisagem. Alignment seleciona texto à esquerda, centralizado, à direita ou justificado. Cada enum usa o código legado do TCPDF como valor do enum, então a ponte compat-tcpdf faz o mapeamento de forma limpa. O compromisso de compatibilidade retroativa para esses enums é aditivo. Nenhum case é removido. Novos cases podem ser adicionados em uma versão minor.

TipoCategoriaMembros principaisEstabilidadeDesde
PdfDocumentInterfaceinterfaceaddPage(), setMargins(), setFont(), cell(), multiCell(), writeHtml(), image(), output(), save()stable1.0.0
DocumentFactoryInterfaceinterfacecreate(?Config): Documentstable1.7.0
ResettableServiceinterfacereset(): voidstable1.7.0
FontRegistryInterfaceinterfaceregister(), get(), warmup(), lock(), isLocked(), registerFromBinary(), memoryUsage()stable1.7.0
ImageRegistryInterfaceinterfaceload(), loadFromString(), getMetadata(), memoryUsage() (estende 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

A página de tipografia documenta FontRegistryInterface e ImageRegistryInterface de forma completa. Esta página aborda o papel deles no ciclo de vida de criação.

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 é o builder imutável. Cada chamada with*() retorna uma nova instância. Internamente, ela compõe um DocumentFactoryInterface, então o modelo de registros para workers descrito na visão geral se aplica sem configuração adicional.

  • createStandalone() monta registros privados. Em um loop de worker, isso reanalisa cada fonte a cada requisição. Em vez disso, use DocumentFactoryInterface com registros compartilhados.
  • Um Document é descartável por design. Reutilizar uma instância entre documentos lógicos faz o estado vazar. Chame create() para cada documento e deixe o garbage collection recuperá-lo.
  • FontRegistryInterface::lock() faz com que register(), addFontDirectory() e warmup() lancem LogicException. Bloqueie após o warmup, nunca durante o tratamento de requisições.
  • OutputDestination::File grava no sistema de arquivos do servidor e retorna os bytes brutos. save() é o caminho de arquivo explícito. Não misture os dois para o mesmo documento.
  • cell() aceita bool|string no argumento de borda para compatibilidade com o TCPDF. Uma string vazia não é a mesma coisa que false. Passe o valor tipado que você realmente quer.

Os registros de fontes e imagens tornam o domínio de documentos um sistema limitado pela memória, não por requisições. O custo predominante é a análise de fontes na primeira requisição. O performance_budget é de 1500 ms de wall time e 64 MB de pico em três documentos no exemplo de worker. Quase todo esse orçamento vem da primeira análise de fonte. Após o warmup, o trabalho atribuível ao contrato por documento é O(1): uma consulta ao registro e uma alocação de contexto. memoryUsage() em qualquer um dos registros retorna um MemoryReport para planejamento de capacidade em tempo real. ResettableService::reset() limita o pico de memória sob carga sustentada.

Os contratos de documento não expõem superfície criptográfica, mas dois riscos operacionais se aplicam. Primeiro, image() aceita um caminho ou um Uniform Resource Locator (URL). Em cenários de entrada não confiável, restrinja a busca remota por meio de ExternalResourcePolicyInterface (consulte a página de política de segurança) em vez de passar diretamente URLs controladas pelo usuário. Segundo, writeHtml() é o ponto de entrada do pipeline de HTML. Marcação não confiável deve passar por um HtmlSecurityPolicyInterface antes da renderização. A própria camada de documento não faz sanitização. Esse trabalho pertence ao domínio de política de segurança e, por ser um contrato, você pode fornecer uma política mais rígida sem precisar fazer fork.

Os contratos de documento implementam a estrutura de documento do PDF 2.0 conforme definido na ISO 32000-2. O tratamento de saída, páginas e fontes produz objetos indiretos e um stream de referência cruzada conforme a ISO 32000-2 §7. A camada writer emite conteúdo de acordo com o contrato da camada de engine, architecture decision record (ADR-010). Esta página não faz nenhuma afirmação em nível de cláusula além da conformidade estrutural. As páginas de extração e acessibilidade documentam a conformidade com PDF/A e PDF/UA e incluem as tabelas normativas.