Salta ai contenuti

Contratti / Documento

Il dominio document riunisce i contratti su cui costruire i PDF: PdfDocumentInterface per i contenuti, DocumentFactoryInterface per la creazione thread-safe nei worker, i contratti dei registri di font e immagini e i tre enum per consegna e impaginazione. Tutti sono stable a partire dalla versione 1.0.0 o 1.7.0.

Terminal window
composer require nextpdf/core:^3

PdfDocumentInterface è la superficie API principale. Definisce la gestione delle pagine, la selezione dei font, l’impaginazione del testo in celle singole e multiple, il rendering HTML, l’incorporamento delle immagini e l’output finale. Ogni metodo restituisce static, quindi le chiamate possono essere concatenate. Document::createStandalone() restituisce un’istanza concreta che soddisfa l’interfaccia. Usare il type hint dell’interfaccia nei propri servizi: in questo modo le parti interne del motore restano sostituibili.

La creazione dei documenti segue due percorsi. In una richiesta PHP-FPM tradizionale, createStandalone() costruisce un documento autonomo con registri privati. Un worker a lunga esecuzione usa l’altro percorso. Rientrano in questo caso RoadRunner, Swoole e Laravel Octane. In questo scenario, DocumentFactoryInterface::create() restituisce un nuovo Document usa e getta. Il documento legge dai registri che vivono quanto il processo, ma non li modifica mai. La factory mantiene i singleton FontRegistryInterface e ImageRegistryInterface. Ogni documento ottiene il proprio contesto di rendering e il proprio writer. Questo realizza il contenimento dei guasti. Un documento non può corrompere lo stato condiviso da cui dipende un altro documento.

I contratti dei registri permettono a un worker di restare veloce. FontRegistryInterface analizza un file di font una sola volta e memorizza nella cache i metadati analizzati per l’intera durata del processo. Può essere bloccato dopo il warmup, in modo che il traffico di produzione non possa modificarlo. ImageRegistryInterface memorizza nella cache i dati binari delle immagini decodificate secondo un criterio LRU (Least Recently Used) con capacità limitata. I metadati delle immagini restano residenti anche dopo l’eliminazione dei dati binari. Entrambi espongono memoryUsage() per la pianificazione della capacità. ImageRegistryInterface estende ResettableService. Quel contratto elimina i dati memorizzati nella cache senza distruggere i metadati strutturali. Un worker può svuotare le cache delle immagini quando la memoria è sotto pressione e continuare a rispondere.

Tre enum completano il dominio. OutputDestination seleziona la visualizzazione inline, il download forzato, la scrittura su file system o la restituzione di una stringa raw. Orientation seleziona l’orientamento verticale od orizzontale. Alignment seleziona il testo allineato a sinistra, al centro, a destra o giustificato. Ogni enum espone i propri casi usando il codice TCPDF legacy come valore dell’enum. Il bridge compat-tcpdf può quindi applicare una mappatura pulita. La garanzia di compatibilità con le versioni precedenti per questi enum è additiva. Nessun caso viene rimosso. Nuovi casi possono essere introdotti in una release minore.

TipoGenereMembri chiaveStabilitàDa
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

FontRegistryInterface e ImageRegistryInterface sono documentati per intero nella pagina della tipografia; questa pagina document ne descrive il ruolo nel ciclo di vita della creazione.

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 è il builder immutabile; ogni with*() restituisce una nuova istanza. Compone internamente un DocumentFactoryInterface, quindi il modello dei registri per i worker descritto nella panoramica si applica senza ulteriore configurazione.

  • createStandalone() costruisce registri privati. In un loop worker, questo comporta l’analisi di ogni font a ogni richiesta. Usare invece DocumentFactoryInterface con registri condivisi.
  • Un Document è usa e getta per progettazione. Riutilizzare una singola istanza per documenti logici diversi provoca una propagazione indebita dello stato. Chiamare create() per ogni documento e lasciare che il garbage collector lo recuperi.
  • FontRegistryInterface::lock() fa sì che register(), addFontDirectory() e warmup() generino una LogicException. Bloccare dopo il warmup, mai durante la gestione della richiesta.
  • OutputDestination::File scrive sul file system del server e restituisce i byte raw. save() è il percorso file esplicito. Non combinare i due approcci per lo stesso documento.
  • cell() accetta bool|string per l’argomento del bordo a fini di compatibilità con TCPDF; una stringa vuota non è la stessa cosa di false. Passare il valore tipizzato previsto.

I registri di font e immagini rendono il dominio document un sistema con memoria limitata, invece di un modello legato alla singola richiesta. L’analisi dei font alla prima richiesta è l’operazione predominante. Il performance_budget è di 1500 ms di wall time e 64 MB di picco su tre documenti nell’esempio worker. Quasi tutto questo budget è dovuto alla prima analisi dei font. Dopo il warmup, il costo attribuibile al contratto per ogni documento è O(1): una ricerca nel registro e un’allocazione di contesto. memoryUsage() su uno dei due registri restituisce un MemoryReport per la pianificazione della capacità in tempo reale. ResettableService::reset() limita il picco di memoria sotto carico prolungato.

I contratti document non presentano alcuna superficie crittografica, ma comportano due rischi operativi. Primo, image() accetta un percorso o un URL. In scenari con input non attendibile, limitare il recupero remoto tramite ExternalResourcePolicyInterface (vedere la pagina security-policy) anziché passare direttamente URL controllati dall’utente. Secondo, writeHtml() è il punto di ingresso della pipeline HTML. Il markup non attendibile deve passare attraverso un HtmlSecurityPolicyInterface prima del rendering. Il livello document di per sé non esegue la sanitizzazione. Questa responsabilità appartiene al dominio security-policy ed è modellata come contratto, in modo da poter fornire un criterio più restrittivo senza ricorrere a un fork.

I contratti document implementano la struttura dei documenti PDF 2.0 come definita dalla norma ISO 32000-2. La gestione di output, pagine e font produce oggetti indiretti e un flusso di riferimenti incrociati secondo ISO 32000-2 §7. Il contenuto viene emesso tramite il livello writer secondo il contratto del livello motore (ADR-010). In questa pagina non viene asserita alcuna dichiarazione a livello di clausola oltre alla conformità strutturale. La conformità PDF/A e PDF/UA è documentata nelle pagine relative all’estrazione e all’accessibilità, che riportano le tabelle normative.