Ir al contenido

Vista general de la integración de NextPDF con Laravel

El paquete nextpdf/laravel conecta el motor de PDF de NextPDF con una aplicación de Laravel 12 y registra automáticamente los bindings del contenedor. Incluye un facade Pdf, un helper HTTP PdfResponse y un job en cola GeneratePdfJob. Laravel descubre el paquete de forma automática, por lo que no es necesario registrarlo manualmente.

Ventana de terminal
composer require nextpdf/laravel

La restricción de Composer declara nextpdf/core: ^3.0 || ^5.2. El paquete también requiere laravel/framework: ^12.0 y php: >=8.4 <9.0. Para ver el procedimiento completo, incluida la publicación de la configuración y las extensiones opcionales, consulta /integrations/laravel/install/.

El paquete actúa como una capa estrecha entre el contenedor de servicios de Laravel y el núcleo de NextPDF, independiente del framework. No reimplementa la generación de PDF. En su lugar, adapta el modelo del núcleo NextPDF\Core\Document al ciclo de vida, la configuración, las colas y las capas HTTP de Laravel.

El siguiente diagrama muestra cómo una solicitud fluye desde el código de la aplicación, a través del paquete, hasta los registros compartidos del núcleo.

NextPDF Laravel request and render flowA request resolves a fresh document from the container, which the package adapts onto the shared font and image registries before HTTP or queue output.

Your Laravel app

Pdf facade

Laravel service container

NextPdfServiceProvider (deferred)

DocumentFactory (singleton)

Document (fresh per resolve)

FontRegistry (singleton, locked)

ImageRegistry (singleton, LRU)

PdfResponse (HTTP)

GeneratePdfJob (queue worker)

NextPDF Laravel request and render flow

El mapa de autoload es una única entrada PSR-4. PSR-4 es la recomendación estándar de PHP para el autoloading, y su prefijo NextPDF\Laravel\ se mapea a src/Laravel/. En PSR-4, un prefijo de espacio de nombres corresponde a un directorio base, y el resto del nombre de la clase se traduce entonces en una ruta de archivo dentro de ese directorio (PSR-4 §3). Bajo este prefijo se encuentran cuatro clases de producción:

  • NextPDF\Laravel\NextPdfServiceProvider: registra los bindings y publica la configuración.
  • NextPDF\Laravel\Facades\Pdf: un proxy estático que resuelve un documento nuevo desde el contenedor.
  • NextPDF\Laravel\Http\PdfResponse: una factory para crear respuestas PDF en línea, de descarga y en streaming, con un conjunto fijo de cabeceras de seguridad.
  • NextPDF\Laravel\Jobs\GeneratePdfJob: un job encolable que construye y guarda un PDF en un worker.

El service provider implementa DeferrableProvider, así que registra sus bindings solo cuando se resuelve una de las entradas anunciadas. Este aplazamiento mantiene ligera la ruta de arranque del framework. El método provides() del proveedor enumera las entradas aplazadas, y el contenedor lee esta lista para mapear cada clave de vuelta al proveedor.

La resolución respeta el contrato del contenedor: cuando existe un binding, resolver el identificador devuelve la entrada registrada. PSR-11 es la recomendación estándar de PHP para la interoperabilidad de contenedores, y señala que dos llamadas sucesivas a get() con el mismo identificador pueden devolver valores diferentes, según la estrategia de binding (PSR-11 §1.1.2). NextPDF se apoya en este comportamiento de forma intencionada. Los registros son singletons, así que cada resolución devuelve la misma instancia; los documentos se resuelven mediante una factory, así que cada resolución devuelve una instancia nueva. Para ver la tabla completa de tiempos de vida de los bindings, consulta /integrations/laravel/boot-and-discovery/.

La arquitectura está pensada para workers de larga vida, como Octane, RoadRunner y Swoole. El registro de fuentes es un singleton con el mismo tiempo de vida que el proceso: el paquete lo precalienta una vez y luego lo bloquea, de modo que ninguna solicitud puede cambiar el estado compartido de las fuentes. El registro de imágenes es un singleton con el mismo tiempo de vida que el proceso, con una caché acotada de tipo «menos usado recientemente» (LRU). Como el paquete siempre crea un documento nuevo a partir de una DocumentFactory, el estado mutable por solicitud nunca se filtra entre solicitudes.

ClasePunto de entrada públicoDevuelvePropósito
NextPdfServiceProviderregister(), boot(), provides()void / arrayBindings del contenedor, publicación de la configuración, lista de entradas aplazadas
Facades\Pdfproxy estático (addPage(), cell(), save(), …)static / mixedResuelve PdfDocumentInterface en cada llamada
Http\PdfResponseinline(), download(), streamInline(), streamDownload()Response / StreamedResponseRespuestas HTTP con cabeceras de OWASP
Jobs\GeneratePdfJobdispatch(), handle(), then(), catch(), failed()PendingDispatch / void / selfGeneración de PDF en cola

Claves del contenedor vinculadas por el proveedor:

