アクショントリガーとイベントリスナー
NextPDF は、NextPDF\Event 内の PSR-14 互換システムを通じてライフサイクルイベントを発火します。リスナーは優先順位付きで登録できます。ドキュメントの作成、新規ページ、フォントの読み込み、署名、暗号化、書き出し、出力に応答し、必要に応じてチェーンを停止できます。
インストール
「インストール」という見出しのセクションcomposer require nextpdf/core:^3概念の概要
「概念の概要」という見出しのセクションイベントシステムは、公開された 2 つの部分で構成されます。ListenerProvider は、イベントクラスをソート済みのリスナー callable リストにマッピングします。EventDispatcher はそのリストをたどり、各リスナーを優先順位順に呼び出します。どちらのクラスも final であるため、サブクラス化ではなくコンポジションで拡張してください。
どちらのクラスもダックタイピングで PSR-14 に適合します。EventDispatcher::dispatch() は PSR-14 の dispatch() シグネチャに適合し、すべてのリスナーの実行後にイベントを返します。ListenerProvider::getListenersForEvent() は PSR-14 のプロバイダーシグネチャに適合します。NextPDF は PSR-14 パッケージを必須とはしませんが、プロジェクトに導入されている場合でも、インターフェイスは引き続き一致します。
拡張機能の作成者が押さえるべき動作が 2 つあります。
- ワイルドカードリスニング。 プロバイダーはリスナー解決時に、イベントの親クラスとそのインターフェイスをたどります。すべてのライフサイクルイベントを監視するには、リスナーを
AbstractEvent基底クラスにバインドします。関連する一群をまとめて捕捉するには、インターフェイスにバインドします。 - 優先順位と伝播。 優先順位の高いリスナーから先に実行されます。同じ優先順位では登録順が維持されます。
AbstractEventを継承するすべてのイベントは停止可能です。リスナーはstopPropagation()を呼び出せます。その場合、ディスパッチャーは残りのリスナーをスキップします。
ディスパッチャーにはゼロコストの高速パスがあります。イベントクラスまたはいずれかの親にリスナーがバインドされていない場合、dispatch() は 1 回の hasListeners() チェックの後にただちに戻ります。
ライフサイクルイベント
「ライフサイクルイベント」という見出しのセクション| イベント | 名前空間 | 発火タイミング | 安定性 |
|---|---|---|---|
DocumentCreatedEvent | NextPDF\Event\Document | ドキュメント構築完了時 | experimental |
PageAddedEvent | NextPDF\Event\Document | ページ完全初期化時 | experimental |
ContentRenderedEvent | NextPDF\Event\Content | ページへのコンテンツレンダリング時 | experimental |
FontLoadedEvent | NextPDF\Event\Content | フォントファミリーとスタイルの初回読み込み時 | experimental |
SignatureAppliedEvent | NextPDF\Event\Security | 署名バイト埋め込み時 | experimental |
EncryptionAppliedEvent | NextPDF\Event\Security | 暗号化構成時 | experimental |
PdfSerializedEvent | NextPDF\Event\Writer | シリアル化完了時 | experimental |
DocumentOutputEvent | NextPDF\Event\Document | 出力配信前 | experimental |
ディスパッチャー、プロバイダー、マーカーインターフェイス、基底クラスは、3.0.0 以降 stable です。イベントペイロードは experimental です。これらのコンストラクター引数と readonly プロパティは、マイナーリリースで変更される可能性があります。パッチリリースでは追加のみが行われます。この点を踏まえて、ペイロードのプロパティ名にバインドしてください。
API サーフェス
「API サーフェス」という見出しのセクションNextPDF\Event\ListenerProvider(stable、final):
| メソッド | 戻り値 | 目的 |
|---|---|---|
addListener(string $eventClass, callable $listener, int $priority = 0) | void | リスナー登録。優先順位の高いリスナーから先に実行。空のクラスでは InvalidConfigException をスロー。 |
getListenersForEvent(EventInterface $event) | list<callable> | 親やインターフェイスの登録を含むリスナー解決。 |
hasListeners(string $eventClass) | bool | クラス階層全体にわたるオーバーヘッドゼロのチェック。 |
getListenerCount(string $eventClass) | int | 直接登録のみのカウント。 |
clearListeners() | void | プロバイダーのリセット。 |
NextPDF\Event\EventDispatcher(stable、final):
| メソッド | 戻り値 | 目的 |
|---|---|---|
dispatch(EventInterface $event) | EventInterface | リスナーの優先順位順の呼び出し、伝播停止の尊重、イベントの返却。 |
getListenerProvider() | ListenerProvider | 実行時にリスナーを追加するためのプロバイダーアクセス。 |
イベントを発火するドキュメントでは NextPDF\Event\EventAwareDocumentTrait を使用します。その setEventDispatcher() メソッドは、1 つのドキュメントにディスパッチャーを接続します。ディスパッチャーがない場合、すべてのディスパッチヘルパーは何もしません。
コードサンプル — クイックスタート
「コードサンプル — クイックスタート」という見出しのセクション<?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);コードサンプル — 本番環境
「コードサンプル — 本番環境」という見出しのセクションこれは本番環境向けの監査リスナーです。最初に実行されるよう高い優先順位を設定し、構造化形式でログを記録し、トレースの網羅性のために基底クラスへキャッチオールを追加します。
<?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); }}エッジケースと注意点
「エッジケースと注意点」という見出しのセクション- final クラス。
EventDispatcherとListenerProviderはfinalです。サブクラス化せず、コンポジションを使用してください。 - 空のイベントクラスはスローします。
addListener('', ...)はInvalidConfigExceptionをスローします。常に class-string 定数を渡してください。 - ワイルドカードのコスト。
AbstractEventに登録したリスナーは、すべてのイベントで呼び出されます。キャッチオールリスナーには低い優先順位を設定し、処理は軽量に保ってください。 - 出力の変更。
DocumentOutputEventは PDF バイトを保持します。エンジンはディスパッチ後にそのバイトを読み戻します。このバイトを変更すると広範な制御が可能になりますが、実際のリスクも伴います。バイトオフセットを誤ると PDF が破損し、署名が壊れる可能性があります。決定性と署名のために結果を自身で管理する場合を除き、観測にとどめることをお勧めします。 - ディスパッチャーがなければイベントもありません。
EventAwareDocumentTraitを通じてディスパッチャーが設定されていないドキュメントは、イベントを発火しません。これは意図されたゼロコストのパスであり、セットアップエラーではありません。
パフォーマンス
「パフォーマンス」という見出しのセクション高速パスは、hasListeners() による親チェーンの 1 回のチェックです。リスナーがなければ、ディスパッチのコストはほぼ発生しません。プロバイダーは、ソート済みのリスナーリストをイベントクラスごとにキャッシュします。このキャッシュは、変更があったときにのみクリアされます。リスナーはノンブロッキングに保ってください。リスナーはレンダリングパス上でインライン実行されます。
セキュリティに関する注意
「セキュリティに関する注意」という見出しのセクションSignatureAppliedEvent と EncryptionAppliedEvent は監査の起点です。署名と暗号化を改ざん検知可能なストアに記録するために、優先順位の高いリスナーを登録してください。後続のリスナーを無効にする意図がない限り、セキュリティイベントでチェーンを停止しないでください。停止すると、後続の監査フックが気づかないうちに無効になることがあります。
このページでは、PSR-14 互換性を超える規範的な主張は行いません。ここでの PSR-14 互換性はダックタイピングのみによるもので、PSR-14 パッケージを必要としません。
商用コンテキスト
「商用コンテキスト」という見出しのセクションNextPDF Enterprise は、署名イベントと暗号化イベントを改ざん検知可能な監査ログへ送る監査済みリスナーを提供します。リスナーのコントラクトは公開イベント API であるため、独自のリスナーは Enterprise のリスナーと同じプロバイダー上で共存できます。
関連するコントラクトとモジュール
「関連するコントラクトとモジュール」という見出しのセクション- Event モジュールリファレンス — PSR-14 ライフサイクルイベントの分類とディスパッチャー内部。
- 署名コントラクトリファレンス —
SignatureAppliedEventの基盤となるコントラクト。 - SPI 安定性ルール — stable なディスパッチャーと experimental なペイロードのバージョン管理方式。
- カスタムフォント —
FontLoadedEventとレジストリのコントラクトの組み合わせ。 - 拡張機能の作成の概要 — 公開 SPI サーフェス全体。
用語集では、このページで使用しているイベントリスナー、イベントディスパッチャー、リスナープロバイダー、停止可能イベントを定義しています。正式な定義については、公開されている用語集を参照してください。