Aller au contenu

Créer une extension : vue d'ensemble de la SPI publique

NextPDF expose un petit ensemble soigneusement choisi de contrats publics, tous situés dans les espaces de noms NextPDF\Contracts et NextPDF\Event. En implémentant ces contrats, tu peux ajouter des polices, intercepter du texte, observer le cycle de vie du document ou fournir ton propre backend de signature, le tout sans forker le moteur.

Fenêtre de terminal
composer require nextpdf/core:^3

NextPDF sépare son interface publique de fournisseur de services (SPI) de son code interne. La SPI correspond à l’ensemble des types que tu es invité à implémenter ou à observer. Tout le reste est privé et peut changer sans préavis.

La SPI publique prend trois formes :

  • Contrats de registre. Des services qui vivent le temps du processus et que tu alimentes avant la création des documents ; FontRegistryInterface et ImageRegistryInterface en sont les principaux exemples. Tu enregistres les ressources et le moteur les lit.
  • Contrats de stratégie. Des points d’ancrage à usage unique que le moteur appelle pendant un rendu. TextPreprocessorInterface gère l’interception de texte au moment de la mise en page, et HtmlSecurityPolicyInterface contrôle l’accès aux fonctionnalités HTML. Tu fournis le comportement et le moteur le pilote.
  • Contrats de signature. Des backends cryptographiques. SignerInterface, HsmSignerInterface et DeferredSignerInterface te permettent de fournir la garde des clés et la production de signatures. Le moteur construit la structure CMS et ton code détient la clé.

Un système d’événements distinct, compatible PSR-14 et situé dans NextPDF\Event, gère l’observation. Les événements de cycle de vie te permettent de réagir à la création du document, à une nouvelle page, au chargement des polices, à la signature et à l’écriture de la sortie. Ils ne changent pas le comportement du moteur.

Chaque contrat porte une balise @stability dans la PHPDoc de sa source : stable, experimental ou deprecated. La balise et la promesse de rétrocompatibilité propres à chaque contrat t’indiquent l’ampleur des changements à prévoir. Consulte Règles de stabilité de la SPI pour la politique complète.

CapacitéContrat publicStabilité
Enregistrement et recherche de policesNextPDF\Contracts\FontRegistryInterfacestable (depuis la 1.7.0)
Mise en cache et décodage d’imagesNextPDF\Contracts\ImageRegistryInterfacestable (depuis la 2.0.0)
Interception de texte au moment de la mise en pageNextPDF\Contracts\TextPreprocessorInterfacestable (depuis la 1.9.0)
Contrôle d’accès aux fonctionnalités HTMLNextPDF\Contracts\HtmlSecurityPolicyInterfacestable (depuis la 3.1.0)
Câblage de la fabrique de documentsNextPDF\Contracts\DocumentFactoryInterfacestable (depuis la 1.7.0)
Signature synchroneNextPDF\Contracts\SignerInterfacestable (depuis la 1.0.0)
Signature adossée au matérielNextPDF\Contracts\HsmSignerInterfacestable (depuis la 1.0.0)
Signature différée et par lotsNextPDF\Contracts\DeferredSignerInterfaceexperimental (depuis la 3.0.0)
Horodatage RFC 3161NextPDF\Contracts\TimestampProviderInterfaceexperimental (depuis la 3.0.0)
Observation du cycle de vieNextPDF\Event\* (compatible PSR-14)dispatcher stable ; charges utiles experimental

Les éléments suivants sont internes. Ne les importe pas, ne les étends pas et n’en dépends pas :

  • Toute classe en dehors des espaces de noms NextPDF\Contracts et NextPDF\Event, sauf si sa PHPDoc porte une balise @stability.
  • Le code d’implémentation du moteur, comme l’analyseur HTML, le writer, le pipeline de mise en page et le sous-ensembleur de polices.
  • Les paquets NextPDF Pro et NextPDF Enterprise. Leurs classes internes ne font pas partie de la surface open source. Quand une édition payante livre une implémentation de la SPI, tu consommes le contrat public, pas son type interne.

La liste qui fait foi est la carte des contrats générée. Elle est reconstruite à partir de la source à chaque version. Traite la balise PHPDoc @stability de chaque fichier d’interface comme la source unique de vérité. Le tableau ci-dessus est une aide à la lecture.

Enregistre une police, puis observe le moment où elle se charge. Les deux étapes n’utilisent que des types publics.

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

Dans un worker de longue durée, construis les registres une seule fois au démarrage, verrouille-les, et injecte un dispatcher partagé via la fabrique de documents.

<?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);
}
}
  • Verrouillage du registre. Après FontRegistryInterface::lock(), les méthodes de modification lèvent LogicException. Ne le verrouille qu’une fois le préchargement terminé.
  • Incohérence de stabilité. Un contrat experimental peut changer dans une version mineure. Vérifie la stabilité déclarée d’un contrat avant d’en dépendre en production.
  • Discipline des espaces de noms. Un type en dehors de NextPDF\Contracts ou NextPDF\Event sans balise @stability est interne. Cela reste vrai même s’il est techniquement public.

La SPI a un coût nul lorsqu’elle n’est pas utilisée. Quand aucun listener n’est lié à une classe d’événement, le dispatcher d’événements retourne immédiatement après une seule vérification hasListeners(). Les registres ne contiennent que des données PHP pures et prennent en charge un préchargement au démarrage pour lisser la latence de la première requête.

Les contrats de signature constituent la surface sensible du point de vue de la sécurité. HsmSignerInterface exige que la clé privée ne quitte jamais la frontière matérielle. Ton implémentation doit respecter cette contrainte. Consulte le contrat de fournisseur KMS pour le contrat de backend de signature tiers et son modèle de menace.

Aucune affirmation normative n’est faite sur cette page de vue d’ensemble. La conformité propre à chaque contrat (PAdES, gestion des clés) est documentée sur les pages SPI concernées.

NextPDF Pro et NextPDF Enterprise fournissent des implémentations de production de plusieurs contrats de signature et de validation, dont la signature adossée à un système de gestion de clés. Tu t’appuies sur le contrat public tandis que l’édition fournit l’implémentation, de sorte que ton code reste portable d’une édition à l’autre.

Le glossaire définit SPI, point d’extension, balise de stabilité et promesse de rétrocompatibilité ; consulte le glossaire publié pour chaque définition canonique.