ClaveTiempo de vidaSe resuelve a
NextPDF\Contracts\FontRegistryInterface (alias FontRegistry)singleton, bloqueadoNextPDF\Typography\FontRegistry
NextPDF\Graphics\ImageRegistrysingleton, acotado por LRUImageRegistry
NextPDF\Contracts\DocumentFactoryInterface (alias DocumentFactory)singletonNextPDF\Core\DocumentFactory
Psr\Http\Client\ClientInterfacesingletonSecurityAwareHttpClient que envuelve a CurlHttpClient
NextPDF\Security\Timestamp\TsaClientcon ámbito acotadoTsaClient o null cuando no hay URL de TSA
NextPDF\Contracts\SignerInterfacefactoryDigitalSigner o null cuando la firma está deshabilitada
NextPDF\Contracts\PdfDocumentInterface (alias nextpdf)factoryNextPDF\Core\Document
NextPDF\Contracts\EInvoice\{Embedder,Validator,Profile,SchematronRunner}Interfacefactoryse resuelve solo cuando nextpdf/premium está instalado
resource: README.md Quick Start (verified against src/Laravel/Facades/Pdf.php)
<?php
declare(strict_types=1);
use NextPDF\Laravel\Facades\Pdf;
Pdf::addPage();
Pdf::cell(0, 10, 'Hello from Laravel', newLine: true);
Pdf::save(storage_path('app/hello.pdf'));

Para ver un ejemplo ejecutable limitado a un controlador, consulta /integrations/laravel/quickstart/.

El patrón de producción resuelve el contrato del documento desde el contenedor en lugar de hacerlo desde el facade, lo que deja el punto de llamada explícito y más fácil de probar. Para ver el controlador completo, con inyección de dependencias (DI) y manejo de errores, consulta /integrations/laravel/production-usage/.

resource: src/Laravel/Http/PdfResponse.php (download factory)
<?php
declare(strict_types=1);
use NextPDF\Contracts\PdfDocumentInterface;
use NextPDF\Laravel\Http\PdfResponse;
$document = app(PdfDocumentInterface::class);
$document->addPage();
$document->cell(0, 10, 'Invoice', newLine: true);
return PdfResponse::download($document, 'invoice.pdf');
  • El proveedor es aplazado, así que resolver una clave del contenedor no relacionada no arranca NextPDF. Los bindings aparecen solo cuando se solicita una de las entradas de provides().
  • SignerInterface y TsaClient se resuelven a null por diseño cuando no se han configurado la firma ni la autoridad de sellado de tiempo. El código debe comprobar si el resultado es null; no se debe asumir que existe una instancia.
  • Los bindings del contrato de factura electrónica siempre están registrados, pero se resuelven a implementaciones concretas de Premium que existen solo cuando nextpdf/premium está instalado. Resolverlos sin Premium provoca un error de clase no encontrada, y el error aparece en la primera resolución, no durante el arranque.
  • El facade devuelve un documento nuevo en cada resolución. Si dos llamadas estáticas a Pdf:: en la misma solicitud están separadas por Pdf::clearResolvedInstances(), ambas llamadas operan sobre documentos distintos.

El registro del proveedor se ejecuta en tiempo O(1). El proveedor vincula closures y no construye objetos pesados, así que el coste de construcción se aplaza hasta la primera resolución. El precalentamiento del registro de fuentes se ejecuta en tiempo O(f), donde f es el número de archivos de fuente precargados, y se ejecuta una vez por proceso de worker. Este momento de ejecución amortiza la latencia de la primera solicitud en los workers de larga vida. El presupuesto de memoria por página para esta vista general se registra en el campo de front-matter performance_budget.

PdfResponse aplica un conjunto fijo de cabeceras del Open Worldwide Application Security Project (OWASP). Las cabeceras son X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Content-Security-Policy: default-src 'none', X-Robots-Tag y Referrer-Policy: no-referrer. GeneratePdfJob valida su ruta de salida en el lado del worker, y esta comprobación mitiga las cargas serializadas que hayan sido manipuladas. Para ver el modelo de amenazas completo y la configuración de despliegue, consulta /integrations/laravel/security-and-operations/.

AfirmaciónFuenteCláusulareference_id
Semántica de resolución / tiempo de vida del contenedorPSR-11 Container§1.1.2
Mapeo del prefijo de autoload PSR-4PSR-4 Autoloader§3

Cuando nextpdf/premium está instalado, el mismo proveedor expone capacidades adicionales: firma digital (PAdES B-B), archivado PDF/A y bindings del contrato de factura electrónica. El proveedor las expone a través de las mismas claves del contenedor, así que el paquete Core documentado aquí no necesita ningún cambio de código para adoptar estas capacidades. Para obtener más detalles, consulta https://nextpdf.dev/get-license/?intent=laravel-signing.

  • /integrations/laravel/install/ — procedimiento de instalación y extensiones opcionales
  • /integrations/laravel/quickstart/ — ejemplo de controlador ejecutable
  • /integrations/laravel/configuration/ — cada clave de configuración, verificada contra config/nextpdf.php
  • /integrations/laravel/production-usage/ — controlador con DI, manejo de errores y colas
  • /integrations/laravel/boot-and-discovery/ — descubrimiento automático y tiempos de vida de los bindings
  • /integrations/laravel/security-and-operations/ — modelo de amenazas y configuración de despliegue