Uso en producción con CodeIgniter 4
En resumen
Sección titulada «En resumen»Los controladores en producción dependen de servicios concretos de NextPDF. Gestionan de forma explícita la jerarquía de excepciones documentada y emiten señales de observabilidad. El trabajo pesado de generación de PDF se desplaza fuera de la solicitud mediante la cola de CodeIgniter 4.
Resumen conceptual
Sección titulada «Resumen conceptual»CodeIgniter 4 resuelve los servicios del paquete a través de su localizador. El patrón de localizador de servicios consiste en entregar un contenedor a un objeto para que el propio objeto pueda obtener sus dependencias. Ese patrón está desaconsejado (PSR-11 §1.3, modal SHOULD NOT). Para seguir esa recomendación, se debe resolver cada servicio de NextPDF una sola vez en el límite del controlador y pasar hacia dentro el objeto concreto. No se debe pasar la clase Services —ni un contenedor— al código de dominio.
Todos los ejemplos de PHP declaran declare(strict_types=1); en su propia línea (PSR-12 §x1.x3.p34).
Superficie de la API
Sección titulada «Superficie de la API»| Aspecto de producción | Superficie verificada |
|---|---|
| Resolver servicios | Services::pdf(false), Services::pdfDocument(false), Services::documentFactory() |
| Construir la respuesta | PdfResponse::download() / inline() → DownloadResponse |
| Capturar los fallos | NextPDF\Exception\NextPdfException (tipo base del ecosistema) |
| Generación asíncrona | GeneratePdfJob registrado en Config\Queue::$jobHandlers |
| Validaciones de ruta y de invocable | GeneratePdfJob lanza InvalidArgumentException |
Controlador de producción: gestión de errores y observabilidad
Sección titulada «Controlador de producción: gestión de errores y observabilidad»Todas las excepciones que lanza el motor central extienden NextPDF\Exception\NextPdfException. Capturar ese único tipo cubre los fallos del núcleo y de las extensiones. El bloque catch mostrado registra el contexto y devuelve una respuesta de error definida, nunca deja un catch vacío.
<?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) devuelve una instancia de biblioteca nueva y un documento subyacente nuevo en cada llamada. Por lo tanto, las solicitudes concurrentes nunca comparten el estado del documento. Las pruebas funcionales del paquete verifican este comportamiento.
Tiempos de vida seguros para servicios en procesos de trabajo
Sección titulada «Tiempos de vida seguros para servicios en procesos de trabajo»Los registros de fuentes e imágenes son, por diseño, singletons que viven durante todo el proceso. El registro de fuentes se precalienta y se bloquea una sola vez. El registro de imágenes es una caché acotada que descarta las entradas usadas menos recientemente (LRU). En un proceso de trabajo de larga duración (el servidor spark de CodeIgniter, un runner de estilo RoadRunner o un trabajador de cola), este es el comportamiento previsto: los registros de alto costo persisten, mientras que cada documento es nuevo. No se debe solicitar un documento compartido (Services::pdfDocument(true)) en el código de una solicitud o de un trabajo; existe solo para reinicios en pruebas y compartiría contenido entre solicitudes.
Generación asíncrona con la cola de CodeIgniter
Sección titulada «Generación asíncrona con la cola de CodeIgniter»GeneratePdfJob ejecuta la generación de PDF fuera de la solicitud mediante codeigniter4/queue. El entorno de ejecución de la cola impone dos condiciones, y ambas deben configurarse correctamente.
1. Registrar el manejador del trabajo por nombre
Sección titulada «1. Registrar el manejador del trabajo por nombre»La cola resuelve un trabajo por una clave de nombre, no por una cadena de clase. El manejador de la cola valida el nombre del trabajo encolado contra las claves de Config\Queue::$jobHandlers. Rechaza los nombres desconocidos con CodeIgniter\Queue\Exceptions\QueueException. Registrar el trabajo en 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. Despachar por el nombre registrado
Sección titulada «2. Despachar por el nombre registrado»Encolar el trabajo usando el nombre registrado como segundo argumento. El primer argumento es el nombre de la cola. El tercer argumento es el arreglo de datos del trabajo.
<?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. Implementar el constructor en App\PdfBuilders
Sección titulada «3. Implementar el constructor en App\PdfBuilders»El trabajo restringe los invocables del constructor al espacio de nombres App\PdfBuilders y confina las rutas de salida a WRITEPATH/pdfs/. El constructor es un método estático. Recibe un Document nuevo y el arreglo de contexto, y devuelve el documento.
<?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; }}Ejecutar el proceso de trabajo
Sección titulada «Ejecutar el proceso de trabajo»php spark queue:work pdf-queueCada ejecución del trabajo parte de un documento nuevo mediante Services::pdfDocument(). Aplica el constructor y luego guarda el resultado en la ruta validada. Las pruebas del paquete verifican que dos ejecuciones consecutivas del trabajo no comparten el estado del documento.
Casos límite y problemas frecuentes
Sección titulada «Casos límite y problemas frecuentes»- Al encolar, la cola rechaza
GeneratePdfJob::classcomo nombre del trabajo porque no es la clave registrada'generate-pdf'. Siempre se debe encolar la clave dejobHandlers. - La cadena del constructor debe coincidir exactamente con
App\PdfBuilders\<Class>::<method>. Las funciones, otros espacios de nombres o las cargas útiles con prefijo o sufijo generanInvalidArgumentExceptionantes de que se ejecute cualquier código. - La ruta de salida debe resolverse dentro de
WRITEPATH/pdfs/y terminar en.pdf(sin distinguir mayúsculas de minúsculas). Se rechazan las rutas con recorrido de directorios y con prefijo de directorio hermano. codeigniter4/queuees una dependencia del paquete solo para desarrollo. Debe requerirse en la aplicación que ejecuta los procesos de trabajo.
Rendimiento
Sección titulada «Rendimiento»Los registros se crean una vez en cada proceso de trabajo. El costo de construir el documento escala con el contenido, no con el adaptador. Para trabajos por lotes grandes, es preferible usar la vía de la cola para que los procesos de trabajo de las solicitudes sigan respondiendo. Debe definirse un performance_budget en cualquier recipe que tenga un objetivo medible.
Notas de seguridad
Sección titulada «Notas de seguridad»El trabajo en cola es la superficie de mayor riesgo. Las cargas útiles de la cola pueden estar influidas por un atacante cuando el broker es accesible. La lista de permitidos de invocables y el confinamiento de rutas se tratan en /integrations/codeigniter/security-and-operations/ con los casos de rechazo verificados.
Conformidad
Sección titulada «Conformidad»- Los controladores reciben servicios concretos, no un contenedor, en consonancia con la recomendación sobre el localizador de servicios de PSR-11 §1.3.
Contexto comercial
Sección titulada «Contexto comercial»El núcleo de NextPDF es Apache-2.0. La salida firmada y PDF/A en los trabajos en cola requiere NextPDF Pro o Enterprise instalado en el entorno del proceso de trabajo. El paquete de CodeIgniter expone los métodos de servicio correspondientes. Devuelven null hasta que se instale el paquete Premium correspondiente. Consulta </get-license/?intent=codeigniter-async-signing>.
Véase también
Sección titulada «Véase también»- /integrations/codeigniter/quickstart/ — la versión mínima de estos controladores.
- /integrations/codeigniter/configuration/ — firma, TSA y configuración de rutas.
- /integrations/codeigniter/security-and-operations/ — modelo de amenazas de la cola y endurecimiento.
- /integrations/codeigniter/troubleshooting/ — modos de fallo de la cola y del descubrimiento.
- /integrations/codeigniter/integration/ — referencia de conexión y prueba de humo.