Trigger di azione e listener di eventi
In breve
Sezione intitolata “In breve”NextPDF emette eventi del ciclo di vita tramite un sistema compatibile con PSR-14 in NextPDF\Event. Registrare un listener con una priorità per reagire alla creazione di un documento, all’aggiunta di una pagina, al caricamento dei font, alla firma, alla cifratura, alla scrittura o all’output. Interrompere la catena quando necessario.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/core:^3Panoramica concettuale
Sezione intitolata “Panoramica concettuale”Il sistema di eventi è composto da due elementi pubblici. ListenerProvider associa una classe di evento a un elenco ordinato di callable listener. EventDispatcher percorre tale elenco e richiama ogni listener in ordine di priorità. Entrambe le classi sono final; conviene quindi estenderne il comportamento tramite composizione, non tramite sottoclasse.
Entrambe le classi sono conformi a PSR-14 tramite duck typing. EventDispatcher::dispatch() corrisponde alla firma PSR-14 dispatch() e restituisce l’evento dopo l’esecuzione di tutti i listener. ListenerProvider::getListenersForEvent() corrisponde alla firma del provider PSR-14. NextPDF non richiede il pacchetto PSR-14, ma se il progetto lo include, le interfacce risultano comunque allineate.
Due comportamenti sono rilevanti per gli autori di estensioni:
- Ascolto con carattere jolly. Per risolvere i listener, il provider percorre le classi padre dell’evento e le interfacce implementate. Associare un listener alla classe base
AbstractEventper osservare ogni evento del ciclo di vita. Associare un listener a un’interfaccia per intercettare una famiglia di eventi. - Priorità e propagazione. La priorità più alta viene eseguita per prima. Le priorità uguali mantengono l’ordine di registrazione. Ogni evento che estende
AbstractEventè interrompibile. Un listener può richiamarestopPropagation(). Il dispatcher salta quindi i listener restanti.
Il dispatcher dispone di un percorso rapido a costo zero. Quando nessun listener è associato a una classe di evento o a una classe padre, dispatch() restituisce immediatamente dopo un solo controllo hasListeners().
Eventi del ciclo di vita
Sezione intitolata “Eventi del ciclo di vita”| Evento | Namespace | Emesso quando | Stabilità |
|---|---|---|---|
DocumentCreatedEvent | NextPDF\Event\Document | Un documento completa la costruzione | sperimentale |
PageAddedEvent | NextPDF\Event\Document | Una pagina viene completamente inizializzata | sperimentale |
ContentRenderedEvent | NextPDF\Event\Content | Il contenuto viene sottoposto a rendering su una pagina | sperimentale |
FontLoadedEvent | NextPDF\Event\Content | Una famiglia e uno stile di font vengono caricati per la prima volta | sperimentale |
SignatureAppliedEvent | NextPDF\Event\Security | I byte della firma vengono incorporati | sperimentale |
EncryptionAppliedEvent | NextPDF\Event\Security | La cifratura viene configurata | sperimentale |
PdfSerializedEvent | NextPDF\Event\Writer | La serializzazione viene completata | sperimentale |
DocumentOutputEvent | NextPDF\Event\Document | Prima della consegna dell’output | sperimentale |
Il dispatcher, il provider, l’interfaccia marcatore e la classe base sono stable (a partire dalla 3.0.0). I payload degli eventi sono experimental. I loro argomenti del costruttore e le proprietà readonly possono cambiare in una release minore. Una patch release aggiunge soltanto elementi. Collegarsi ai nomi delle proprietà del payload tenendo conto di questo aspetto.
Superficie API
Sezione intitolata “Superficie API”NextPDF\Event\ListenerProvider (stable, final):
| Metodo | Restituisce | Scopo |
|---|---|---|
addListener(string $eventClass, callable $listener, int $priority = 0) | void | Registra un listener; la priorità più alta viene eseguita per prima. Genera InvalidConfigException in presenza di una classe vuota. |
getListenersForEvent(EventInterface $event) | list<callable> | Risolve i listener, incluse le registrazioni di classi padre e interfacce. |
hasListeners(string $eventClass) | bool | Controllo a overhead zero lungo l’intera gerarchia di classi. |
getListenerCount(string $eventClass) | int | Conta solo le registrazioni dirette. |
clearListeners() | void | Reimposta il provider. |
NextPDF\Event\EventDispatcher (stable, final):
| Metodo | Restituisce | Scopo |
|---|---|---|
dispatch(EventInterface $event) | EventInterface | Richiama i listener in ordine di priorità; rispetta l’interruzione della propagazione; restituisce l’evento. |
getListenerProvider() | ListenerProvider | Restituisce il provider per aggiungere listener in fase di runtime. |
I documenti che emettono eventi utilizzano NextPDF\Event\EventAwareDocumentTrait. Il relativo metodo setEventDispatcher() collega un dispatcher a un singolo documento. In assenza di un dispatcher, ciascun helper di dispatch non esegue alcuna operazione.
Esempio di codice — Avvio rapido
Sezione intitolata “Esempio di codice — Avvio rapido”<?php
declare(strict_types=1);
use NextPDF\Event\EventDispatcher;use NextPDF\Event\ListenerProvider;use NextPDF\Event\Security\SignatureAppliedEvent;
$listeners = new ListenerProvider();$listeners->addListener( SignatureAppliedEvent::class, static function (SignatureAppliedEvent $event): void { \error_log("Signed at level {$event->signatureLevel} by {$event->signerName}"); }, priority: 100,);
$dispatcher = new EventDispatcher($listeners);Esempio di codice — Produzione
Sezione intitolata “Esempio di codice — Produzione”Questo listener di audit è pensato per la produzione. Utilizza una priorità elevata per essere eseguito per primo, registra i dati in forma strutturata e aggiunge un listener catch-all sulla classe base per completezza.
<?php
declare(strict_types=1);
use NextPDF\Event\AbstractEvent;use NextPDF\Event\EventDispatcher;use NextPDF\Event\ListenerProvider;use NextPDF\Event\Security\EncryptionAppliedEvent;use NextPDF\Event\Security\SignatureAppliedEvent;use Psr\Log\LoggerInterface;
final class SecurityAuditSubscriber{ public function __construct(private readonly LoggerInterface $logger) {}
public function register(ListenerProvider $listeners): EventDispatcher { $listeners->addListener( SignatureAppliedEvent::class, function (SignatureAppliedEvent $event): void { $this->logger->info('signature.applied', [ 'level' => $event->signatureLevel, 'signer' => $event->signerName, ]); }, priority: 1000, );
$listeners->addListener( EncryptionAppliedEvent::class, function (EncryptionAppliedEvent $event): void { $this->logger->info('encryption.applied', [ 'algorithm' => $event->algorithm, ]); }, priority: 1000, );
// Catch-all: observe every lifecycle event for trace completeness. $listeners->addListener( AbstractEvent::class, fn (AbstractEvent $event): mixed => $this->logger->debug('lifecycle', ['event' => $event->getEventName()]), priority: -1000, );
return new EventDispatcher($listeners); }}Casi limite e insidie
Sezione intitolata “Casi limite e insidie”- Classi final.
EventDispatchereListenerProvidersonofinal. Usare la composizione, non le sottoclassi. - Una classe di evento vuota genera un’eccezione.
addListener('', ...)generaInvalidConfigException. Passare sempre una costante class-string. - Costo del carattere jolly. Un listener su
AbstractEventviene attivato per ogni evento. Assegnare ai listener catch-all una priorità bassa. Mantenerli leggeri. - Mutazione dell’output.
DocumentOutputEventtrasporta i byte del PDF. Il motore li rilegge dopo il dispatch. La modifica di tali byte offre un ampio controllo e comporta un rischio reale. Un offset di byte errato danneggia il PDF e può invalidare una firma. È preferibile limitarsi all’osservazione, a meno di assumersi la responsabilità del risultato in termini di determinismo e firme. - Nessun dispatcher, nessun evento. Un documento privo di un dispatcher impostato tramite
EventAwareDocumentTraitnon emette alcun evento. È il percorso a costo zero previsto. Non si tratta di un errore di configurazione.
Prestazioni
Sezione intitolata “Prestazioni”Il percorso rapido consiste in un unico controllo hasListeners() sulla catena delle classi padre. In assenza di listener, il dispatch è praticamente gratuito. Il provider memorizza nella cache l’elenco ordinato dei listener per ciascuna classe di evento. Svuota la cache solo in caso di modifica. Mantenere i listener non bloccanti. Vengono eseguiti inline nel percorso di rendering.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”SignatureAppliedEvent ed EncryptionAppliedEvent sono i punti di ancoraggio per l’audit. Registrare listener ad alta priorità per tracciare la firma e la cifratura in un archivio a prova di manomissione. Non interrompere la catena su un evento di sicurezza, a meno che non si intenda disattivare i listener successivi. L’interruzione può disattivare silenziosamente gli hook di audit eseguiti in seguito.
Conformità
Sezione intitolata “Conformità”In questa pagina non viene formulata alcuna dichiarazione normativa oltre alla compatibilità con PSR-14, che è basata esclusivamente su duck typing e non richiede il pacchetto PSR-14.
Contesto commerciale
Sezione intitolata “Contesto commerciale”NextPDF Enterprise include listener verificati per gli eventi di firma e cifratura che alimentano un registro di audit a prova di manomissione. Il contratto dei listener è l’API pubblica degli eventi; di conseguenza, i listener personalizzati coesistono con quelli di Enterprise sullo stesso provider.
Vedere anche
Sezione intitolata “Vedere anche”- Panoramica della creazione di estensioni
- Font personalizzati
- Layout personalizzato e intercettazione del testo
- Contratto del provider KMS
- Regole di stabilità SPI
Contratti e moduli correlati
Sezione intitolata “Contratti e moduli correlati”- Riferimento del modulo Event — la tassonomia degli eventi del ciclo di vita PSR-14 e i meccanismi interni del dispatcher.
- Riferimento dei contratti di firma — i contratti alla base di
SignatureAppliedEvent. - Regole di stabilità SPI — come vengono gestite le versioni del dispatcher stabile e dei payload sperimentali.
- Font personalizzati — collega
FontLoadedEvental contratto del registry. - Panoramica della creazione di estensioni — l’intera superficie SPI pubblica.
Il glossario definisce i termini event listener, event dispatcher, listener provider e stoppable event utilizzati in questa pagina. Per le definizioni canoniche, consultare il glossario pubblicato.