Salta ai contenuti

Creazione di estensioni: panoramica dell'SPI pubblica

NextPDF espone un insieme piccolo e mirato di contratti pubblici, tutti contenuti nei namespace NextPDF\Contracts e NextPDF\Event. Implementando questi contratti, è possibile aggiungere font, intercettare il testo, osservare il ciclo di vita del documento o fornire un proprio back end di firma, il tutto senza creare un fork del motore.

Terminal window
composer require nextpdf/core:^3

NextPDF separa la propria service provider interface (SPI) pubblica dal codice interno. L’SPI è l’insieme dei tipi che possono essere implementati o osservati. Tutto il resto è privato e può cambiare senza preavviso.

L’SPI pubblica ha tre forme:

  • Contratti di registro. Servizi con durata pari a quella del processo, popolati prima della creazione dei documenti; FontRegistryInterface e ImageRegistryInterface ne sono gli esempi principali. Le risorse vengono registrate e il motore le legge.
  • Contratti di strategia. Hook con un singolo compito che il motore richiama durante il rendering. TextPreprocessorInterface gestisce l’intercettazione del testo in fase di impaginazione e HtmlSecurityPolicyInterface regola l’accesso alle funzionalità HTML. Si fornisce il comportamento e il motore ne pilota l’esecuzione.
  • Contratti di firma. Back end crittografici. SignerInterface, HsmSignerInterface e DeferredSignerInterface consentono di fornire la custodia delle chiavi e la produzione della firma. Il motore costruisce la struttura CMS e il codice utente detiene la chiave.

Un sistema di eventi separato, compatibile con PSR-14 e disponibile in NextPDF\Event, gestisce l’osservazione. Gli eventi del ciclo di vita consentono di reagire alla creazione del documento, a una nuova pagina, al caricamento dei font, alla firma e alla scrittura. Non modificano il comportamento del motore.

Ogni contratto include un tag @stability nel proprio PHPDoc di origine: stable, experimental o deprecated. Il tag, insieme alla promessa di compatibilità con le versioni precedenti specifica per ogni contratto, indica quanti cambiamenti aspettarsi. Per i criteri completi, consultare Regole di stabilità dell’SPI.

FunzionalitàContratto pubblicoStabilità
Registrazione e ricerca dei fontNextPDF\Contracts\FontRegistryInterfacestabile (da 1.7.0)
Memorizzazione nella cache e decodifica delle immaginiNextPDF\Contracts\ImageRegistryInterfacestabile (da 2.0.0)
Intercettazione del testo in fase di impaginazioneNextPDF\Contracts\TextPreprocessorInterfacestabile (da 1.9.0)
Controllo dell’accesso alle funzionalità HTMLNextPDF\Contracts\HtmlSecurityPolicyInterfacestabile (da 3.1.0)
Cablaggio della factory dei documentiNextPDF\Contracts\DocumentFactoryInterfacestabile (da 1.7.0)
Firma sincronaNextPDF\Contracts\SignerInterfacestabile (da 1.0.0)
Firma supportata da hardwareNextPDF\Contracts\HsmSignerInterfacestabile (da 1.0.0)
Firma differita e in batchNextPDF\Contracts\DeferredSignerInterfacesperimentale (da 3.0.0)
Marcatura temporale RFC 3161NextPDF\Contracts\TimestampProviderInterfacesperimentale (da 3.0.0)
Osservazione del ciclo di vitaNextPDF\Event\* (compatibile con PSR-14)dispatcher stabile; payload sperimentali

I seguenti elementi sono interni. Non importarli, non estenderli e non dipendere da essi:

  • Qualsiasi classe esterna ai namespace NextPDF\Contracts e NextPDF\Event, a meno che il relativo PHPDoc non includa un tag @stability.
  • Implementazioni concrete del motore, come il parser HTML, il writer, la pipeline di impaginazione e il subsetter dei font.
  • I pacchetti NextPDF Pro e NextPDF Enterprise. Le loro classi interne non fanno parte della superficie open source. Quando un’edizione a pagamento distribuisce un’implementazione dell’SPI, utilizzare il contratto pubblico, non il tipo interno.

L’elenco autorevole è la mappa dei contratti generata. Viene rigenerata dal codice sorgente a ogni release. Considerare il tag PHPDoc @stability in ogni file di interfaccia come l’unica fonte attendibile. La tabella precedente è un supporto alla lettura.

Registrare un font e poi osservare quando viene caricato. Entrambi i passaggi utilizzano esclusivamente tipi pubblici.

<?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);

In un worker a lunga esecuzione, creare i registri una sola volta all’avvio, bloccarli e iniettare un dispatcher condiviso tramite la factory dei documenti.

<?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);
}
}
  • Blocco del registro. Dopo FontRegistryInterface::lock(), i metodi di modifica lanciano LogicException. Eseguire il blocco solo al termine del warmup.
  • Discordanza di stabilità. Un contratto experimental può cambiare in una release minore. Verificare la stabilità dichiarata di un contratto prima di dipendere da esso in produzione.
  • Disciplina dei namespace. Un tipo esterno a NextPDF\Contracts o NextPDF\Event privo di tag @stability è interno. Ciò vale anche se tecnicamente è public.

L’SPI ha costo zero quando non viene utilizzata. Quando a una classe di evento non è associato alcun listener, il dispatcher di eventi restituisce immediatamente il controllo dopo un singolo controllo hasListeners(). I registri contengono dati PHP puri e supportano il warmup all’avvio, così da distribuire la latenza della prima richiesta.

I contratti di firma rappresentano la superficie sensibile dal punto di vista della sicurezza. HsmSignerInterface richiede che la chiave privata non lasci mai il confine hardware. Una propria implementazione deve rispettare tale requisito. Per il contratto del back end di firma di terze parti e il relativo modello delle minacce, consultare il contratto del provider KMS.

Questa pagina panoramica non contiene affermazioni normative. La conformità specifica per ogni contratto (PAdES, gestione delle chiavi) è documentata nelle relative pagine dell’SPI.

NextPDF Pro e NextPDF Enterprise forniscono implementazioni di produzione di diversi contratti di firma e validazione, inclusa la firma supportata da un key management system. Il codice dipende dal contratto pubblico mentre l’edizione fornisce l’implementazione, in modo che rimanga portabile tra le edizioni.

Il glossario definisce SPI, extension point, stability tag e backward-compatibility promise; per le definizioni canoniche, consultare il glossario pubblicato.