Ir al contenido

Creación de extensiones: visión general de la SPI pública

NextPDF expone un conjunto reducido y deliberado de contratos públicos, todos ubicados en los espacios de nombres NextPDF\Contracts y NextPDF\Event. Al implementar estos contratos, se pueden agregar fuentes, interceptar texto, observar el ciclo de vida del documento o proporcionar un backend de firma propio, todo sin bifurcar el motor.

Ventana de terminal
composer require nextpdf/core:^3

NextPDF separa su interfaz pública de proveedor de servicios (SPI) de su código interno. La SPI es el conjunto de tipos que pueden implementarse u observarse. Todo lo demás es privado y puede cambiar sin previo aviso.

La SPI pública tiene tres formas:

  • Contratos de registro. Servicios que viven durante todo el proceso y se rellenan antes de crear documentos; FontRegistryInterface e ImageRegistryInterface son los ejemplos principales. Se registran los recursos y el motor los lee.
  • Contratos de estrategia. Enganches de un solo trabajo que el motor invoca durante un renderizado. TextPreprocessorInterface se encarga de interceptar texto en tiempo de maquetación, y HtmlSecurityPolicyInterface controla las funciones de HTML. Se aporta el comportamiento y el motor lo ejecuta.
  • Contratos de firma. Backends criptográficos. SignerInterface, HsmSignerInterface y DeferredSignerInterface permiten aportar la custodia de claves y la producción de la firma. El motor construye la estructura CMS y el código de la extensión conserva la clave.

Un sistema de eventos independiente, compatible con PSR-14 y ubicado en NextPDF\Event, se encarga de la observación. Los eventos del ciclo de vida permiten reaccionar a la creación del documento, a una página nueva, a la carga de fuentes, a la firma y a la escritura del resultado. No cambian el comportamiento del motor.

Cada contrato lleva una etiqueta @stability en el PHPDoc de su código fuente: stable, experimental o deprecated. La etiqueta y la promesa de compatibilidad con versiones anteriores de cada contrato indican cuánto cambio cabe esperar. Consultar Reglas de estabilidad de la SPI para conocer la política completa.

CapacidadContrato públicoEstabilidad
Registro y búsqueda de fuentesNextPDF\Contracts\FontRegistryInterfacestable (desde 1.7.0)
Almacenamiento en caché y decodificación de imágenesNextPDF\Contracts\ImageRegistryInterfacestable (desde 2.0.0)
Intercepción de texto en tiempo de maquetaciónNextPDF\Contracts\TextPreprocessorInterfacestable (desde 1.9.0)
Control de funciones de HTMLNextPDF\Contracts\HtmlSecurityPolicyInterfacestable (desde 3.1.0)
Cableado de la fábrica de documentosNextPDF\Contracts\DocumentFactoryInterfacestable (desde 1.7.0)
Firma síncronaNextPDF\Contracts\SignerInterfacestable (desde 1.0.0)
Firma respaldada por hardwareNextPDF\Contracts\HsmSignerInterfacestable (desde 1.0.0)
Firma diferida y por lotesNextPDF\Contracts\DeferredSignerInterfaceexperimental (desde 3.0.0)
Marcas de tiempo con RFC 3161NextPDF\Contracts\TimestampProviderInterfaceexperimental (desde 3.0.0)
Observación del ciclo de vidaNextPDF\Event\* (compatible con PSR-14)despachador stable; cargas útiles experimental

Los siguientes elementos son internos. No importarlos, heredarlos ni depender de ellos:

  • Cualquier clase fuera de los espacios de nombres NextPDF\Contracts y NextPDF\Event, salvo que su PHPDoc lleve una etiqueta @stability.
  • Código concreto del motor, como el analizador de HTML, el escritor, la canalización de maquetación y el subdivisor de fuentes.
  • Los paquetes NextPDF Pro y NextPDF Enterprise. Sus clases internas no forman parte de la superficie de código abierto. Cuando una edición de pago incluye una implementación de la SPI, se consume el contrato público, no su tipo interno.

