Produktiver Einsatz mit CodeIgniter 4
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Controller im Produktivbetrieb sind von konkreten NextPDF-Diensten abhängig. Sie behandeln die dokumentierte Exception-Hierarchie explizit und geben Observability-Signale aus. Lang laufende PDF-Arbeit wird über die CodeIgniter 4 Queue aus dem Request ausgelagert.
Konzeptioneller Überblick
Abschnitt betitelt „Konzeptioneller Überblick“CodeIgniter 4 löst die Dienste des Pakets über seinen Locator auf. Beim Service-Locator-Muster wird einem Objekt ein Container übergeben, damit das Objekt seine eigenen Abhängigkeiten daraus ziehen kann. Von diesem Muster wird abgeraten (PSR-11 §1.3, modales SHOULD NOT). Um dieser Empfehlung zu folgen, lösen Sie jeden NextPDF-Dienst einmal an der Controller-Grenze auf und reichen das konkrete Objekt nach innen weiter. Übergeben Sie weder die Services-Klasse noch einen Container an Ihren Domänencode.
Jedes PHP-Beispiel deklariert declare(strict_types=1); in einer eigenen Zeile (PSR-12 §x1.x3.p34).
API-Oberfläche
Abschnitt betitelt „API-Oberfläche“| Produktiv-Aspekt | Verifizierte Oberfläche |
|---|---|
| Dienste auflösen | Services::pdf(false), Services::pdfDocument(false), Services::documentFactory() |
| Response aufbauen | PdfResponse::download() / inline() → DownloadResponse |
| Fehler abfangen | NextPDF\Exception\NextPdfException (Basistyp des Ökosystems) |
| Asynchrone Generierung | GeneratePdfJob registriert in Config\Queue::$jobHandlers |
| Schutz für Pfad / Callable | GeneratePdfJob wirft InvalidArgumentException |
Produktiv-Controller — Fehlerbehandlung und Observability
Abschnitt betitelt „Produktiv-Controller — Fehlerbehandlung und Observability“Die Core-Engine wirft Exceptions, die alle NextPDF\Exception\NextPdfException erweitern. Das Abfangen dieses einen Typs deckt Fehler aus Core und Erweiterungen ab. Der catch-Block in diesem Beispiel protokolliert mit Kontext und gibt eine definierte Fehler-Response zurück; ein leerer catch-Block wird niemals verwendet.
<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\DownloadResponse;use CodeIgniter\HTTP\ResponseInterface;use NextPDF\CodeIgniter\Config\Services;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
final class InvoiceController extends BaseController{ public function download(int $id): DownloadResponse|ResponseInterface { /** @var LoggerInterface $logger */ $logger = \service('logger');
$start = \hrtime(true);
try { $pdf = Services::pdf(false); $pdf->document()->addPage(); $pdf->document()->cell(0, 10, "Invoice #{$id}");
$response = $pdf->download("invoice-{$id}.pdf");
$logger->info('pdf.invoice.generated', [ 'invoice_id' => $id, 'elapsed_ms' => (\hrtime(true) - $start) / 1_000_000, ]);
return $response; } catch (NextPdfException $e) { $logger->error('pdf.invoice.failed', [ 'invoice_id' => $id, 'exception' => $e::class, 'message' => $e->getMessage(), ]);
return $this->response ->setStatusCode(ResponseInterface::HTTP_INTERNAL_SERVER_ERROR) ->setJSON(['error' => 'pdf_generation_failed', 'invoice_id' => $id]); } }}Services::pdf(false) gibt bei jedem Aufruf eine neue Bibliotheksinstanz und ein neues zugrunde liegendes Dokument zurück. Gleichzeitige Requests teilen sich deshalb niemals den Dokumentzustand. Die funktionalen Tests des Pakets stellen dieses Verhalten sicher.
Worker-sichere Dienst-Lebensdauern
Abschnitt betitelt „Worker-sichere Dienst-Lebensdauern“Die Schriftarten- und Bild-Registries sind absichtlich Singletons mit Prozesslebensdauer. Die Schriftarten-Registry wird einmal vorgewärmt und gesperrt. Die Bild-Registry ist ein begrenzter Least-Recently-Used-Cache (LRU). In einem langlebigen Worker (CodeIgniter spark server, Runner im RoadRunner-Stil oder ein Queue-Worker) ist das genau das gewünschte Verhalten: Die teuren Registries bleiben bestehen, während jedes Dokument neu ist. Fordern Sie in Request- oder Jobcode kein geteiltes Dokument an (Services::pdfDocument(true)); es existiert nur für den Test-Reset und würde Inhalte über Requests hinweg teilen.
Asynchrone Generierung mit der CodeIgniter Queue
Abschnitt betitelt „Asynchrone Generierung mit der CodeIgniter Queue“GeneratePdfJob führt die PDF-Generierung über codeigniter4/queue außerhalb des Requests aus. Die Queue-Laufzeit erzwingt zwei Vorgaben, die Sie beide korrekt konfigurieren müssen.
1. Registrieren Sie den Job-Handler über seinen Namen
Abschnitt betitelt „1. Registrieren Sie den Job-Handler über seinen Namen“Die Queue löst einen Job über einen Namensschlüssel auf, nicht über einen Klassenstring. Der Queue-Handler validiert den gepushten Job-Namen gegen die Schlüssel von Config\Queue::$jobHandlers. Er weist einen unbekannten Namen mit CodeIgniter\Queue\Exceptions\QueueException ab. Registrieren Sie den Job in app/Config/Queue.php:
<?php
declare(strict_types=1);
namespace Config;
use CodeIgniter\Queue\Config\Queue as BaseQueue;use NextPDF\CodeIgniter\Jobs\GeneratePdfJob;
final class Queue extends BaseQueue{ /** @var array<string, class-string> */ public array $jobHandlers = [ 'generate-pdf' => GeneratePdfJob::class, ];}2. Versenden Sie über den registrierten Namen
Abschnitt betitelt „2. Versenden Sie über den registrierten Namen“Pushen Sie den Job mit dem registrierten Namen als zweitem Argument. Das erste Argument ist der Queue-Name. Das dritte Argument ist das Job-Daten-Array.
<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\ResponseInterface;
final class InvoiceController extends BaseController{ public function queueInvoice(int $id): ResponseInterface { \service('queue')->push('pdf-queue', 'generate-pdf', [ 'builder' => 'App\\PdfBuilders\\InvoiceBuilder::build', 'outputPath' => WRITEPATH . 'pdfs/invoice-' . $id . '.pdf', 'context' => ['invoice_id' => $id], ]);
return $this->response ->setStatusCode(ResponseInterface::HTTP_ACCEPTED) ->setJSON(['status' => 'queued', 'invoice_id' => $id]); }}3. Implementieren Sie den Builder unter App\PdfBuilders
Abschnitt betitelt „3. Implementieren Sie den Builder unter App\PdfBuilders“Der Job beschränkt Builder-Callables auf den Namespace App\PdfBuilders und begrenzt Ausgabepfade auf WRITEPATH/pdfs/. Der Builder ist eine statische Methode. Er erhält ein neues Document und das Kontext-Array und gibt das Dokument zurück.
<?php
declare(strict_types=1);
namespace App\PdfBuilders;
use NextPDF\Core\Document;
final class InvoiceBuilder{ /** @param array<string, mixed> $context */ public static function build(Document $document, array $context): Document { $invoiceId = (int) ($context['invoice_id'] ?? 0);
$document->addPage(); $document->cell(0, 10, "Invoice #{$invoiceId}");
return $document; }}Den Worker ausführen
Abschnitt betitelt „Den Worker ausführen“php spark queue:work pdf-queueJeder Joblauf startet über Services::pdfDocument() mit einem neuen Dokument. Er wendet den Builder an und speichert anschließend in den validierten Pfad. Die Tests des Pakets verifizieren, dass zwei aufeinanderfolgende Jobläufe keinen Dokumentzustand teilen.
Sonderfälle & Fallstricke
Abschnitt betitelt „Sonderfälle & Fallstricke“- Die Queue weist
GeneratePdfJob::classals Job-Namen beim Pushen ab, weil dies nicht der registrierte Schlüssel'generate-pdf'ist. Pushen Sie immer denjobHandlers-Schlüssel. - Der Builder-String muss exakt
App\PdfBuilders\<Class>::<method>entsprechen. Funktionen, andere Namespaces oder prefixed/suffixed Payloads lösenInvalidArgumentExceptionaus, bevor Code ausgeführt wird. - Der Ausgabepfad muss innerhalb von
WRITEPATH/pdfs/aufgelöst werden und auf.pdfenden (ohne Beachtung der Groß-/Kleinschreibung). Traversal- und Geschwister-Präfix-Pfade werden abgelehnt. codeigniter4/queueist eine reine Entwicklungsabhängigkeit des Pakets. Nehmen Sie es als Abhängigkeit in die Anwendung auf, die Worker ausführt.
Performance
Abschnitt betitelt „Performance“Die Registries werden einmal pro Workerprozess erstellt. Die Kosten für den Dokumentaufbau skalieren mit dem Inhalt, nicht mit dem Adapter. Bevorzugen Sie für große Batch-Jobs den Queue-Pfad, damit Request-Worker reaktionsfähig bleiben. Setzen Sie in jedem Recipe ein performance_budget mit messbarem Ziel.
Sicherheitshinweise
Abschnitt betitelt „Sicherheitshinweise“Der Queue-Job bildet die Oberfläche mit dem höchsten Risiko. Queue-Payloads sind von Angreifern beeinflussbar, wenn der Broker erreichbar ist. Die Callable-Allowlist und die Pfadbegrenzung werden in /integrations/codeigniter/security-and-operations/ zusammen mit den verifizierten Ablehnungsfällen behandelt.
Konformität
Abschnitt betitelt „Konformität“- Controller erhalten konkrete Dienste, keinen Container, im Einklang mit der Service-Locator-Empfehlung von PSR-11 §1.3.
Kommerzieller Kontext
Abschnitt betitelt „Kommerzieller Kontext“NextPDF Core ist Apache-2.0. Signierte Ausgabe und PDF/A-Ausgabe in Queue-Jobs setzen voraus, dass NextPDF Pro oder Enterprise in der Worker-Umgebung installiert ist. Das CodeIgniter-Paket stellt die entsprechenden Dienstmethoden bereit. Diese geben null zurück, bis das passende Premium-Paket installiert ist. Siehe </get-license/?intent=codeigniter-async-signing>.
Siehe auch
Abschnitt betitelt „Siehe auch“- /integrations/codeigniter/quickstart/ — die Minimalversion dieser Controller.
- /integrations/codeigniter/configuration/ — Signierung, TSA und Pfadkonfiguration.
- /integrations/codeigniter/security-and-operations/ — Bedrohungsmodell und Härtung der Queue.
- /integrations/codeigniter/troubleshooting/ — Fehlermodi von Queue und Discovery.
- /integrations/codeigniter/integration/ — Verdrahtungsreferenz und Smoke-Test.