Ir al contenido

NextPDF para CodeIgniter 4

nextpdf/codeigniter conecta el motor PDF de NextPDF con una aplicación CodeIgniter 4 mediante la propia capa de Services del framework. Permite construir documentos PDF en controladores, jobs o comandos y devolverlos después como respuestas HTTP nativas de CodeIgniter.

Ventana de terminal
composer require nextpdf/codeigniter

El composer.json del paquete requiere php >=8.4 <9.0, nextpdf/core ^3.0 || ^5.2 y codeigniter4/framework ^4.6. También sugiere nextpdf/artisan, nextpdf/premium y codeigniter4/queue. La tabla completa de requisitos, paquetes opcionales y pasos de verificación está en /integrations/codeigniter/install/.

NextPDF es un motor PDF 2.0 para PHP 8.4. El motor central (nextpdf/core) es independiente del framework: no sabe nada de HTTP, enrutamiento ni cableado de dependencias. nextpdf/codeigniter es el adaptador que conecta el motor con una aplicación CodeIgniter 4. Con el adaptador instalado, no hace falta cablear manualmente los registries, las factories ni el manejo de respuestas.

El paquete añade cuatro cosas a una aplicación CodeIgniter 4:

  • Una clase Services (NextPDF\CodeIgniter\Config\Services) que CodeIgniter detecta automáticamente y que expone servicios con nombre: fontRegistry, imageRegistry, documentFactory, pdfDocument, pdf, tsaClient y pdfSigner.
  • Una biblioteca Pdf (NextPDF\CodeIgniter\Libraries\Pdf): una API de alto nivel para controladores. Envuelve un documento de un solo uso y lo convierte en una respuesta con una sola llamada.
  • Un helper PdfResponse (NextPDF\CodeIgniter\Http\PdfResponse) que produce un DownloadResponse de CodeIgniter para vista previa en línea o descarga. Adjunta un conjunto fijo de cabeceras de endurecimiento para la respuesta.
  • Dos funciones auxiliares globales, pdf() y pdf_document(). Se registran a través de la entrada de autocarga files de Composer y del Registrar del paquete.

El paquete también detecta extensiones opcionales de NextPDF al construir el documento. Cuando nextpdf/artisan está instalado y hay un binario de Chrome configurado, el documento incorpora el renderer de Chrome. Cuando NextPDF Pro está instalado, la salida PDF/A y la firma digital quedan disponibles a través de la misma superficie de Services. La detección es condicional y silenciosa. El paquete nunca requiere una extensión que no esté presente.

Por qué usar una clase Services y no un binding del contenedor

Sección titulada «Por qué usar una clase Services y no un binding del contenedor»

CodeIgniter 4 no incluye un contenedor de inyección de dependencias PSR-11. En su lugar, usa un localizador de servicios. Un localizador de servicios es una clase con métodos de fábrica estáticos, detectada por el framework, en la que cada método devuelve una instancia compartida o una nueva. PSR-11 trata explícitamente como desaconsejado el patrón de localizador de servicios —pasar un contenedor a un objeto para que el objeto recupere sus propias dependencias— (PSR-11 §1.3, modal SHOULD NOT). El paquete sigue la convención de localizador de CodeIgniter. Además, mantiene la superficie del localizador mínima y explícita: cada servicio es un método de fábrica con nombre y un parámetro bool $getShared, y quienes lo llaman reciben objetos concretos en lugar de un manejador del contenedor.

Este diseño mantiene la integración con CodeIgniter alineada con las integraciones de Laravel y Symfony. Cada una de esas integraciones expone los mismos servicios lógicos a través de las convenciones de su propio framework.

Punto de entradaTipoDevuelveVida útil
Services::fontRegistry()servicioFontRegistryInterfacecompartido (precalentado y luego bloqueado)
Services::imageRegistry()servicioImageRegistrycompartido (caché LRU acotada)
Services::documentFactory()servicioDocumentFactoryInterfacecompartido (sin estado)
Services::pdfDocument(false)servicioNextPDF\Core\Documentnuevo en cada llamada
Services::pdf(false)servicioNextPDF\CodeIgniter\Libraries\Pdfnuevo en cada llamada
Services::tsaClient()servicio?TsaClientcompartido; null cuando no hay URL de TSA
Services::pdfSigner(false)servicio?SignerInterfacenuevo; null cuando la firma está deshabilitada
pdf()helperPdfnuevo en cada llamada
pdf_document()helperDocumentnuevo en cada llamada
PdfResponse::inline() / download()estáticoDownloadResponsepor llamada
GeneratePdfJobjob de colauno por despacho

