Utilisation en production avec CodeIgniter 4
En production, les contrôleurs dépendent de services NextPDF concrets. Ils gèrent explicitement la hiérarchie d’exceptions documentée et émettent des signaux d’observabilité. Les traitements PDF de longue durée sont sortis du cycle de requête via la file d’attente (Queue) de CodeIgniter 4.
Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »CodeIgniter 4 résout les services du package via son localisateur. Le motif de localisateur de service confie un conteneur à un objet pour que celui-ci récupère lui-même ses dépendances. Ce motif est déconseillé (PSR-11 §1.3, modal SHOULD NOT). Pour suivre cette recommandation, résous chaque service NextPDF une seule fois à la frontière du contrôleur, puis transmets l’objet concret aux couches internes. Ne passe pas la classe Services — ni un conteneur — dans ton code métier.
Chaque exemple PHP déclare declare(strict_types=1); sur sa propre ligne (PSR-12 §x1.x3.p34).
Surface d’API
Section intitulée « Surface d’API »| Point d’attention en production | Surface vérifiée |
|---|---|
| Résoudre les services | Services::pdf(false), Services::pdfDocument(false), Services::documentFactory() |
| Construire la réponse | PdfResponse::download() / inline() → DownloadResponse |
| Intercepter les échecs | NextPDF\Exception\NextPdfException (type de base de l’écosystème) |
| Génération asynchrone | GeneratePdfJob enregistré dans Config\Queue::$jobHandlers |
| Garde-fous sur les chemins et les callables | GeneratePdfJob lève InvalidArgumentException |
Contrôleur de production — gestion des erreurs et observabilité
Section intitulée « Contrôleur de production — gestion des erreurs et observabilité »Le moteur principal lève des exceptions qui héritent toutes de NextPDF\Exception\NextPdfException. Intercepter ce seul type couvre les échecs du moteur principal et des extensions. Le bloc catch utilisé ici journalise avec du contexte et renvoie une réponse d’erreur définie, jamais un bloc catch vide.
<?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) renvoie une nouvelle instance de bibliothèque et un document sous-jacent neuf à chaque appel. Les requêtes concurrentes ne partagent donc jamais l’état d’un document. Les tests fonctionnels du package vérifient ce comportement.
Durées de vie des services sûres pour les workers
Section intitulée « Durées de vie des services sûres pour les workers »Les registres de polices et d’images sont, par conception, des singletons dont la durée de vie est celle du processus. Le registre de polices est préchauffé et verrouillé une seule fois. Le registre d’images est un cache borné de type « least-recently-used » (LRU). Dans un worker de longue durée (serveur CodeIgniter spark, runner de type RoadRunner ou worker de file d’attente), c’est le comportement attendu : les registres coûteux persistent, tandis que chaque document est neuf. Ne demande pas un document partagé (Services::pdfDocument(true)) dans le code d’une requête ou d’une tâche ; il est réservé à la réinitialisation des tests et partagerait le contenu entre les requêtes.
Génération asynchrone avec la file d’attente CodeIgniter
Section intitulée « Génération asynchrone avec la file d’attente CodeIgniter »GeneratePdfJob exécute la génération PDF hors de la requête via codeigniter4/queue. Le fonctionnement de la file d’attente impose deux points à respecter, et tu dois configurer les deux correctement.
1. Enregistre le gestionnaire de tâche par son nom
Section intitulée « 1. Enregistre le gestionnaire de tâche par son nom »La file d’attente résout une tâche à partir d’une clé de nom, pas d’une chaîne de classe. Le gestionnaire de file d’attente vérifie que le nom de tâche poussé correspond à l’une des clés de Config\Queue::$jobHandlers. La file d’attente rejette un nom inconnu avec CodeIgniter\Queue\Exceptions\QueueException. Enregistre la tâche dans 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. Dispatche par le nom enregistré
Section intitulée « 2. Dispatche par le nom enregistré »Pousse la tâche en utilisant le nom enregistré comme deuxième argument. Le premier argument est le nom de la file d’attente. Le troisième argument contient le tableau de données de la tâche.
<?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. Implémente le builder sous App\PdfBuilders
Section intitulée « 3. Implémente le builder sous App\PdfBuilders »La tâche restreint les callables de builder à l’espace de noms App\PdfBuilders et confine les chemins de sortie à WRITEPATH/pdfs/. Le builder correspond à une méthode statique. Il reçoit un Document neuf et le tableau de contexte, puis il renvoie le document.
<?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; }}Lance le worker
Section intitulée « Lance le worker »php spark queue:work pdf-queueChaque exécution de tâche part d’un document neuf via Services::pdfDocument(). Elle applique le builder, puis l’enregistre dans le chemin validé. Les tests du package vérifient que deux exécutions de tâche consécutives ne partagent pas l’état d’un document.
Cas limites et pièges
Section intitulée « Cas limites et pièges »- La file d’attente rejette
GeneratePdfJob::classcomme nom de tâche au moment du push, car ce n’est pas la clé enregistrée'generate-pdf'. Pousse toujours la clé dejobHandlers. - La chaîne de builder doit correspondre exactement à
App\PdfBuilders\<Class>::<method>. Les fonctions, les autres espaces de noms ou les charges utiles avec préfixe ou suffixe lèventInvalidArgumentExceptionavant l’exécution du moindre code. - Le chemin de sortie doit se résoudre à l’intérieur de
WRITEPATH/pdfs/et se terminer par.pdf(insensible à la casse). Les chemins de traversée et ceux utilisant un préfixe frère sont rejetés. codeigniter4/queueest une dépendance du package réservée au développement. Ajoute-la aux dépendances de l’application qui exécute les workers.
Performance
Section intitulée « Performance »Les registres sont créés une seule fois par processus worker. Le coût de construction d’un document évolue avec le contenu, pas avec l’adaptateur. Pour les grosses tâches de traitement par lots, privilégie la file d’attente afin que les workers de requête restent réactifs. Définis un performance_budget dans toute recipe ayant une cible mesurable.
Notes de sécurité
Section intitulée « Notes de sécurité »La tâche de file d’attente est la surface la plus à risque. Les charges utiles de la file d’attente sont influençables par un attaquant lorsque le broker est accessible. La liste d’autorisation de callables et le confinement des chemins sont traités dans /integrations/codeigniter/security-and-operations/ avec les cas de rejet vérifiés.
Conformité
Section intitulée « Conformité »- Les contrôleurs reçoivent des services concrets, pas un conteneur, conformément à la recommandation de PSR-11 §1.3 relative au localisateur de service.
Contexte commercial
Section intitulée « Contexte commercial »Le cœur de NextPDF est sous licence Apache-2.0. La production de sorties signées et PDF/A dans les tâches de file d’attente nécessite NextPDF Pro ou Enterprise installé dans l’environnement du worker. Le package CodeIgniter expose les méthodes de service correspondantes. Elles renvoient null tant que le package Premium correspondant n’est pas installé. Voir </get-license/?intent=codeigniter-async-signing>.
Voir aussi
Section intitulée « Voir aussi »- /integrations/codeigniter/quickstart/ — la version minimale de ces contrôleurs.
- /integrations/codeigniter/configuration/ — signature, TSA et configuration des chemins.
- /integrations/codeigniter/security-and-operations/ — modèle de menace de la file d’attente et durcissement.
- /integrations/codeigniter/troubleshooting/ — modes de défaillance de la file d’attente et de la découverte.
- /integrations/codeigniter/integration/ — référence de câblage et test de fumée.