Pular para o conteúdo

O modelo de pipeline

Spec: ISO 32000-2, §7.5 Evidence: Code-backed

Um documento do NextPDF não é produzido em uma única etapa opaca. Ele percorre um pequeno número de estágios explícitos: uma fachada que registra a intenção, uma camada de conteúdo que transforma a intenção em um modelo e um escritor que serializa esse modelo em um PDF em conformidade. Esta página explica esse formato e por que ele é o formato certo para o motor.

O próprio formato de arquivo PDF é uma estrutura em camadas — um cabeçalho, um corpo de objetos, uma tabela de referência cruzada e um trailer — e um escritor precisa montar tudo isso de forma consistente. Se o motor que o constrói for um único procedimento emaranhado, cada mudança colocará toda saída em risco. A única forma de ganhar confiança passa a ser renderizar documentos inteiros e inspecioná-los a olho, o que é lento, tardio e pouco convincente.

Um pipeline explícito inverte essa situação. Cada estágio tem uma única tarefa e um limite tipado, de modo que você pode raciocinar sobre uma mudança e testá-la no estágio que ela afeta, não apenas no final do arquivo. A arquitetura é, antes de tudo, uma decisão de testabilidade e extensibilidade.

  • O ponto de entrada público é uma fachada Document. Ela é um construtor fluente, de uso único e seguro para workers, que registra o que você quer, não como isso é serializado.
  • A fachada delega a cerca de duas dúzias de traits de responsabilidade focados (saída de texto, desenho, páginas, segurança, navegação e assim por diante) — cada um com uma responsabilidade, em vez de uma única classe gigante.
  • O conteúdo chega por um de dois caminhos: desenho direto (primitivas gráficas) ou o motor HTML/CSS. Ambos produzem o mesmo modelo de documento interno.
  • Um escritor de PDF dedicado serializa esse modelo, escolhendo uma estratégia para PDF 1.4 / 1.7 / 2.0. A produção de uma estrutura de arquivo válida fica aqui e em nenhum outro lugar.
  • O estado de vida longa (os registros de fontes e imagens) tem escopo de processo e é compartilhado; o estado por requisição (o documento) é criado do zero e nunca reutilizado. O limite é explícito, e é isso que torna os runtimes de worker seguros.

A maneira mais clara de enxergar o modelo é acompanhar um documento da chamada até os bytes.

  1. Document facade Fluent, use-once builder; records intent via concern traits.
  2. Content production Direct drawing or the HTML/CSS engine — both build one document model.
  3. Document model Accumulated pages, content, and resources held as typed state.
  4. PDF writer Serialises the model; selects a PDF 1.4 / 1.7 / 2.0 strategy.
  5. Conforming PDF Header, object body, cross-reference table, trailer.
O percurso de um documento pelo NextPDF: cada estágio tem uma única responsabilidade e um limite tipado, de modo que pode ser raciocinado e testado de forma isolada.

Duas escolhas de projeto fazem disso mais do que um diagrama.

A fachada é composta, não monolítica. O Document não implementa cada recurso por conta própria; ele delega cada área a um trait de responsabilidade dedicado — saída de texto, desenho, páginas, segurança, tipografia, navegação, transações e assim por diante. Um novo método de documento pertence ao trait responsável por sua área, não à própria fachada. A classe que você chama continua pequena, e as responsabilidades continuam separadas.

O escritor é dono exclusivo da estrutura de arquivo. A produção de conteúdo decide quais marcas e objetos existem; o escritor decide como eles se tornam um arquivo PDF válido, inclusive qual estratégia de versão se aplica. Essa separação é imposta como uma regra arquitetural: o código de layout e de conteúdo não emite a estrutura final do arquivo, e o escritor não toma decisões de layout. O benefício é que “a saída é um PDF válido?” tem exatamente um lugar para ser testado.

O limite de tempo de vida faz parte do modelo, não é uma reflexão tardia. Os registros de fontes e imagens vivem durante toda a vida do processo e são compartilhados entre requisições; o documento, seu contexto de renderização e o escritor são criados por requisição e descartados. Em um runtime de worker, essa distinção é a diferença entre reutilização segura e corrupção entre requisições. Por isso, ela é declarada na arquitetura, não deixada à disciplina.