La lista canónica es el mapa de contratos generado. Se regenera a partir del código fuente en cada versión. La etiqueta PHPDoc @stability de cada archivo de interfaz debe tratarse como la única fuente de verdad. La tabla anterior sirve como ayuda de lectura.

Registrar una fuente y observar después cuándo se carga. Ambos pasos usan únicamente tipos públicos.

<?php
declare(strict_types=1);
use NextPDF\Contracts\FontRegistryInterface;
use NextPDF\Event\Content\FontLoadedEvent;
use NextPDF\Event\EventDispatcher;
use NextPDF\Event\ListenerProvider;
/** @var FontRegistryInterface $fonts */
$fonts->register('/srv/fonts/Inter-Regular.ttf', 'Inter');
$listeners = new ListenerProvider();
$listeners->addListener(
FontLoadedEvent::class,
static function (FontLoadedEvent $event): void {
\error_log("Font loaded: {$event->family} {$event->style}");
},
);
$dispatcher = new EventDispatcher($listeners);

En un worker de larga duración, construir los registros una sola vez al arrancar, bloquearlos e inyectar un despachador compartido a través de la fábrica de documentos.

<?php
declare(strict_types=1);
use NextPDF\Contracts\DocumentFactoryInterface;
use NextPDF\Contracts\FontRegistryInterface;
use NextPDF\Event\EventDispatcher;
use NextPDF\Event\ListenerProvider;
use Psr\Log\LoggerInterface;
final class DocumentBootstrap
{
public function __construct(
private readonly FontRegistryInterface $fonts,
private readonly DocumentFactoryInterface $factory,
private readonly LoggerInterface $logger,
) {}
public function warmup(): EventDispatcher
{
$this->fonts->warmup([
'/srv/fonts/Inter-Regular.ttf',
'/srv/fonts/Inter-Bold.ttf',
]);
$this->fonts->lock();
$listeners = new ListenerProvider();
$listeners->addListener(
\NextPDF\Event\Security\SignatureAppliedEvent::class,
fn (object $event): mixed => $this->logger->info('Signature applied'),
);
return new EventDispatcher($listeners);
}
}
  • Bloqueo del registro. Después de FontRegistryInterface::lock(), los métodos de modificación lanzan LogicException. Bloquear el registro solo cuando el calentamiento previo haya terminado.
  • Discrepancia de estabilidad. Un contrato experimental puede cambiar en una versión menor. Comprobar la estabilidad declarada de un contrato antes de depender de él en producción.
  • Disciplina de espacios de nombres. Un tipo fuera de NextPDF\Contracts o NextPDF\Event sin etiqueta @stability es interno. Esto sigue aplicando incluso si técnicamente es public.

La SPI tiene costo cero cuando no se usa. Cuando no hay ningún oyente vinculado a una clase de evento, el despachador de eventos devuelve de inmediato tras una sola comprobación de hasListeners(). Los registros almacenan datos PHP puros y admiten un calentamiento previo al arrancar para repartir la latencia de la primera solicitud.

Los contratos de firma son la superficie sensible a la seguridad. HsmSignerInterface exige que la clave privada nunca salga del límite del hardware. La implementación debe respetar ese límite. Consultar el contrato del proveedor de KMS para conocer el contrato del backend de firma de terceros y su modelo de amenazas.

En esta página de visión general no se hacen afirmaciones normativas. La conformidad de cada contrato (PAdES, gestión de claves) se documenta en las páginas de la SPI correspondientes.

NextPDF Pro y NextPDF Enterprise proporcionan implementaciones de producción de varios contratos de firma y validación, incluida la firma respaldada por un sistema de gestión de claves. Se depende del contrato público mientras la edición aporta la implementación, de modo que el código se mantiene portátil entre ediciones.

El glosario define SPI, punto de extensión, etiqueta de estabilidad y promesa de compatibilidad con versiones anteriores; consultar el glosario publicado para conocer cada definición canónica.