Salta ai contenuti
getnextpdf.com

Un solo motore, ogni framework

Spec: PSR-11 Container, §1.1.2Spec: PSR-4 Autoloader, §3

La maggior parte dei parchi PHP in crescita finisce per avere più di un framework. NextPDF è un unico motore PDF che incontra ciascuno alle sue condizioni: bridge idiomatici per Laravel, Symfony e CodeIgniter, più un percorso standalone per il codice che non gira in nessuno di essi. Il modello del documento è condiviso. Cambia soltanto il modo in cui lo si chiama.

Una libreria PDF diversa per ogni stack è una tassa silenziosa. Ciascuna ha le sue stranezze, la sua gestione dei font, la sua idea di che cosa significhi valido. Una fattura che si rende correttamente dal servizio Laravel può rendersi in modo lievemente diverso dal worker Symfony, perché l’ha disegnata una libreria diversa. Ora il tuo target archivistico, la posizione della firma e i tag di accessibilità dipendono da quale team ha prodotto il documento. Il bug report dice «il PDF è sbagliato», e la risposta dipende da quale dei tre motori l’ha prodotto.

Standardizzare su un solo motore riduce quella superficie. C’è un unico punto in cui si decide un profilo PDF/A, una sola pipeline di font da certificare, un solo validatore di cui fidarsi. Il framework in cui ti trovi di volta in volta smette di essere una variabile rispetto alla correttezza del documento.

  • Il motore core è indipendente dal framework. nextpdf/core non sa nulla di HTTP, routing o wiring del container. È un motore PDF 2.0 e nient’altro.
  • Ogni bridge adatta, non reimplementa. I pacchetti Laravel, Symfony e CodeIgniter ti offrono una facade o una factory, un helper per la risposta HTTP e un percorso di generazione in coda o asincrono — sopra lo stesso motore.
  • Un bridge segue il tuo framework, non il tuo documento. Cambia il modo in cui chiami il motore, mai ciò che il motore può produrre.
  • Lo standalone è sempre disponibile. Uno strumento da CLI, un demone o una libreria non hanno un framework da cui fare da bridge; costruiscono un documento direttamente.
  • Un solo modello del documento viaggia attraverso tutti e quattro. Gli stessi value object, enum e contratto di output compaiono ovunque, così un documento si sposta tra i punti di chiamata senza cambiare.

L’architettura è una suddivisione deliberata. Il motore è l’asset; il bridge è un adattatore sottile che parla gli idiomi di un framework. Un bridge registra un piccolo namespace sopra il core condiviso tramite l’autoloading standard (Spec: PSR-4 Autoloader, §3) e restituisce un documento tramite il contratto del container (Spec: PSR-11 Container, §1.1.2). Quel contratto è l’eroe silenzioso qui: permette a due risoluzioni dello stesso identificatore di restituire istanze diverse, che è esattamente il modo in cui un bridge ti dà un documento fresco e usa-e-getta per ogni richiesta, mantenendo al contempo il registro dei font analizzati e la cache delle immagini come singleton a livello di processo. I worker a lunga vita — Octane, RoadRunner, Swoole, Messenger — ottengono l’analisi dei font ammortizzata senza alcuna fuga di stato tra richieste, per costruzione.

I quattro idiomi differiscono soltanto in superficie:

  1. Core enginenextpdf/core — the framework-agnostic PDF 2.0 engine; the single shared document model, value objects, and output contract.
  2. Laravel bridgenextpdf/laravel — auto-discovered provider, a Pdf facade, a PdfResponse helper, and a queued GeneratePdfJob.
  3. Symfony bridgenextpdf/symfony — an auto-registered bundle, an injectable PdfFactory, a PdfResponse, and an optional Messenger handler.
  4. CodeIgniter bridgenextpdf/codeigniter — a service and pdf() helper, a Pdf library over a disposable Document, and a PdfResponse.
  5. StandaloneNo framework to bridge from — construct a Document directly in a CLI tool, daemon, or library.
Un unico motore core indipendente dal framework, raggiunto attraverso quattro superfici idiomatiche: una facade Laravel, una factory Symfony iniettata, un service CodeIgniter o un documento standalone costruito direttamente — ciascuna restituisce lo stesso modello Document usa-e-getta.

Leggi il diagramma da sinistra a destra e la lezione è la simmetria. Ogni superficie si risolve nello stesso Document. La facade Laravel, la factory Symfony, il service CodeIgniter e il costruttore standalone sono quattro porte verso un’unica stanza.

Le stesse tre righe di intento, espresse in ciascun idioma. Il corpo che costruisce il documento — pagine, font, celle, firma, conformità — è identico in tutti e quattro, perché è lo stesso motore.

