Ga naar inhoud

Contracts / Document

Het documentdomein bevat de contracten die u gebruikt om Portable Document Format (PDF)-uitvoer te bouwen: PdfDocumentInterface voor inhoud, DocumentFactoryInterface voor worker-veilige creatie, de lettertype- en afbeeldingsregistercontracten en de drie uitvoer- en lay-out-enums. Ze zijn allemaal stable sinds 1.0.0 of 1.7.0.

Terminal window
composer require nextpdf/core:^3

PdfDocumentInterface is het primaire oppervlak van de application programming interface (API). Het definieert paginabeheer, lettertypeselectie, tekstlayout voor cell en multi-cell, rendering van Hypertext Markup Language (HTML), het inbedden van afbeeldingen en de uiteindelijke uitvoer. Elke methode retourneert static, zodat u aanroepen aan elkaar kunt schakelen. Document::createStandalone() retourneert een concrete instantie die aan de interface voldoet. Gebruik in uw eigen services een type-hint voor de interface, zodat de interne onderdelen van de engine uitwisselbaar blijven.

Er zijn twee paden om een document te maken. Bij een klassiek verzoek via de PHP FastCGI Process Manager (PHP-FPM) bouwt createStandalone() een op zichzelf staand document met privéregisters. Langlopende workers, waaronder RoadRunner, Swoole en Laravel Octane, gebruiken het andere pad. In dat pad retourneert DocumentFactoryInterface::create() een nieuw, wegwerpbaar Document. Het document leest uit registers die net zo lang leven als het proces, maar wijzigt deze nooit. De factory bevat de singletons FontRegistryInterface en ImageRegistryInterface. Elk document krijgt zijn eigen renderingcontext en writer. Dit beperkt de impact van fouten: het ene document kan geen gedeelde status beschadigen waarvan een ander document afhankelijk is.

De registercontracten houden workers snel. FontRegistryInterface ontleedt een lettertypebestand eenmalig en bewaart de ontlede metadata gedurende de levensduur van het proces in de cache. U kunt het register na de warmup vergrendelen, zodat productieverkeer het niet kan wijzigen. ImageRegistryInterface bewaart gedecodeerde binaire afbeeldingsgegevens in de cache met een begrensd least-recently-used-beleid. De afbeeldingsmetadata blijven aanwezig, zelfs nadat de binaire gegevens zijn verwijderd. Beide registers stellen memoryUsage() beschikbaar voor capaciteitsplanning. ImageRegistryInterface breidt ResettableService uit, dat gegevens uit de cache verwijdert zonder de structurele metadata te vernietigen. Een worker kan afbeeldingscaches laten vallen bij geheugendruk en toch aanvragen blijven afhandelen.

Drie enums maken het domein compleet. OutputDestination selecteert inline weergave, geforceerde download, schrijven naar het bestandssysteem of het retourneren van een ruwe string. Orientation selecteert staand of liggend. Alignment selecteert links, gecentreerd, rechts of uitgevulde tekst. Elke enum gebruikt de verouderde TCPDF-code als enum-waarde, zodat de compat-tcpdf-brug correct wordt gemapt. De belofte van achterwaartse compatibiliteit voor deze enums is additief. Geen enkele case wordt verwijderd. Nieuwe cases kunnen verschijnen in een minor release.

TypeSoortBelangrijke ledenStabiliteitSinds
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() (breidt ResettableService uit)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

De typografiepagina documenteert FontRegistryInterface en ImageRegistryInterface volledig. Deze pagina behandelt hun rol in de levenscyclus van documentcreatie.

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 is de immutable builder. Elke aanroep van with*() retourneert een nieuwe instantie. Achter de schermen stelt hij een DocumentFactoryInterface samen, zodat het worker-registermodel uit het overzicht zonder extra wiring van toepassing is.

  • createStandalone() bouwt privéregisters. In een worker-loop wordt elk lettertype daardoor bij elk verzoek opnieuw ontleed. Gebruik in plaats daarvan DocumentFactoryInterface met gedeelde registers.
  • Een Document is door zijn ontwerp wegwerpbaar. Het hergebruiken van één instantie voor meerdere logische documenten lekt status. Roep create() aan voor elk document en laat de garbage collection het opruimen.
  • FontRegistryInterface::lock() zorgt ervoor dat register(), addFontDirectory() en warmup() een LogicException gooien. Vergrendel na de warmup, nooit tijdens het afhandelen van een verzoek.
  • OutputDestination::File schrijft naar het bestandssysteem van de server en retourneert de ruwe bytes. save() is het expliciete bestandspad. Combineer deze twee niet voor hetzelfde document.
  • cell() accepteert bool|string voor het border-argument vanwege TCPDF-compatibiliteit. Een lege string is niet hetzelfde als false. Geef de getypeerde waarde door die u bedoelt.

De lettertype- en afbeeldingsregisters maken van het documentdomein een geheugengebonden systeem in plaats van een systeem per verzoek. Het ontleden van lettertypen bij het eerste verzoek is daarbij dominant. Het performance_budget is 1500 ms wall en 64 MB piek over drie documenten in het worker-voorbeeld. Bijna het volledige budget gaat naar het ontleden van het eerste lettertype. Na de warmup is het werk dat aan het contract is toe te schrijven per document O(1): een register-lookup en een contextallocatie. memoryUsage() op elk van beide registers retourneert een MemoryReport voor live capaciteitsplanning. ResettableService::reset() begrenst het piekgeheugen onder aanhoudende belasting.

De documentcontracten hebben geen cryptografisch oppervlak, maar er gelden twee operationele risico’s. Ten eerste accepteert image() een pad of Uniform Resource Locator (URL). Beperk in scenario’s met niet-vertrouwde invoer het ophalen op afstand via ExternalResourcePolicyInterface (zie de pagina security-policy) in plaats van door de gebruiker beheerde URL’s rechtstreeks door te geven. Ten tweede is writeHtml() het toegangspunt voor de HTML-pijplijn. Niet-vertrouwde markup moet vóór rendering door een HtmlSecurityPolicyInterface gaan. De documentlaag zelf voert geen sanitatie uit. Dat is de taak van het security-policy-domein, en omdat het een contract is, kunt u een striktere policy leveren zonder te forken.

De documentcontracten implementeren de PDF 2.0-documentstructuur zoals gedefinieerd in ISO 32000-2. De afhandeling van uitvoer, pagina’s en lettertypen produceert indirecte objecten en een cross-referencestream conform ISO 32000-2 §7. De writer-laag levert inhoud conform het contract van de engine-laag, architecture decision record (ADR-010). Deze pagina doet geen enkele claim op clausuleniveau die verder gaat dan structurele conformiteit. De pagina’s over extractie en toegankelijkheid documenteren de conformiteit met PDF/A en PDF/UA en bevatten de normatieve tabellen.