Zum Inhalt springen

NextPDF Symfony-Schnellstart

Injizieren Sie PdfFactory, erstellen Sie ein Document und geben Sie es über PdfResponse zurück. Um ein PDF im Hintergrund zu erzeugen, senden Sie eine GeneratePdfMessage an einen Messenger-Transport.

Schritt 1 – Ein PDF in einem Controller erzeugen

Abschnitt betitelt „Schritt 1 – Ein PDF in einem Controller erzeugen“

Injizieren Sie NextPDF\Symfony\Service\PdfFactory. Die Methode create() liefert ein neues NextPDF\Core\Document zurück. Die konfigurierten Standardwerte sind bereits für Sie gesetzt: Ersteller, Autor und Sprache. Geben Sie dieses Dokument über NextPDF\Symfony\Http\PdfResponse zurück.

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() liefert eine Symfony\Component\HttpFoundation\Response zurück. Sie setzt Content-Type: application/pdf, eine attachment-Disposition, eine Content-Length sowie die vom Bundle fest vorgegebenen Sicherheits-Header. Symfony dokumentiert die kanonische Response-Klasse und ihr Header-Modell (https://symfony.com/doc/current/components/http_foundation.html).

Damit der Browser das PDF anzeigt, anstatt es herunterzuladen, verwenden Sie inline():

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

Die Disposition wird auf inline gesetzt. Alle anderen Header bleiben unverändert.

Bei großen Dokumenten geben die Streaming-Varianten das PDF in 64-KB-Blöcken aus. Dadurch sinkt der maximale Speicherverbrauch. Sie liefern eine Symfony\Component\HttpFoundation\StreamedResponse zurück und setzen kein Content-Length.

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

streamInline() ist das entsprechende Inline-Äquivalent. Symfony dokumentiert den Callback-Vertrag von StreamedResponse, also ein void-Callable, das die Ausgabe leert (https://symfony.com/doc/current/components/http_foundation.html).

Wenn symfony/messenger installiert ist, können Sie die Erzeugung aus dem Request-Thread herauslösen.

Implementieren Sie NextPDF\Symfony\Message\PdfBuilderInterface. Der Handler übergibt Ihnen ein neues, vorkonfiguriertes Document. Zusätzlich übergibt er den serialisierbaren Kontext aus der Nachricht.

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;
}
}

Der Handler löst Builder über einen PSR-11-Service-Locator auf, dessen Schlüssel Klassennamen sind. Dadurch sind nur registrierte Builder erreichbar. Fügen Sie den Builder in config/services.yaml einem Locator hinzu:

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'

Der Handler fordert den Builder über dessen Klassen-String-ID beim Locator an. Eine PSR-11-Container-Kennung ist eine Zeichenkette, die einen Eintrag eindeutig identifiziert (PSR-11 §1.1.2).

Injizieren Sie Symfony\Component\Messenger\MessageBusInterface und versenden Sie anschließend die Nachricht:

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 ist ein readonly-DTO. Sein Konstruktor weist leere Ausgabepfade, Ausgabepfade ohne .pdf-Endung, Path-Traversal-Segmente, Stream-Wrapper-Schemata und Null-Bytes zurück. Außerdem verlangt er, dass builderClass ein syntaktisch gültiger Klassenname ist. Der Handler validiert den Ausgabepfad zur Ausführungszeit erneut, bevor er schreibt. Dadurch wird ein Pfad weiterhin zurückgewiesen, wenn er beim Versenden sicher war, beim Verarbeiten aber unsicher ist. Das Attribut #[AsMessageHandler] und der Dispatch-Vertrag von MessageBusInterface folgen dem Standardmodell von Symfony Messenger (https://symfony.com/doc/current/messenger.html).

4d – Die Nachricht routen und einen Worker ausführen

Abschnitt betitelt „4d – Die Nachricht routen und einen Worker ausführen“

Routen Sie die Nachricht in config/packages/messenger.yaml zu einem Transport:

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

Führen Sie anschließend einen Worker aus:

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

Der erste Befehl bestätigt, dass der Builder-Locator registriert ist. Der zweite Befehl verarbeitet eine einzelne Nachricht aus der Warteschlange und gibt den Fortschritt des Handlers aus.

  • /integrations/symfony/configuration/ – Standardwerte, Schriftarten und den Dokument-Service anpassen.
  • /integrations/symfony/production-usage/ – Worker-Sicherheit und Streaming unter Last.
  • /integrations/symfony/troubleshooting/ – häufige Boot- und Laufzeitprobleme.

Jede auf dieser Seite getroffene normative Aussage ist mit einer vollständigen 64-stelligen Hex-reference_id aus dem gegateten SDO-Korpus verankert. Die Provenance (Korpus-Manifest, Retrieval-Transport) ist in _sidecars/rag-citations.yaml dokumentiert.

SpecKlauselreference_idAussage
PSR-11psr_11_container#1.1.2.p4Identifier-Vertrag von Container-has()/get()
  • /integrations/symfony/overview/ – Funktionsübersicht.
  • /integrations/symfony/install/ – Installation und Registrierung.
  • /integrations/symfony/integration/ – End-to-End-Referenz zur Verdrahtung.