<?php
declare(strict_types=1);
// Laravel — resolve a fresh document from the container.
use NextPDF\Contracts\PdfDocumentInterface;
$document = app(PdfDocumentInterface::class);
// Symfony — inject the factory, then ask it for a document.
use NextPDF\Symfony\Service\PdfFactory;
$document = $factory->create(); // PdfFactory injected into your service
// CodeIgniter — pull it from the Services layer.
use NextPDF\CodeIgniter\Config\Services;
$document = Services::pdfDocument();
// Standalone — no framework; construct it directly.
use NextPDF\Core\Document;
$document = Document::createStandalone();
// From here, the code is identical regardless of how $document arrived.
$document->addPage();
$document->cell(0, 10, 'One engine, every framework', newLine: true);
$bytes = $document->getPdfData();

Le prime righe sono l’unica differenza. Tutto ciò che segue è portabile: sposta un servizio che costruisce documenti da Symfony a un worker standalone e il codice di rendering non cambia, perché il contratto da cui dipende non è cambiato.

L’assunto frequente è che il bridge del framework sblocchi capacità — che la validazione a lungo termine delle firme o la fatturazione elettronica strutturata arrivi perché hai installato nextpdf/laravel anziché chiamare il motore direttamente. Non è così. Un bridge cambia il punto di chiamata, mai la portata del motore. Le capacità core come l’output PDF/A e la firma baseline PAdES sono open source e raggiungono ogni superficie; le capacità avanzate sono sbloccate da un’edizione e diventano poi disponibili attraverso qualunque bridge o il percorso standalone allo stesso modo. Scegliere un’integrazione di framework non significa scegliere un insieme di funzionalità.

L’equivoco speculare è che «un solo motore» debba significare un unico percorso di rendering per ogni documento. Non è così. Il motore in-process rende il PDF direttamente; quando un documento ha davvero bisogno di un motore di layout di livello browser, se ne occupa un pacchetto renderer. Rendering e invocazione sono assi distinti — la guida alle decisioni di integrazione è il punto che li mappa.

Un bridge non espande ciò che il motore può rendere. È il limite onesto, ed è il punto: la capacità vive nel core e nel tier, non nell’adattatore attraverso cui la raggiungi.

Framework bridges over one engine — edition availability
EditionAvailability
Core

Ogni bridge (Laravel, Symfony, CodeIgniter) e il percorso standalone sono Apache-2.0 e funzionano rispetto a Core. Adattano o espongono il motore; non gating delle funzionalità e non cambiano ciò che esso può produrre.

Pro

Le capacità avanzate come la validazione a lungo termine delle firme (PAdES B-LT e B-LTA) sono sbloccate da un’edizione, poi raggiunte in modo identico attraverso qualunque bridge o standalone — mai cambiando framework. L’output archivistico PDF/A e la firma baseline PAdES (B-B e B-T) sono già in Core, disponibili allo stesso modo attraverso ogni superficie.

Enterprise

Anche la fatturazione elettronica strutturata (EN 16931) e gli strumenti di conformità più approfonditi sono capacità di edizione, ugualmente identiche da qualunque superficie chiami il motore, mentre la validazione di conformità in sé è inclusa in Core.

Vale la pena enunciare con chiarezza altri due confini. Primo, ogni bridge segue una major corrente del proprio framework — Laravel, Symfony e CodeIgniter fissano ciascuno un intervallo supportato, quindi «ogni framework» significa la versione supportata di ciascuno, non ogni release storica; considera la documentazione di ciascun pacchetto come autorevole per la sua API. Secondo, i bridge sono adattatori di framework, non backend di rendering. Se un documento necessita di un motore di layout browser completo, è una scelta di renderer indipendente da quale framework abbia chiamato il motore.

  • La guida alle decisioni di integrazione — la mappa caso d’uso-pacchetto, inclusi i renderer e la superficie del servizio Connect, quando occorre decidere anziché standardizzare.
  • Open core, nessun lock-in — perché il motore è l’asset e i bridge sono sottili, così standardizzare non ti intrappola.
  • La pipeline HTML — che cosa copre il motore in-process, così sai quando un renderer browser è la questione separata.
  • Le fondamenta PHP 8.4 — la base di runtime che ogni bridge e il percorso standalone condividono.
  • Motore corenextpdf/core, il motore PDF 2.0 indipendente dal framework su cui ogni bridge e il percorso standalone si fondano.
  • Bridge di framework — un pacchetto di integrazione (Laravel, Symfony, CodeIgniter) che adatta il motore agli idiomi di un framework — facade, factory, risposta, job in coda — senza cambiarne le capacità.
  • Percorso standalone — l’uso diretto del motore core, senza framework, costruendo tu stesso un Document; la via per strumenti da CLI, demoni e librerie.
  • Documento usa-e-getta — il contratto Document a uso singolo: costruisci, emetti, scarta. Ogni risoluzione del container ne restituisce uno fresco, così nessuno stato trapela tra le richieste in un worker a lunga vita.
  • PAdES — PDF Advanced Electronic Signatures, la famiglia di profili ETSI per la firma dei PDF. La firma baseline (B-B e B-T) è in Core; la validazione a lungo termine (B-LT e B-LTA) è una funzionalità delle edizioni avanzate. In ogni caso la si raggiunge attraverso qualunque superficie, come illustrato in dettaglio nelle pagine sulla firma.