NextPDF-Laravel-Paket im produktiven Einsatz
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Lösen Sie in der Produktion den Dokumentvertrag per Constructor Injection auf. Behandeln Sie PDF-Schreibfehler mit einer spezifischen Exception. Verlagern Sie aufwendige Generierung oder Batch-Generierung nach GeneratePdfJob und verdrahten Sie explizite Erfolgs- und Fehler-Callbacks.
Installation
Abschnitt betitelt „Installation“composer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-configKonfigurieren Sie die Queue-Verbindung in config/nextpdf.php. Setzen Sie queue.connection, queue.queue und queue.timeout. Stellen Sie anschließend sicher, dass für die konfigurierte Verbindung ein Worker läuft.
Konzeptioneller Überblick
Abschnitt betitelt „Konzeptioneller Überblick“Der Container stellt NextPDF\Contracts\PdfDocumentInterface über ein Factory-Binding bereit. Jede Auflösung liefert ein frisches NextPDF\Core\Document. PSR-11 erlaubt es einem Container, bei aufeinanderfolgenden get()-Aufrufen je nach Binding-Strategie unterschiedliche Werte zurückzugeben (PSR-11 §1.1.2). Das Paket verwendet dafür ein Factory-Binding, damit Request-bezogener veränderlicher Zustand niemals über Requests hinweg übertragen wird. Die Font- und Image-Registrys sind Singletons. So bleibt der Vertrag gewahrt, dass ein gebundener Bezeichner zu seinem registrierten Eintrag aufgelöst wird (PSR-11 §1.1.2), während die teuren Ressourcen weiterhin über den Worker hinweg geteilt werden.
Bevorzugen Sie im Produktionscode Constructor Injection gegenüber der Facade. Dadurch wird die Abhängigkeit explizit, und der Controller bleibt im Unit-Test prüfbar, ohne den Facade-Root zu booten.
Codebeispiel — Produktion
Abschnitt betitelt „Codebeispiel — Produktion“Per DI verdrahteter Controller mit typisierter Fehlerbehandlung
Abschnitt betitelt „Per DI verdrahteter Controller mit typisierter Fehlerbehandlung“<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\Response;use NextPDF\Contracts\PdfDocumentInterface;use NextPDF\Laravel\Http\PdfResponse;use Psr\Log\LoggerInterface;use Throwable;
final class InvoiceController extends Controller{ public function __construct( private readonly PdfDocumentInterface $document, private readonly LoggerInterface $logger, ) {}
public function show(int $invoiceId): Response { try { $this->document->addPage(); $this->document->cell(0, 10, "Invoice #{$invoiceId}", newLine: true); $this->document->cell(0, 10, 'Thank you for your business.');
return PdfResponse::download( $this->document, "invoice-{$invoiceId}.pdf", ); } catch (Throwable $exception) { // Rethrow as an HTTP-meaningful failure; never swallow. $this->logger->error('Invoice PDF generation failed', [ 'invoice_id' => $invoiceId, 'exception' => $exception::class, ]);
return new Response('Could not generate the invoice PDF.', 500); } }}Injizieren Sie PdfDocumentInterface, nicht das konkrete Document, damit das Binding in Tests austauschbar bleibt. Der Container gibt pro Controller-Instanziierung ein frisches Dokument zurück. Verwenden Sie dieselbe Controller-Instanz nicht für zwei voneinander unabhängige Dokumente innerhalb eines Prozesses.
Der Catch-Block protokolliert die Exception-Klasse und gibt einen definierten HTTP-Fehler zurück, anstatt einen Stacktrace nach außen dringen zu lassen. Verwenden Sie Psr\Log\LoggerInterface, das der Container zum Framework-Logger auflöst. PSR-3 überlässt das Escaping von Platzhaltern dem Implementierer und weist Aufrufer an, Kontextwerte nicht vorab zu escapen (PSR-3 §1.2). Übergeben Sie strukturierten Kontext, keine interpolierten Strings.
Generierung in der Queue mit Erfolgs- und Fehler-Callbacks
Abschnitt betitelt „Generierung in der Queue mit Erfolgs- und Fehler-Callbacks“GeneratePdfJob ist ein ShouldQueue-Job. Standardmäßig verwendet er drei Versuche, ein Timeout von 120 Sekunden und ein Backoff von 10 Sekunden. Alle drei können Sie über config/nextpdf.php überschreiben. Die Builder-Closure erhält das vom Container aufgelöste Dokument und muss ein konfiguriertes Dokument zurückgeben.
<?php
declare(strict_types=1);
namespace App\Jobs;
use NextPDF\Contracts\PdfDocumentInterface;use NextPDF\Laravel\Jobs\GeneratePdfJob;use Psr\Log\LoggerInterface;use Throwable;
final class DispatchMonthlyStatement{ public function __construct(private readonly LoggerInterface $logger) {}
public function __invoke(int $accountId): void { // Dispatchable::dispatch() is `public static`: it constructs the // job from the arguments it receives and returns a PendingDispatch. // Pass every constructor argument — including the callbacks — to // the static call. Building an instance and then calling // `$job->dispatch(...)` would discard that instance (and its // callbacks) and queue a different job from only the static args. GeneratePdfJob::dispatch( storage_path("app/statements/{$accountId}.pdf"), static fn (PdfDocumentInterface $document): PdfDocumentInterface => $document ->addPage() ->cell(0, 10, "Statement for account {$accountId}", newLine: true), function (string $path) use ($accountId): void { $this->logger->info('Statement PDF written', [ 'account_id' => $accountId, 'path' => $path, ]); }, function (Throwable $exception) use ($accountId): void { $this->logger->error('Statement PDF failed', [ 'account_id' => $accountId, 'exception' => $exception::class, ]); }, ); }}GeneratePdfJob::dispatch() leitet seine Argumente direkt an den Constructor (string $outputPath, callable $builder, ?callable $onSuccess, ?callable $onFailure) weiter. Damit werden die Erfolgs- und Fehler-Callbacks in genau den Job verdrahtet, der in die Queue gestellt wird. Das entspricht der positionsbasierten Form GeneratePdfJob::dispatch($path, $builder) in /integrations/laravel/quickstart/. Der Erfolgs-Callback erhält den Ausgabepfad und der Fehler-Callback das Throwable. Der Job stellt außerdem fluente then()- und catch()-Setter bereit, die den Job zur Verkettung zurückgeben. Verwenden Sie diese Setter nur, wenn Sie dieselbe Instanz behalten und dispatchen, etwa über den Helper dispatch(). Der Job stellt zudem eine failed()-Methode bereit, die der Queue-Runner bei endgültigem Fehlschlag aufruft. Die Callbacks werden in serialisierbare Closures verpackt, damit sie über den Queue-Transport hinweg erhalten bleiben.
Queue-Verhalten anpassen
Abschnitt betitelt „Queue-Verhalten anpassen“| Property | Standard | Config-Schlüssel |
|---|---|---|
tries | 3 | nicht config-gesteuert; zum Ändern eine Subklasse bilden |
timeout | 120 | nextpdf.queue.timeout |
backoff | 10 | nicht config-gesteuert; zum Ändern eine Subklasse bilden |
| Queue-Name | pdf | nextpdf.queue.queue |
| Verbindung | default | nextpdf.queue.connection |
tries und backoff sind öffentliche Properties, die aus der Job-Instanz gelesen werden. Der ausgelieferte Job liest sie nicht aus der Config. Wenn Ihre Retry-Policy abweicht, bilden Sie zum Überschreiben eine Subklasse von GeneratePdfJob.
Sonderfälle & Stolperfallen
Abschnitt betitelt „Sonderfälle & Stolperfallen“- Die Builder-Closure muss ein
PdfDocumentInterfacezurückgeben. Der Job speichert diesen Rückgabewert, nicht die ursprünglich aufgelöste Instanz. Der Job-Test prüft diesen Vertrag explizit. - Die Auflösung von
SignerInterfaceergibtnull, solange Signieren nicht aktiviert, kein Zertifikat konfiguriert odernextpdf/premiumnicht installiert ist. Prüfen Sie vor dem Signieren immer auf null. - Langlebige Worker (Octane/RoadRunner/Swoole) teilen sich die gesperrte Font-Registry. Konfigurieren Sie
preload_fonts, damit das Warmup einmalig beim Worker-Start statt beim ersten Request passiert. - Bei einem fehlgeschlagenen Job wird
failed()aufgerufen, nachdemtriesaufgebraucht ist. Der Fehlschlag eines einzelnen Versuchs löstonFailureerst dann aus, wenn der Queue-Runner den endgültigen Fehlschlag feststellt.
Performance
Abschnitt betitelt „Performance“Synchrone Generierung im Controller blockiert den Request während des gesamten PDF-Builds. Für mehrseitige Ausgabe oder Batch-Ausgabe dispatchen Sie GeneratePdfJob und kehren sofort zurück. Die Singleton-Registrys verteilen Font-Parsing und Image-Decoding über die Lebensdauer des Workers hinweg. Die Kosten pro Request beschränken sich dann auf Dokumentaufbau und Inhaltsausgabe.
Sicherheitshinweise
Abschnitt betitelt „Sicherheitshinweise“Der DI-Controller protokolliert die Exception-Klasse, nicht ihre Nachricht oder ihren Trace, um interne Details nicht in Logs offenzulegen. GeneratePdfJob validiert den Ausgabepfad auf dem Worker, um manipulierte serialisierte Payloads auf dem Queue-Transport zu entschärfen. Die vollständige Abdeckung finden Sie unter /integrations/laravel/security-and-operations/.
Konformität
Abschnitt betitelt „Konformität“| Aussage | Quelle | Klausel | reference_id |
|---|---|---|---|
| Gebundener Bezeichner wird zu seinem registrierten Eintrag aufgelöst | PSR-11 Container | §1.1.2 | |
| Aufeinanderfolgende Auflösungen können sich je nach Binding-Strategie unterscheiden (Factory-Binding) | PSR-11 Container | §1.1.2 |
Die Hinweise zum PSR-3-Logging sind in der PSR-3-Spezifikation dokumentiert. Sie besagen, dass das Escaping von Platzhaltern in der Verantwortung des Implementierers liegt und dass Aufrufer strukturierten Kontext übergeben. Siehe Doc psr_3_logger §1.2.
Kommerzieller Kontext
Abschnitt betitelt „Kommerzieller Kontext“Signierte PAdES B-B-Ausgabe und PDF/A-Archivierung über nextpdf/premium nutzen dieselbe DI-Oberfläche. Das ist eine optionale Enterprise-Fähigkeit. Für die Übernahme sind im hier dokumentierten Core-Paket keine Codeänderungen erforderlich. Siehe https://nextpdf.dev/get-license/?intent=laravel-signing.
Siehe auch
Abschnitt betitelt „Siehe auch“- /integrations/laravel/quickstart/ — minimales erstes Beispiel
- /integrations/laravel/configuration/ — Queue-, Signatur- und Font-Schlüssel
- /integrations/laravel/security-and-operations/ — Bedrohungsmodell und Härtung
- /integrations/laravel/troubleshooting/ — häufige Produktionsfehler