Gatilhos de ação e ouvintes de evento
Visão geral
Seção intitulada “Visão geral”O NextPDF dispara eventos de ciclo de vida por meio de um sistema em NextPDF\Event compatível com a PHP Standards Recommendation 14 (PSR-14). Registre um ouvinte, escolha uma prioridade e reaja quando um documento for criado, uma página for adicionada, uma fonte for carregada, a assinatura ou a criptografia for executada, bytes forem gravados ou a saída começar. Interrompa a cadeia somente quando isso for necessário.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3Visão conceitual
Seção intitulada “Visão conceitual”O sistema de eventos tem duas partes públicas. ListenerProvider mapeia cada classe de evento para uma lista ordenada de callables de ouvintes. EventDispatcher percorre essa lista e chama cada ouvinte na ordem de prioridade. As duas classes são final; portanto, estenda o comportamento por composição, não por herança.
As duas classes correspondem à PSR-14 por duck typing. EventDispatcher::dispatch() usa a assinatura dispatch() da PSR-14 e retorna o evento depois que cada ouvinte é executado. ListenerProvider::getListenersForEvent() usa a assinatura de provider da PSR-14. O NextPDF não exige o pacote PSR-14. Se o projeto o instalar, as interfaces ainda assim permanecerão alinhadas.
Dois comportamentos importam para autores de extensões:
- Escuta com curinga. Para resolver os ouvintes, o provider percorre as classes pai e as interfaces do evento. Vincule um ouvinte à classe base
AbstractEventpara observar todos os eventos de ciclo de vida. Vincule um ouvinte a uma interface para capturar uma família. - Prioridade e propagação. A prioridade mais alta é executada primeiro. Prioridades iguais preservam a ordem de registro. Todo evento que estende
AbstractEventé interrompível. Um ouvinte pode chamarstopPropagation(); nesse caso, o dispatcher ignora o restante.
O dispatcher tem um caminho rápido de custo zero. Quando nenhum ouvinte está vinculado a uma classe de evento nem a qualquer classe pai, dispatch() retorna imediatamente após uma única verificação hasListeners().
Eventos de ciclo de vida
Seção intitulada “Eventos de ciclo de vida”| Evento | Namespace | Disparado quando | Estabilidade |
|---|---|---|---|
DocumentCreatedEvent | NextPDF\Event\Document | A construção do documento termina | experimental |
PageAddedEvent | NextPDF\Event\Document | Uma página é totalmente inicializada | experimental |
ContentRenderedEvent | NextPDF\Event\Content | O conteúdo é renderizado em uma página | experimental |
FontLoadedEvent | NextPDF\Event\Content | Uma família e um estilo de fonte são carregados pela primeira vez | experimental |
SignatureAppliedEvent | NextPDF\Event\Security | Os bytes da assinatura são incorporados | experimental |
EncryptionAppliedEvent | NextPDF\Event\Security | A criptografia é configurada | experimental |
PdfSerializedEvent | NextPDF\Event\Writer | A serialização é concluída | experimental |
DocumentOutputEvent | NextPDF\Event\Document | A entrega da saída está prestes a começar | experimental |
O dispatcher, o provider, a interface marcadora e a classe base são stable (desde 3.0.0). Os payloads de evento são experimental. Os argumentos de construtor e as propriedades readonly deles podem mudar em uma versão menor. Versões de patch apenas adicionam novos itens. Vincule-se a nomes de propriedades de payload tendo essa restrição em mente.
Superfície da API
Seção intitulada “Superfície da API”NextPDF\Event\ListenerProvider (stable, final):
| Método | Retorna | Propósito |
|---|---|---|
addListener(string $eventClass, callable $listener, int $priority = 0) | void | Registra um ouvinte; a prioridade mais alta é executada primeiro. Lança InvalidConfigException quando a classe está vazia. |
getListenersForEvent(EventInterface $event) | list<callable> | Resolve os ouvintes, incluindo registros em classes pai e interfaces. |
hasListeners(string $eventClass) | bool | Verifica a hierarquia de classes sem overhead. |
getListenerCount(string $eventClass) | int | Conta apenas os registros diretos. |
clearListeners() | void | Redefine o provider. |
NextPDF\Event\EventDispatcher (stable, final):
| Método | Retorna | Propósito |
|---|---|---|
dispatch(EventInterface $event) | EventInterface | Invoca os ouvintes na ordem de prioridade, respeita as interrupções de propagação e retorna o evento. |
getListenerProvider() | ListenerProvider | Acessa o provider para adicionar ouvintes em tempo de execução. |
Os documentos que disparam eventos usam NextPDF\Event\EventAwareDocumentTrait. O método setEventDispatcher() dele conecta um dispatcher a um documento. Sem um dispatcher, todo auxiliar de dispatch permanece inativo.
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”<?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);Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”Este ouvinte de auditoria de produção usa prioridade alta para ser executado primeiro, grava logs estruturados e adiciona um catch-all na classe base para completar a cobertura.
<?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); }}Casos extremos e armadilhas
Seção intitulada “Casos extremos e armadilhas”- Classes final.
EventDispatchereListenerProvidersãofinal. Use composição; não herde delas. - Classe de evento vazia lança exceção.
addListener('', ...)lançaInvalidConfigException. Sempre passe uma constante de class-string. - Custo do curinga. Um ouvinte em
AbstractEventdispara para todos os eventos. Use prioridade baixa para ouvintes catch-all e mantenha-os leves. - Mutação da saída.
DocumentOutputEventcarrega os bytes do Portable Document Format (PDF). O motor os lê de volta após o dispatch. Se você alterar esses bytes, terá controle amplo e risco na mesma medida. Um deslocamento de byte errado corrompe o PDF e pode quebrar uma assinatura. Prefira apenas observar, a menos que você assuma o resultado em nome do determinismo e das assinaturas. - Sem dispatcher, sem eventos. Um documento sem dispatcher definido por meio de
EventAwareDocumentTraitnão dispara eventos. Este é o caminho de custo zero previsto, não um erro de configuração.
Desempenho
Seção intitulada “Desempenho”O caminho rápido é uma única verificação hasListeners() na cadeia de pais. Sem ouvintes, o dispatch é praticamente gratuito. O provider mantém em cache a lista ordenada de ouvintes por classe de evento e limpa esse cache apenas quando os ouvintes mudam. Mantenha os ouvintes não bloqueantes, pois eles são executados inline no caminho de renderização.
Notas de segurança
Seção intitulada “Notas de segurança”SignatureAppliedEvent e EncryptionAppliedEvent são as âncoras de auditoria. Registre ouvintes de prioridade alta para registrar a assinatura e a criptografia em um armazenamento à prova de adulteração. Não interrompa a cadeia em um evento de segurança, a menos que você pretenda silenciar os ouvintes posteriores. Interrompê-la pode desativar silenciosamente os hooks de auditoria executados depois.
Conformidade
Seção intitulada “Conformidade”Esta página não faz nenhuma afirmação normativa além da compatibilidade com a PSR-14. Essa compatibilidade ocorre apenas por duck-type e não requer o pacote PSR-14.
Contexto comercial
Seção intitulada “Contexto comercial”O NextPDF Enterprise fornece ouvintes auditados para eventos de assinatura e criptografia que alimentam um log de auditoria à prova de adulteração. Como o contrato do ouvinte é a application programming interface (API) pública de eventos, os seus próprios ouvintes podem coexistir com os ouvintes do Enterprise no mesmo provider.
Veja também
Seção intitulada “Veja também”- Visão geral da criação de extensões
- Fontes personalizadas
- Layout personalizado e interceptação de texto
- Contrato de provedor do Key Management Service (KMS)
- Regras de estabilidade da Service Provider Interface (SPI)
Contratos e módulos relacionados
Seção intitulada “Contratos e módulos relacionados”- Referência do módulo de eventos — a taxonomia dos eventos de ciclo de vida da PSR-14 e os detalhes internos do dispatcher.
- Referência dos contratos de assinatura — os contratos por trás de
SignatureAppliedEvent. - Regras de estabilidade da SPI — como o dispatcher stable e os payloads experimental são versionados.
- Fontes personalizadas — combina
FontLoadedEventcom o contrato do registro. - Visão geral da criação de extensões — a superfície pública completa da SPI.
O glossário define os termos event listener, event dispatcher, listener provider e stoppable event usados nesta página. Consulte o glossário publicado para as definições canônicas.