Guida per sviluppatori Symfony
In breve
Sezione intitolata “In breve”Il package Symfony è orientato ai servizi. Iniettare PdfFactory, chiamare create() per ogni documento e utilizzare i builder Messenger per la generazione asincrona. La factory può essere registrata come servizio del container, perché ogni chiamata restituisce un documento nuovo.
Utilizzare questa guida quando si progettano controller, servizi, handler Messenger o punti di estensione a livello di bundle basati su nextpdf/symfony.
Confine architetturale
Sezione intitolata “Confine architetturale”| Livello | Di proprietà di | Responsabilità | Da non collocare qui |
|---|---|---|---|
| Controller | Applicazione | Autorizzare la richiesta, raccogliere l’input e restituire PdfResponse. | Layout PDF condiviso tra i casi d’uso. |
| Servizio applicativo | Applicazione | Caricare i dati di dominio e scegliere un builder. | Logica dei compiler pass del container Symfony. |
| Servizio builder | Applicazione | Implementare PdfBuilderInterface per costruire documenti in modo sincrono o in coda. | Oggetti request, entity manager o contesti non serializzabili. |
| Bundle Symfony | nextpdf/symfony | Registrare servizi, albero di configurazione, pass di estensione opzionale, helper per le response e DTO Messenger. | Policy di archiviazione specifiche del tenant. |
| Motore core | nextpdf/nextpdf | Comporre e serializzare il documento. | Comportamento della response Symfony o di Messenger. |
Ciclo di vita a runtime
Sezione intitolata “Ciclo di vita a runtime”| Fase | Comportamento | Azione dello sviluppatore |
|---|---|---|
| Avvio del bundle | NextPdfBundle::build() registra il rilevamento delle estensioni opzionali. | Lasciare che Symfony rilevi il bundle oppure registrarlo in bundles.php. |
| Caricamento della configurazione | NextPdfExtension::load() elabora la configurazione nextpdf: e carica le definizioni dei servizi. | Mantenere la configurazione esplicita e consapevole dell’ambiente di esecuzione. |
| Uso della factory | PdfFactory::create() restituisce un documento nuovo già configurato. | Non memorizzare i documenti nei servizi. |
| Output del controller | PdfResponse trasforma un documento completato in una response. | Utilizzare l’helper anziché assemblare manualmente gli header. |
| Dispatch di Messenger | GeneratePdfMessage trasporta la classe del builder, il percorso di output e il contesto serializzabile. | Mantenere il contesto minimo e basato su valori scalari. |
| Gestione del messaggio | GeneratePdfHandler risolve il builder tramite un service locator e salva il documento. | Rendere i builder deterministici e idempotenti. |
Struttura applicativa consigliata
Sezione intitolata “Struttura applicativa consigliata”| Percorso | Scopo |
|---|---|
src/Pdf/Builder/* | Servizi che implementano PdfBuilderInterface. |
src/Pdf/Data/* | DTO piccoli o array utilizzati come contesto del builder. |
src/Pdf/Storage/* | Scelta della root di archiviazione e policy per il nome del file di output. |
src/Controller/* | Entrypoint per response sincrone. |
tests/Pdf/* | Test per builder, response, Messenger e configurazione. |
Preferire i servizi builder alle funzioni helper statiche. Sono facili da taggare, decorare, testare e utilizzare da Messenger.
<?php
namespace App\Pdf\Builder;
use NextPDF\Core\Document;use NextPDF\Symfony\Message\PdfBuilderInterface;
final readonly class InvoicePdfBuilder implements PdfBuilderInterface{ public function build(Document $document, array $context): Document { $document->setTitle((string) $context['title']) ->addPage() ->writeHtml((string) $context['html']);
return $document; }}Pattern di response sincrona
Sezione intitolata “Pattern di response sincrona”<?php
namespace App\Controller;
use App\Pdf\Builder\InvoicePdfBuilder;use NextPDF\Symfony\Http\PdfResponse;use NextPDF\Symfony\Service\PdfFactory;
final readonly class InvoiceController{ public function __invoke( PdfFactory $factory, InvoicePdfBuilder $builder, ) { $document = $builder->build($factory->create(), [ 'title' => 'Invoice 1234', 'html' => '<h1>Invoice 1234</h1>', ]);
return PdfResponse::download($document, 'invoice-1234.pdf'); }}Mantenere snello il contesto del controller. Se un builder richiede molti oggetti di dominio, spostare l’orchestrazione in un servizio applicativo e passare al builder un DTO o un array normalizzato.
Pattern Messenger
Sezione intitolata “Pattern Messenger”GeneratePdfMessage convalida la classe del builder e il percorso di output prima del dispatch. L’handler convalida nuovamente il percorso in fase di esecuzione.
<?php
use App\Pdf\Builder\InvoicePdfBuilder;use NextPDF\Symfony\Message\GeneratePdfMessage;
$bus->dispatch(new GeneratePdfMessage( builderClass: InvoicePdfBuilder::class, outputPath: $projectDir . '/var/pdfs/invoice-1234.pdf', builderContext: [ 'title' => 'Invoice 1234', 'html' => '<h1>Invoice 1234</h1>', ],));Non inserire entity Doctrine, stream aperti, closure, oggetti request o oggetti di servizio in builderContext.
Punti di estensione
Sezione intitolata “Punti di estensione”| Punto di estensione | Da utilizzare per | Vincolo |
|---|---|---|
Decorazione del servizio PdfFactory | Applicare i valori predefiniti dell’applicazione prima che i documenti raggiungano i controller. | Deve preservare la semantica del documento nuovo. |
PdfBuilderInterface | Definire builder di documenti riutilizzabili o in coda. | Deve restituire un Document. |
OptionalExtensionPass | Abilitare funzionalità Artisan o Premium opzionali in fase di compilazione. | La disponibilità è determinata in fase di compilazione del container, non a livello di richiesta. |
| Albero di configurazione Symfony | Valori predefiniti, PDF/A, impostazioni del renderer, firma, TSA, Messenger. | Una configurazione non valida deve generare un errore durante la build del container. |
Wiring del servizio GeneratePdfHandler | Limitare i builder raggiungibili dai messaggi in coda. | Il service locator deve esporre solo i servizi builder approvati. |
Flusso di lavoro di sviluppo
Sezione intitolata “Flusso di lavoro di sviluppo”- Aggiungere un servizio builder con input deterministico.
- Utilizzare
PdfFactory::create()in un controller o in un servizio. - Aggiungere un test della response per nome del file, content type e header.
- Registrare il builder per Messenger quando lo stesso documento deve essere generato in modo asincrono.
- Aggiungere test sui messaggi non validi per nome della classe, percorso di output e forma del contesto.
- Aggiungere un test di compilazione del container con configurazione minima e di produzione.
- Misurare tempo di rendering e memoria con le stesse impostazioni PHP della produzione.
Gestione degli errori
Sezione intitolata “Gestione degli errori”| Errore | Dove deve essere gestito | Risposta consigliata |
|---|---|---|
| Configurazione non valida | Compilazione del container. | Far fallire il deployment prima che il traffico raggiunga l’applicazione. |
| Servizio builder mancante | Test dell’handler Messenger e tag dei servizi. | Far fallire il messaggio e avvisare il team responsabile. |
| Percorso di output non sicuro | Costruttore del messaggio e policy di archiviazione. | Rifiutare il messaggio prima del dispatch; mantenere la convalida nell’handler come difesa in profondità. |
| Estensione opzionale non disponibile | Compiler pass e comportamento della factory. | Disabilitare la funzionalità opzionale oppure rendere esplicita l’installazione. |
| Errore di conversione del servizio o di rendering | Confine del builder. | Fallire in modo sicuro, a meno che il caso d’uso non disponga di un fallback documentato. |
Valori predefiniti sicuri
Sezione intitolata “Valori predefiniti sicuri”| Aspetto | Predefinito | Quando sovrascrivere |
|---|---|---|
| Durata della factory | Servizio del container. | Mantenere questa impostazione; la factory è sicura perché crea documenti nuovi. |
| Durata del documento | Una singola unità di lavoro. | Non condividerlo mai tra richieste o messaggi. |
| Convalida del percorso di output | Costruttore del messaggio e handler. | Aggiungere vincoli di tenant o di root di archiviazione nel codice applicativo. |
| Nome del file della response | document.pdf. | Sovrascrivere con identificatori di business sanificati. |
| Trasporto Messenger | async. | Utilizzare un trasporto dedicato quando l’elaborazione PDF è pesante. |
Checklist di test
Sezione intitolata “Checklist di test”- I test del container compilano il bundle con configurazione minima e di produzione.
- I test della response verificano gli header di sicurezza e la gestione del nome del file.
- I test Messenger verificano che percorsi non validi e nomi di classi builder non validi falliscano prima del dispatch.
- I test dell’handler utilizzano un servizio builder reale e una directory di output temporanea.
- I test del builder eseguono il rendering di un documento rappresentativo e lo salvano con permessi di file system simili a quelli di produzione.
- I test delle estensioni opzionali coprono Artisan non disponibile, Premium non disponibile e il comportamento del profilo PDF/A configurato.