Salta ai contenuti

Guida per sviluppatori Laravel

Il pacchetto Laravel adatta NextPDF alle convenzioni di Laravel senza modificare il ciclo di vita del documento nel core. Il container gestisce registry e factory condivisi. Ogni documento PDF è monouso: va generato, restituito, trasmesso in streaming o salvato una sola volta.

Usare questa guida per progettare servizi applicativi, job in coda, flussi di risposta o copertura dei test attorno a nextpdf/laravel.

LivelloGestito daResponsabilitàDa non inserire qui
ControllerApplicazioneAutorizzare la richiesta, scegliere un builder di documenti, restituire una risposta.Regole di layout PDF condivise tra più casi d’uso.
Servizio applicativoApplicazioneRaccogliere i dati di dominio e richiamare il codice che costruisce il documento.Logica di inizializzazione del container o configurazione del pacchetto.
Builder di documentiApplicazioneTradurre i dati di dominio in chiamate ai documenti NextPDF.Oggetti request, logica di query Eloquent o dettagli del trasporto della coda.
Integrazione Laravelnextpdf/laravelAssociare factory, registry, signer, client TSA, facade, risposte e job in coda.Percorsi di archiviazione specifici del business o policy del tenant.
Motore corenextpdf/nextpdfGenerare e serializzare il PDF.Policy di risposta, coda o filesystem di Laravel.
FaseComportamentoAzione dello sviluppatore
Registrazione del service providerNextPdfServiceProvider::register() registra i registry condivisi, la factory dei documenti, il binding del documento, il client HTTP, il client TSA, il signer e i contratti e-invoice opzionali.Pubblicare e verificare config/nextpdf.php prima della messa in produzione.
Risoluzione del documentoLa facade Pdf e il binding PdfDocumentInterface risolvono un nuovo documento tramite DocumentFactoryInterface.Risolvere un documento una sola volta per ogni richiesta, comando o job in coda.
CreazioneIl codice applicativo richiama le API dei documenti del core tramite la facade o il documento iniettato.Mantenere l’estrazione dei dati di dominio al di fuori del builder di documenti.
Output terminalePdfResponse emette l’output HTTP, oppure il documento viene salvato su disco.Scegliere un unico percorso di output terminale per documento.
Esecuzione in codaGeneratePdfJob ricostruisce il documento all’interno del worker e convalida nuovamente il percorso di output.Passare un contesto scalare e mantenere idempotenti le callback.
PercorsoScopo
app/Pdf/Builders/*Builder di documenti puri. Ricevono i dati e restituiscono un documento completato.
app/Pdf/Data/*Piccoli DTO che trasportano input documentali già autorizzati.
app/Services/*Orchestrazione applicativa, query, propagazione dell’autorizzazione e selezione del percorso di archiviazione.
app/Jobs/*Wrapper opzionali attorno a GeneratePdfJob quando l’applicazione richiede job con nome.
tests/Feature/Pdf/*Test di risposta HTTP, dispatch in coda e autorizzazione.
tests/Unit/Pdf/*Test dei builder con piccoli input deterministici.

Mantenere i builder indipendenti dagli oggetti request di Laravel. Un builder deve poter essere invocato da un controller, un comando, un test e un queue worker con lo stesso input.

<?php
namespace App\Pdf\Builders;
use App\Pdf\Data\InvoicePdfData;
use NextPDF\Contracts\PdfDocumentInterface;
final readonly class InvoicePdfBuilder
{
public function build(PdfDocumentInterface $pdf, InvoicePdfData $data): PdfDocumentInterface
{
$pdf->setTitle($data->title)
->addPage()
->setFont('dejavusans', '', 12)
->writeHtml($data->html);
return $pdf;
}
}

Usare la constructor injection quando il flusso PDF rientra nella logica applicativa. Usare la facade solo in flussi di controller brevi, dove lo stile statico migliora la leggibilità.

<?php
namespace App\Http\Controllers;
use App\Pdf\Builders\InvoicePdfBuilder;
use App\Pdf\Data\InvoicePdfData;
use NextPDF\Contracts\PdfDocumentInterface;
use NextPDF\Laravel\Http\PdfResponse;
final readonly class DownloadInvoiceController
{
public function __invoke(
PdfDocumentInterface $pdf,
InvoicePdfBuilder $builder,
) {
$document = $builder->build(
$pdf,
InvoicePdfData::fromInvoiceId(1234),
);
return PdfResponse::download($document, 'invoice-1234.pdf');
}
}

Gli helper di risposta materializzano i byte del documento prima di costruire la risposta di Laravel. Sono helper di risposta, non renderer in background.

GeneratePdfJob accetta un callable builder e un percorso di output. Il job valida i percorsi al momento dell’esecuzione, rifiutando quelli non sicuri. Il codice applicativo deve comunque scegliere una radice di archiviazione sicura per il tenant prima del dispatch.

<?php
use App\Pdf\Builders\QueuedInvoiceBuilder;
use NextPDF\Laravel\Jobs\GeneratePdfJob;
GeneratePdfJob::dispatch(
outputPath: storage_path('app/pdfs/invoice-1234.pdf'),
builder: [QueuedInvoiceBuilder::class, 'build'],
)->onQueue(config('nextpdf.queue.queue', 'pdf'));

Le callback della coda devono essere minimali. È preferibile scrivere lo stato persistente da un listener di job applicativo anziché memorizzare closure complesse nel payload della coda.

Punto di estensioneDa usare perVincolo
PdfDocumentInterface (binding)Sostituire o decorare la creazione dei documenti per definire valori predefiniti a livello applicativo.Deve restituire una nuova istanza di documento.
DocumentFactoryInterfaceCreazione esplicita di un nuovo documento in servizi e test.Non memorizzare nella cache i documenti restituiti.
config/nextpdf.phpValori predefiniti, impostazioni della coda, impostazioni del renderer Chrome, hook di firma, cache TSA e OCSP.Trattare le variabili d’ambiente come configurazione di deployment, non come input della richiesta.
GeneratePdfJob (builder)Generare documenti in modo asincrono.Il callable deve essere serializzabile dal trasporto della coda di Laravel.
Callback di successo/fallimentoNotifica o pulizia dopo la generazione.Mantenere le callback idempotenti e consapevoli degli effetti collaterali.
Contratti Premium opzionaliEmbedder e-invoice, validator, profile e Schematron runner.Risolvere solo nei punti in cui il pacchetto opzionale è installato e dotato di licenza.
  1. Generare il primo documento in modo sincrono in un controller o in un feature test.
  2. Spostare il codice di layout in una classe builder sotto app/Pdf/Builders.
  3. Spostare la logica di query e di autorizzazione in un servizio applicativo.
  4. Aggiungere test PdfResponse per gli header e i nomi dei file.
  5. Spostare la generazione lenta o ad alto volume su GeneratePdfJob.
  6. Aggiungere test della coda per il contesto serializzato, la policy del percorso di output e la gestione dei fallimenti.
  7. Misurare memoria e tempo di rendering con dati di produzione rappresentativi.
FallimentoDove gestirloRisposta consigliata
Richiesta non valida o documento non autorizzatoController o policy.Restituire la normale risposta applicativa per autorizzazione o validazione.
Font mancante o immagine non validaTest del builder e logging applicativo.Far fallire la richiesta o il job; non emettere PDF parziali.
Percorso di output non sicuroServizio applicativo di archiviazione e GeneratePdfJob.Rifiutare prima del dispatch e affidarsi alla validazione lato worker come difesa in profondità.
Fallimento di firma o TSAConfine del servizio di firma.Decidere se il documento può rimanere non firmato; per i documenti regolamentati, applicare il fail closed come comportamento predefinito.
Timeout della codaConfigurazione del queue worker e osservabilità.Riprovare solo quando il builder è deterministico e il percorso di output può essere sovrascritto in sicurezza.
AspettoPredefinitoQuando eseguire l’override
Nome della codapdfUsare una coda dedicata quando la generazione compete con i job rivolti agli utenti.
Timeout del job120 secondiAumentarlo solo dopo aver misurato la dimensione del documento e la capacità del worker.
Nome del file di rispostadocument.pdfUsare identificatori di business sanificati.
Registry dei fontCondiviso e bloccato dopo il warmup.Aggiungere preload_fonts per i font utilizzati sui percorsi critici.
Registry delle immaginiCache condivisa con limite.Ridurre image_cache_mb per i worker con memoria limitata.
Suddivisione in chunk della risposta in streamingChunk da 64 KB.Non dipendere dai confini dei chunk; sono un dettaglio dell’output.
  • I test dei controller verificano Content-Type, Content-Disposition e gli header difensivi.
  • I test dei builder utilizzano DTO deterministici e non interrogano il database.
  • I test della coda verificano che il builder riceva un nuovo documento.
  • I test dei percorsi coprono il rifiuto di traversal, stream-wrapper, null-byte ed estensioni diverse da .pdf.
  • I test dei worker eseguono il rendering di documenti rappresentativi con lo stesso limite di memoria di produzione.
  • I test di firma opzionali coprono il certificato mancante, la password non valida, l’indisponibilità della TSA e il livello di firma configurato.