Ir al contenido

Arranque y descubrimiento automático de Laravel con NextPDF

Laravel descubre automáticamente NextPdfServiceProvider a partir del composer.json del paquete. El proveedor registra enlaces diferidos del contenedor y, en contexto de consola, publica el archivo de configuración. Esta página explica el mecanismo de descubrimiento y el tiempo de vida de cada enlace.

Ventana de terminal
composer require nextpdf/laravel
php artisan vendor:publish --tag=nextpdf-config

Cómo funciona el descubrimiento automático de Laravel

Sección titulada «Cómo funciona el descubrimiento automático de Laravel»

El paquete declara el proveedor y el alias de la fachada en el bloque extra.laravel de su propio composer.json:

resource: composer.json (extra.laravel)
{
"extra": {
"laravel": {
"providers": [
"NextPDF\\Laravel\\NextPdfServiceProvider"
],
"aliases": {
"Pdf": "NextPDF\\Laravel\\Facades\\Pdf"
}
}
}
}

Al ejecutar composer require, Laravel lee este bloque y registra el proveedor y el alias. No es necesario editar config/app.php ni bootstrap/providers.php a mano. El arreglo extra.laravel.providers registra automáticamente los proveedores de servicios, y extra.laravel.aliases registra automáticamente los alias de fachada (guía de desarrollo de paquetes de Laravel 12, https://laravel.com/docs/12.x/packages, consultado el 2026-05-18).

NextPdfServiceProvider implementa tanto DeferrableProvider como el ciclo de vida estándar register() / boot().

  1. register() fusiona la configuración del paquete bajo la clave nextpdf. Luego enlaza las entradas del contenedor: registro de fuentes, registro de imágenes, fábrica de documentos, cliente HTTP PSR-18, cliente de marca de tiempo, firmante, documento y contratos de factura electrónica. Cada enlace es un closure, por lo que en esta fase no se instancia ningún objeto pesado.
  2. boot() comprueba que las extensiones PHP mbstring y zlib estén cargadas. Registra la configuración publicable bajo la etiqueta nextpdf-config únicamente cuando runningInConsole() es verdadero.

El proveedor es diferido, por lo que register() se ejecuta solo cuando se resuelve una de las entradas que devuelve provides(). Resolver una clave del contenedor no relacionada no arranca NextPDF.

PSR-11 permite que dos llamadas sucesivas a get() con el mismo identificador devuelvan valores distintos según la estrategia de enlace (PSR-11 §1.1.2). El proveedor se apoya deliberadamente en este comportamiento:

Clave de enlaceTiempo de vidaNotas
FontRegistryInterface (+ alias FontRegistry)singleton, bloqueado tras el calentamientoSe precarga desde preload_fonts; queda bloqueado para que ninguna solicitud pueda mutarlo
ImageRegistrysingletonCaché LRU acotada y dimensionada por image_cache_mb; sin bloquear
DocumentFactoryInterface (+ alias DocumentFactory)singletonSin estado; comparte los dos registros
Psr\Http\Client\ClientInterfacesingletonCliente compatible con solicitudes simuladas que envuelve a un cliente curl; construido a partir de tsa.*
TsaClientscopednull cuando tsa.url está vacío
SignerInterfacefactorynull cuando la firma está deshabilitada o el certificado está vacío
PdfDocumentInterface (+ alias nextpdf)factoryNuevo NextPDF\Core\Document por cada resolución, con los metadatos predeterminados aplicados
EmbedderInterface, ValidatorInterface, ProfileInterface, SchematronRunnerInterfacefactoryResuelven a las clases concretas de Premium; fallan en la primera resolución sin nextpdf/premium

El enlace del documento aplica defaults.creator, defaults.language y (cuando no está vacío) defaults.author a cada documento nuevo. Cuando pdfa no es nulo, habilita PDF/A (Premium). Cuando la sección artisan está presente y existe una clase de fábrica para el navegador Chrome, aplica la configuración del renderer de Chrome.

En el contenedor, has() toma un único identificador de cadena (PSR-11 §1.1.2). Los contratos de factura electrónica están enlazados, por lo que has() devuelve verdadero para ellos incluso cuando Premium está ausente. La clase concreta faltante solo falla en el momento de la construcción.

Agregar el paquete al arreglo dont-discover de la aplicación y luego registrar el proveedor manualmente:

resource: application composer.json
{
"extra": {
"laravel": {
"dont-discover": ["nextpdf/laravel"]
}
}
}
resource: bootstrap/providers.php
<?php
declare(strict_types=1);
return [
App\Providers\AppServiceProvider::class,
NextPDF\Laravel\NextPdfServiceProvider::class,
];

Cada clave se resuelve en este orden: variable de entorno → valor publicado de config/nextpdf.php → valor predeterminado del paquete fusionado en register(). La mayoría de las claves aceptan un nombre NEXTPDF_* o un nombre de entorno heredado TCPDF_*. Preferir NEXTPDF_*.

Ventana de terminal
php artisan package:discover --ansi

Una línea que incluya nextpdf/laravel confirma el descubrimiento. Como el proveedor es diferido, los enlaces en sí no aparecen hasta la primera resolución. La línea de descubrimiento es la señal de éxito correcta.

  • La publicación de la configuración se registra solo en contexto de consola, por lo que una solicitud exclusivamente web nunca la activa. Ejecutar vendor:publish desde la CLI.
  • Junto con las claves de registro, fábrica, cliente HTTP, firmante, marca de tiempo y documento, provides() incluye las cuatro claves de contrato de factura electrónica.
  • Una instalación nueva puede parecer inerte hasta la primera resolución relevante. Es parte del diseño del proveedor diferido, no un fallo.

register() es O(1): solo closures. El calentamiento del registro de fuentes es O(f) respecto de las fuentes precargadas y se ejecuta una vez por proceso worker. Diferir el proveedor mantiene el coste de construcción de NextPDF fuera de la ruta de arranque del framework hasta que un enlace se utiliza realmente.

El diseño diferido reduce la superficie de ataque en el arranque. El registro de fuentes bloqueado impide la mutación del estado de fuentes entre solicitudes en workers de larga vida. Para una cobertura completa de amenazas, consultar /integrations/laravel/security-and-operations/.

AfirmaciónFuenteCláusulareference_id
Las resoluciones sucesivas pueden diferir según la estrategia de enlacePSR-11 Container§1.1.2
has() toma un identificador de cadenaPSR-11 Container§1.1.2

Los nombres de las claves de descubrimiento de Laravel se verificaron con la documentación oficial de paquetes de Laravel 12 (https://laravel.com/docs/12.x/packages, consultado el 2026-05-18).

Las clases concretas de Premium se resuelven a través de las mismas claves de enlace diferido. Es una capacidad opcional de Enterprise, y el paquete Core documentado aquí no requiere ningún cambio de código para adoptarla. Consultar https://nextpdf.dev/get-license/?intent=laravel-signing.

  • /integrations/laravel/install/ — instalación y publicación
  • /integrations/laravel/overview/ — arquitectura del paquete
  • /integrations/laravel/integration/ — guía práctica para el cableado de extremo a extremo
  • /integrations/laravel/configuration/ — cada clave de configuración