Esta página é Evidence: Code-backed . Os estágios mapeiam para a estrutura real no repositório do core:

  • A fachada e sua delegação estão em src/Core/Document.php, junto com os traits de responsabilidade em src/Core/Concerns/ (saída de texto, saída, desenho, páginas, segurança, tipografia, navegação, transações e mais — cada um com uma única responsabilidade).
  • Os dois caminhos de conteúdo são o motor HTML/CSS (src/Html/) e o desenho direto (src/Graphics/), ambos alimentando o modelo interno.
  • A serialização e a estratégia de versão do PDF vivem em src/Writer/ (PdfWriter.php, com classes de estratégia explícitas para PDF 1.4 / 1.7 / 2.0).
  • O limite entre tempo de vida do processo e por requisição é o desenho seguro para workers registrado na visão geral da arquitetura e exercitado pelo exemplo de worker-factory que acompanha o produto, que compartilha um FontRegistry e um ImageRegistry entre requisições enquanto cria cada Document do zero.

O destino é fixado pelo formato. A saída do escritor precisa ser um cabeçalho, um corpo de objetos, uma tabela de referência cruzada e um trailer, conforme Spec: ISO 32000-2, §7.5 . Concentrar essa obrigação em um único estágio é o que permite que o resto do motor permaneça focado no conteúdo, em vez da montagem da estrutura de arquivo.

A tarefa da fachada é fazer a intenção parecer intenção. O caminho de conteúdo e o escritor permanecem invisíveis no ponto de chamada:

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone(); // facade
$doc->setTitle('Quarterly Report'); // metadata concern
$doc->addPage(); // pages concern
$doc->setFont('helvetica', 'B', 16); // typography concern
$doc->cell(0, 12, 'Summary', newLine: true); // text-output concern
$doc->writeHtml('<p>Generated in-process.</p>'); // HTML content path
$doc->save(__DIR__ . '/report.pdf'); // writer stage

Cada chamada cai em uma responsabilidade diferente. Dois caminhos de conteúdo diferentes alimentam o mesmo modelo. Exatamente um estágio — save() — transforma o modelo em bytes de arquivo. Nada no ponto de chamada precisa saber como a tabela de referência cruzada é construída.

A leitura equivocada mais comum é achar que “pipeline” implica uma API de streaming por push, conectada estágio a estágio, como um pipe do Unix. Não é o caso. Aqui, o pipeline é uma decomposição arquitetural: estágios com responsabilidades únicas e limites tipados. Você continua programando contra uma fachada fluente. Os estágios são a forma como o motor é construído e testado, não um transporte que você monta à mão.

Um erro relacionado é supor que a fachada é o motor. Ela é o ponto de entrada. O trabalho real é distribuído entre os traits de responsabilidade, os dois caminhos de conteúdo e um escritor. Essa distribuição é justamente o motivo pelo qual a mudança de um recurso não põe toda saída em risco.

Esta página descreve o formato do pipeline, não a API interna de qualquer estágio isolado. O inventário exato de traits de responsabilidade, as regras de seleção da estratégia do escritor e os campos do modelo de conteúdo são definidos pelo código e pela referência, não por esta explicação. A contagem exata de traits é um detalhe de implementação que pode mudar sem mudar o modelo. Esta página não cobre os estágios internos do motor HTML (um tópico à parte) nem o comportamento de streaming e de memória do escritor (também à parte). As afirmações estruturais são precisas na data de revisão desta página; a fonte autoritativa é o src/Core/, src/Html/, src/Graphics/ e src/Writer/ do repositório do core.

O modelo de pipeline é idêntico entre todas as edições; as edições adicionam capacidades dentro dos estágios, não novos estágios:

Pipeline model — edition availability
Edition Availability
Core O Core implementa o pipeline completo de fachada → conteúdo → escritor.
Pro O Pro adiciona capacidades dentro dos estágios existentes, não novos estágios.
Enterprise O Enterprise adiciona capacidades dentro dos estágios existentes, não novos estágios.
  • Fachada — o ponto de entrada público Document: um construtor fluente, de uso único, que registra a intenção e delega aos traits de responsabilidade.
  • Trait de responsabilidade — um trait PHP focado que a fachada compõe, cada um dono de uma única área de recurso (saída de texto, desenho, páginas, segurança e assim por diante).
  • Caminho de conteúdo — uma das duas maneiras pelas quais o conteúdo entra no modelo: desenho direto ou o motor HTML/CSS.
  • Modelo de documento — o acúmulo interno e tipado do motor de páginas, conteúdo e recursos antes da serialização.
  • Estágio do escritor — o componente que serializa o modelo em um PDF válido, selecionando uma estratégia para PDF 1.4 / 1.7 / 2.0.
  • Seguro para workers — projetado para que o estado de tempo de vida do processo seja compartilhado com segurança, enquanto o estado por requisição é criado do zero e nunca reutilizado.