Un controlador devuelve un PDF en tres líneas. Services::pdf() produce una biblioteca Pdf nueva que envuelve un documento nuevo. Luego, download() produce un DownloadResponse de CodeIgniter.

<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\DownloadResponse;
use NextPDF\CodeIgniter\Config\Services;
final class InvoiceController extends BaseController
{
public function download(int $id): DownloadResponse
{
$pdf = Services::pdf();
$pdf->document()->addPage();
$pdf->document()->cell(0, 10, "Invoice #{$id}");
return $pdf->download("invoice-{$id}.pdf");
}
}

El recorrido ejecutable completo está en /integrations/codeigniter/quickstart/. Cubre el enrutamiento, la vista previa en línea y las variaciones de los helpers pdf() y pdf_document().

En producción, se debe solicitar una instancia no compartida con Services::pdf(false). Se debe capturar la única excepción base NextPDF\Exception\NextPdfException; todo fallo del núcleo y de las extensiones la extiende. El fallo debe registrarse con su contexto, en lugar de ocultar el error.

try {
$pdf = Services::pdf(false);
$pdf->document()->addPage();
$pdf->document()->cell(0, 10, "Invoice #{$id}");
return $pdf->download("invoice-{$id}.pdf");
} 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]);
}

El controlador de producción completo está en /integrations/codeigniter/production-usage/. Añade instrumentación de observabilidad, ciclos de vida seguros para workers y generación asíncrona.

  • Los registries de fuentes e imágenes son singletons con vida útil del proceso. Un documento nunca se comparte. pdfDocument y pdf devuelven una instancia nueva en cada llamada, de modo que una solicitud no pueda filtrar contenido a otra. Services::pdf(false) y pdf() devuelven ambos una biblioteca nueva que envuelve un documento nuevo.
  • El paquete requiere las extensiones de PHP mbstring y zlib. El registry de fuentes valida esto una vez por proceso. Si falta cualquiera de las dos extensiones, el registry de fuentes lanza un error en tiempo de ejecución que indica la extensión que falta.
  • El comportamiento de las extensiones opcionales depende de lo que esté instalado en la misma aplicación. Con solo nextpdf/core presente, las rutas de firma y de PDF/A devuelven null o se omiten. Nunca fallan de forma ruidosa.

La integración no añade ninguna sobrecarga medible más allá del propio motor. El registry de fuentes se analiza una vez y luego queda bloqueado. El registry de imágenes es una caché LRU acotada por el ajuste imageCacheMb (50 MB de forma predeterminada). El coste de construir el PDF lo determinan el motor central y el contenido del documento, no el adaptador. El presupuesto por página de este conjunto de documentación es de 1500 ms de tiempo real / 128 MB de pico. Las recipes reales fijan su propio presupuesto en el front-matter.

PdfResponse adjunta un conjunto fijo de cabeceras de respuesta a cada PDF que emite: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Content-Security-Policy: default-src 'none', X-Robots-Tag: noindex, nofollow y Referrer-Policy: no-referrer. Los nombres de archivo se sanean, y los nombres no ASCII se emiten con un parámetro extendido RFC 5987. El job de cola restringe los callables de construcción al espacio de nombres App\PdfBuilders y confina las rutas de salida a WRITEPATH/pdfs/. El modelo de amenazas completo está en /integrations/codeigniter/security-and-operations/.

  • La detección de módulos se basa en la autocarga PSR-4 de Composer. Un prefijo de espacio de nombres se asigna a un directorio base, y el nombre de clase completamente cualificado se asigna a una ruta de archivo (PSR-4 §x1.x3).
  • El diseño de Services sigue la guía sobre localizadores descrita en PSR-11 §1.3.

El núcleo de NextPDF es Apache-2.0. NextPDF Pro y NextPDF Enterprise proporcionan las firmas digitales, el archivado PDF/A y la incrustación de facturas electrónicas Factur-X. El paquete de CodeIgniter expone los métodos de servicio correspondientes. Esos métodos devuelven null hasta que el paquete Premium correspondiente esté instalado en la misma aplicación.

  • /integrations/codeigniter/install/ — instala y verifica el paquete.
  • /integrations/codeigniter/quickstart/ — tu primer PDF desde un controlador.
  • /integrations/codeigniter/configuration/ — cada clave de configuración.
  • /integrations/codeigniter/boot-and-discovery/ — cómo encuentra CodeIgniter la clase Services.
  • /integrations/codeigniter/integration/ — referencia de cableado y prueba de humo.