Salta ai contenuti

Avvio rapido a NextPDF per Symfony

Iniettare PdfFactory, costruire un Document e restituirlo con PdfResponse. Per generare un PDF in background, inviare un GeneratePdfMessage a un trasporto Messenger.

Iniettare NextPDF\Symfony\Service\PdfFactory: il relativo metodo create() restituisce un nuovo NextPDF\Core\Document. I valori predefiniti configurati, cioè creatore, autore e lingua, vengono applicati automaticamente. Restituire tale documento con NextPDF\Symfony\Http\PdfResponse.

src/Controller/InvoiceController.php
<?php
declare(strict_types=1);
namespace App\Controller;
use NextPDF\Symfony\Http\PdfResponse;
use NextPDF\Symfony\Service\PdfFactory;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
final class InvoiceController
{
#[Route('/invoice/{number}', name: 'invoice_pdf')]
public function download(PdfFactory $pdf, string $number): Response
{
$doc = $pdf->create();
$doc->addPage();
$doc->cell(0, 10, "Invoice #{$number}", newLine: true);
$doc->cell(0, 10, 'Thank you for your business.');
return PdfResponse::download($doc, "invoice-{$number}.pdf");
}
}

PdfResponse::download() restituisce una Symfony\Component\HttpFoundation\Response. Imposta Content-Type: application/pdf, una disposizione attachment, un Content-Length e le intestazioni di sicurezza fisse del bundle. Symfony documenta la classe canonica Response e il relativo modello di intestazioni (https://symfony.com/doc/current/components/http_foundation.html).

Per consentire al browser di visualizzare il PDF invece di scaricarlo, utilizzare inline():

return PdfResponse::inline($doc, 'preview.pdf');

La disposizione passa a inline. Tutte le altre intestazioni rimangono invariate.

Passaggio 3 — Trasmettere in streaming un PDF di grandi dimensioni

Sezione intitolata “Passaggio 3 — Trasmettere in streaming un PDF di grandi dimensioni”

Per i documenti di grandi dimensioni, le varianti in streaming emettono il PDF in blocchi da 64 KB. Questo riduce il picco di memoria. Restituiscono una Symfony\Component\HttpFoundation\StreamedResponse e omettono Content-Length.

return PdfResponse::streamDownload($doc, 'annual-report.pdf');

streamInline() è l’equivalente inline. Symfony documenta il contratto di callback StreamedResponse, cioè un callable void che effettua il flush dell’output (https://symfony.com/doc/current/components/http_foundation.html).

Quando symfony/messenger è installato, è possibile spostare la generazione fuori dal thread della richiesta.

Implementare NextPDF\Symfony\Message\PdfBuilderInterface. L’handler passa un Document nuovo e preconfigurato. Passa anche il contesto serializzabile contenuto nel messaggio.

src/Pdf/InvoicePdfBuilder.php
<?php
declare(strict_types=1);
namespace App\Pdf;
use NextPDF\Core\Document;
use NextPDF\Symfony\Message\PdfBuilderInterface;
final class InvoicePdfBuilder implements PdfBuilderInterface
{
public function build(Document $document, array $context): Document
{
$document->addPage();
$document->setFont('dejavusans', '', 12);
$document->cell(0, 10, 'Invoice #' . $context['invoice_id']);
return $document;
}
}

L’handler risolve i builder da un service locator PSR-11 indicizzato per nome di classe. Di conseguenza, solo i builder registrati sono risolvibili. Aggiungere il builder a un locator in config/services.yaml:

services:
App\Pdf\InvoicePdfBuilder: ~
nextpdf.pdf_builder_locator:
class: Symfony\Component\DependencyInjection\ServiceLocator
arguments:
- 'App\Pdf\InvoicePdfBuilder': '@App\Pdf\InvoicePdfBuilder'
tags: ['container.service_locator']
NextPDF\Symfony\Message\GeneratePdfHandler:
arguments:
$builderLocator: '@nextpdf.pdf_builder_locator'

L’handler richiede al locator il builder tramite il relativo id class-string. Un identificatore di container PSR-11 è una stringa che identifica in modo univoco una voce (PSR-11 §1.1.2).

Iniettare Symfony\Component\Messenger\MessageBusInterface e inviare il messaggio:

src/Controller/ReportController.php
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Pdf\InvoicePdfBuilder;
use NextPDF\Symfony\Message\GeneratePdfMessage;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;
final class ReportController
{
#[Route('/invoice/{id}/queue', name: 'invoice_queue')]
public function queue(MessageBusInterface $bus, int $id): Response
{
$bus->dispatch(new GeneratePdfMessage(
builderClass: InvoicePdfBuilder::class,
outputPath: '/var/storage/invoices/' . $id . '.pdf',
builderContext: ['invoice_id' => $id],
));
return new Response('PDF generation queued.', 202);
}
}

GeneratePdfMessage è un DTO readonly. Il relativo costruttore rifiuta percorsi di output vuoti o non .pdf, segmenti di path traversal, schemi degli stream wrapper e byte null. Richiede inoltre che builderClass sia un nome di classe sintatticamente valido. L’handler convalida di nuovo il percorso di output in fase di esecuzione, prima di scrivere. Pertanto, un percorso sicuro al momento dell’invio ma non sicuro al momento del consumo viene comunque rifiutato. L’attributo #[AsMessageHandler] e il contratto di invio MessageBusInterface seguono il modello standard di Symfony Messenger (https://symfony.com/doc/current/messenger.html).

4d — Instradare il messaggio ed eseguire un worker

Sezione intitolata “4d — Instradare il messaggio ed eseguire un worker”

In config/packages/messenger.yaml, instradare il messaggio verso un trasporto:

framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
NextPDF\Symfony\Message\GeneratePdfMessage: async

Quindi eseguire un worker:

Terminal window
php bin/console messenger:consume async
Terminal window
php bin/console debug:container --tag=container.service_locator
php bin/console messenger:consume async --limit=1 -vv

Il primo comando conferma che il locator del builder è registrato. Il secondo consuma un singolo messaggio accodato e stampa lo stato di avanzamento dell’handler.

  • /integrations/symfony/configuration/ — ottimizzare i valori predefiniti, i font e il servizio document.
  • /integrations/symfony/production-usage/ — sicurezza dei worker e streaming sotto carico.
  • /integrations/symfony/troubleshooting/ — problemi comuni di avvio e di runtime.

Ogni riga è un’affermazione normativa presente in questa pagina, ancorata a un reference_id completo a 64 cifre esadecimali proveniente dal corpus SDO ad accesso riservato. La provenienza (manifest del corpus, trasporto usato per il recupero) è in _sidecars/rag-citations.yaml.

SpecificaClausolareference_idAffermazione
PSR-11psr_11_container#1.1.2.p4Contratto degli identificatori has()/get() del container
  • /integrations/symfony/overview/ — riepilogo delle funzionalità.
  • /integrations/symfony/install/ — installazione e registrazione.
  • /integrations/symfony/integration/ — riferimento di wiring end-to-end.