Het pijplijnmodel
Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 Evidence: Code-backed
In het kort
Sectie met titel “In het kort”Een NextPDF-document wordt niet in één ondoorzichtige stap geproduceerd. Het doorloopt een klein aantal expliciete fasen: een façade die de intentie vastlegt, een contentlaag die die intentie omzet in een model, en een writer die dat model serialiseert tot een conforme PDF. Deze pagina legt die opzet uit en waarom dit de juiste vorm voor de engine is.
Waarom dit belangrijk is
Sectie met titel “Waarom dit belangrijk is”Het PDF-bestandsformaat is zelf gelaagd opgebouwd: een header, een hoofddeel met objecten, een cross-referencetabel en een trailer. Een writer moet al die onderdelen consistent samenstellen. Als de engine die dit opbouwt één verstrengelde procedure is, brengt elke wijziging elke uitvoer in gevaar. De enige manier om vertrouwen te krijgen is dan volledige documenten renderen en ze visueel inspecteren; dat is traag, laat en weinig overtuigend.
Een expliciete pijplijn draait dat om. Elke fase heeft één taak en een getypeerde grens, zodat je over een wijziging kunt redeneren en die wijziging kunt testen in de fase die ze raakt, niet pas aan het einde van het bestand. De architectuur is in de eerste plaats een keuze voor testbaarheid en uitbreidbaarheid.
De korte versie
Sectie met titel “De korte versie”- Het publieke startpunt is een Document-façade. Het is een fluente, eenmalig te gebruiken, worker-veilige builder die vastlegt wat je wilt, niet hoe het wordt geserialiseerd.
- De façade delegeert naar ongeveer twee dozijn gerichte concern-traits (tekstuitvoer, tekenen, pagina’s, beveiliging, navigatie enzovoort), elk met één verantwoordelijkheid, niet één gigantische klasse.
- Content komt binnen via een van twee paden: direct tekenen (grafische primitieven) of de HTML/CSS-engine. Beide produceren hetzelfde interne documentmodel.
- Een aparte PDF-writer serialiseert dat model en kiest een PDF 1.4 / 1.7 / 2.0-strategie. Het produceren van een geldige bestandsstructuur gebeurt hier en nergens anders.
- State met een lange levensduur (lettertype- en afbeeldingsregisters) is procesgebonden en gedeeld; per-request-state (het document) wordt voor elke request opnieuw aangemaakt en nooit hergebruikt. Die grens is expliciet, en daardoor blijven worker-runtimes veilig.
Hoe NextPDF dit aanpakt
Sectie met titel “Hoe NextPDF dit aanpakt”De helderste manier om het model te zien is een document te volgen van aanroep tot bytes.
- Document facade Fluent, use-once builder; records intent via concern traits.
- Content production Direct drawing or the HTML/CSS engine — both build one document model.
- Document model Accumulated pages, content, and resources held as typed state.
- PDF writer Serialises the model; selects a PDF 1.4 / 1.7 / 2.0 strategy.
- Conforming PDF Header, object body, cross-reference table, trailer.
Twee ontwerpkeuzes maken dit meer dan een diagram.
De façade is samengesteld, niet monolithisch. Document implementeert niet elke functie zelf; elk gebied wordt gedelegeerd aan een gerichte concern-trait: tekstuitvoer, tekenen, pagina’s, beveiliging, typografie, navigatie, transacties enzovoort. Een nieuwe documentmethode hoort thuis in de trait voor het betreffende gebied, niet op de façade zelf. De klasse die je aanroept blijft klein en de verantwoordelijkheden blijven gescheiden.
Alleen de writer beheert de bestandsstructuur. Contentproductie beslist welke markeringen en objecten bestaan; de writer beslist hoe die een geldig PDF-bestand worden, inclusief welke versiestrategie van toepassing is. Die scheiding wordt afgedwongen als architectuurregel: lay-out- en contentcode genereert geen definitieve bestandsstructuur, en de writer neemt geen lay-outbeslissingen. Het voordeel is dat de vraag „is de uitvoer een geldige PDF?” precies één plek heeft waar die wordt getest.
De levensduurgrens is onderdeel van het model, geen bijzaak. Lettertype- en afbeeldingsregisters bestaan zolang het proces leeft en worden gedeeld tussen requests; het document, de weergavecontext en de writer worden per request aangemaakt en weer opgeruimd. In een worker-runtime is dat onderscheid het verschil tussen veilig hergebruik en corruptie tussen requests. Daarom is het vastgelegd in de architectuur en niet overgelaten aan discipline.
Wat het bewijs zegt
Sectie met titel “Wat het bewijs zegt”Deze pagina is Evidence: Code-backed . De fasen komen overeen met de daadwerkelijke structuur in de core-repository:
- De façade en de delegatie ervan zijn
src/Core/Document.phpplus de concern-traits insrc/Core/Concerns/(tekstuitvoer, uitvoer, tekenen, pagina’s, beveiliging, typografie, navigatie, transacties en meer — elk met één verantwoordelijkheid). - De twee contentpaden zijn de HTML/CSS-engine (
src/Html/) en direct tekenen (src/Graphics/), die beide het interne model voeden. - Serialisatie en de PDF-versiestrategie bevinden zich in
src/Writer/(PdfWriter.php, met expliciete PDF 1.4 / 1.7 / 2.0-strategieklassen). - De grens tussen proceslevensduur en per-request-state is het worker-veilige ontwerp dat is vastgelegd in het architectuuroverzicht en wordt gedemonstreerd door het meegeleverde worker-factory-voorbeeld, dat een
FontRegistryenImageRegistrydeelt tussen requests terwijl het elkDocumenttelkens opnieuw aanmaakt.
De eindvorm ligt vast in het formaat. De uitvoer van de writer moet een header, een hoofddeel met objecten, een cross-referencetabel en een trailer bevatten, conform Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 . Door die verplichting in één fase te concentreren, kan de rest van de engine gericht blijven op content in plaats van op het samenstellen van de bestandsstructuur.
Praktijkvoorbeeld
Sectie met titel “Praktijkvoorbeeld”De taak van de façade is de intentie ook als intentie te laten lezen. Het contentpad en de writer blijven onzichtbaar op de aanroepplek:
<?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 stageElke aanroep komt in een ander concern terecht. Twee verschillende contentpaden voeden hetzelfde model. Precies één fase — save() — zet het model om in bestandsbytes. Niets op de aanroepplek hoeft te weten hoe de cross-referencetabel wordt opgebouwd.
Veelvoorkomend misverstand
Sectie met titel “Veelvoorkomend misverstand”Een veelvoorkomende misvatting is dat „pijplijn” een streaming-push-API impliceert die je fase voor fase aan elkaar koppelt, zoals een Unix-pipe. Dat is niet zo. De pijplijn is hier een architecturale decompositie: fasen met enkelvoudige verantwoordelijkheden en getypeerde grenzen. Je programmeert nog steeds tegen een fluente façade. De fasen zijn de manier waarop de engine wordt gebouwd en getest, niet een transportmechanisme dat je met de hand samenstelt.
Een verwante fout is aannemen dat de façade de engine is. De façade is het startpunt. Het echte werk is verdeeld over concern-traits, twee contentpaden en een writer. Die verdeling is precies de reden waarom één functiewijziging niet elke uitvoer in gevaar brengt.
Grenzen en beperkingen
Sectie met titel “Grenzen en beperkingen”Deze pagina beschrijft de vorm van de pijplijn, niet de interne API van een afzonderlijke fase. De exacte inventaris van concern-traits, de selectieregels voor de writer-strategie en de velden van het contentmodel worden bepaald door de code en de referentie, niet door deze uitleg. Het precieze aantal traits is een implementatiedetail dat kan veranderen zonder het model te wijzigen. Deze pagina behandelt niet de interne fasen van de HTML-engine (een afzonderlijk onderwerp) of het streaming- en geheugengedrag van de writer (eveneens afzonderlijk). De structurele beweringen zijn juist op de reviewdatum van deze pagina; de gezaghebbende bronnen zijn src/Core/, src/Html/, src/Graphics/ en src/Writer/ van de core-repository.
Het pijplijnmodel is in alle edities identiek; edities voegen mogelijkheden toe binnen bestaande fasen, geen nieuwe fasen:
| Edition | Availability |
|---|---|
| Core | Core implementeert de volledige façade → content → writer-pijplijn. |
| Pro | Pro voegt mogelijkheden toe binnen bestaande fasen, geen nieuwe fasen. |
| Enterprise | Enterprise voegt mogelijkheden toe binnen bestaande fasen, geen nieuwe fasen. |
Gerelateerde documentatie
Sectie met titel “Gerelateerde documentatie”- Geheugen en streaming — hoe de writer-fase het geheugen begrensd houdt.
- De HTML-pijplijn — de interne fasen van het HTML-contentpad.
- Strenge types, overal — de getypeerde grenzen die elke fase onafhankelijk testbaar maken.
Verklarende woordenlijst
Sectie met titel “Verklarende woordenlijst”- Façade — het publieke
Document-startpunt: een fluente, eenmalig te gebruiken builder die de intentie vastlegt en delegeert naar concern-traits. - Concern-trait — een gerichte PHP-trait die de façade samenstelt en verantwoordelijk is voor één functiegebied (tekstuitvoer, tekenen, pagina’s, beveiliging enzovoort).
- Contentpad — een van de twee manieren waarop content in het model komt: direct tekenen of de HTML/CSS-engine.
- Documentmodel — de interne, getypeerde verzameling van pagina’s, content en resources van de engine vóór serialisatie.
- Writer-fase — de component die het model serialiseert tot een geldige PDF en daarbij een PDF 1.4 / 1.7 / 2.0-strategie kiest.
- Worker-veilig — zo ontworpen dat state met proceslevensduur veilig wordt gedeeld terwijl per-request-state telkens opnieuw wordt aangemaakt en nooit hergebruikt.