Przejdź do głównej zawartości

Wyzwalacze akcji i nasłuchiwacze zdarzeń

NextPDF emituje zdarzenia cyklu życia za pośrednictwem systemu w NextPDF\Event, zgodnego z PHP Standards Recommendation 14 (PSR-14). Zarejestruj nasłuchiwacz, wybierz priorytet i reaguj, gdy dokument zostaje utworzony, strona dodana, czcionka załadowana, rozpoczyna się podpisywanie lub szyfrowanie, zapisywane są bajty albo startuje generowanie danych wyjściowych. Zatrzymuj łańcuch tylko wtedy, gdy jest to konieczne.

Okno terminala
composer require nextpdf/core:^3

System zdarzeń ma dwie publiczne części. ListenerProvider mapuje każdą klasę zdarzenia na posortowaną listę wywoływalnych nasłuchiwaczy. EventDispatcher przechodzi przez tę listę i wywołuje każdy nasłuchiwacz w kolejności priorytetów. Obie klasy są final, dlatego rozszerzaj ich zachowanie przez kompozycję, a nie przez dziedziczenie.

Obie klasy są zgodne z PSR-14 dzięki kaczemu typowaniu. EventDispatcher::dispatch() używa sygnatury dispatch() z PSR-14 i zwraca zdarzenie po wykonaniu wszystkich nasłuchiwaczy. ListenerProvider::getListenersForEvent() używa sygnatury dostawcy z PSR-14. NextPDF nie wymaga pakietu PSR-14. Jeśli pakiet jest zainstalowany w projekcie, interfejsy nadal się zgadzają.

Dla autorów rozszerzeń istotne są dwa zachowania:

  • Nasłuchiwanie wieloznaczne. Aby rozwiązać nasłuchiwacze, dostawca przechodzi przez klasy nadrzędne i interfejsy zdarzenia. Powiąż nasłuchiwacz z klasą bazową AbstractEvent, aby obserwować każde zdarzenie cyklu życia. Powiąż go z interfejsem, aby objąć całą rodzinę.
  • Priorytet i propagacja. Nasłuchiwacze o wyższym priorytecie są wykonywane jako pierwsze. Przy równych priorytetach zachowana jest kolejność rejestracji. Każde zdarzenie rozszerzające AbstractEvent można zatrzymać. Nasłuchiwacz może wywołać stopPropagation(), a dyspozytor pomija wtedy pozostałe.

Dyspozytor ma szybką ścieżkę bez narzutu. Gdy dla klasy zdarzenia ani żadnej klasy nadrzędnej nie powiązano nasłuchiwacza, dispatch() zwraca wynik natychmiast po jednym sprawdzeniu hasListeners().

ZdarzeniePrzestrzeń nazwEmitowane, gdyStabilność
DocumentCreatedEventNextPDF\Event\DocumentKończy się konstruowanie dokumentueksperymentalne
PageAddedEventNextPDF\Event\DocumentStrona jest w pełni zainicjowanaeksperymentalne
ContentRenderedEventNextPDF\Event\ContentTreść jest renderowana na stronieeksperymentalne
FontLoadedEventNextPDF\Event\ContentRodzina i styl czcionki ładują się po raz pierwszyeksperymentalne
SignatureAppliedEventNextPDF\Event\SecurityBajty podpisu zostają osadzoneeksperymentalne
EncryptionAppliedEventNextPDF\Event\SecurityZostaje skonfigurowane szyfrowanieeksperymentalne
PdfSerializedEventNextPDF\Event\WriterKończy się serializacjaeksperymentalne
DocumentOutputEventNextPDF\Event\DocumentZa chwilę rozpocznie się dostarczanie danych wyjściowycheksperymentalne

Dyspozytor, dostawca, interfejs znacznikowy i klasa bazowa są stable (od 3.0.0). Ładunki zdarzeń są experimental. Ich argumenty konstruktora i właściwości readonly mogą się zmienić w wydaniu pomocniczym. Wydania poprawkowe wprowadzają wyłącznie dodatki. Opieraj się na nazwach właściwości ładunku z uwzględnieniem tego ograniczenia.

NextPDF\Event\ListenerProvider (stabilna, final):

MetodaZwracaPrzeznaczenie
addListener(string $eventClass, callable $listener, int $priority = 0)voidRejestruje nasłuchiwacz; nasłuchiwacze o wyższym priorytecie są wykonywane jako pierwsze. Zgłasza InvalidConfigException, gdy klasa jest pusta.
getListenersForEvent(EventInterface $event)list<callable>Rozwiązuje nasłuchiwacze, w tym rejestracje na klasach nadrzędnych i interfejsach.
hasListeners(string $eventClass)boolSprawdza hierarchię klas bez żadnego narzutu.
getListenerCount(string $eventClass)intZlicza tylko bezpośrednie rejestracje.
clearListeners()voidResetuje dostawcę.

NextPDF\Event\EventDispatcher (stabilna, final):

MetodaZwracaPrzeznaczenie
dispatch(EventInterface $event)EventInterfaceWywołuje nasłuchiwacze w kolejności priorytetów, respektuje zatrzymania propagacji i zwraca zdarzenie.
getListenerProvider()ListenerProviderUdostępnia dostawcę, aby dodawać nasłuchiwacze w czasie wykonywania.

Dokumenty emitujące zdarzenia korzystają z NextPDF\Event\EventAwareDocumentTrait. Jego metoda setEventDispatcher() podłącza dyspozytor do jednego dokumentu. Bez dyspozytora każdy pomocnik wysyłki pozostaje bezczynny.

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

Ten produkcyjny nasłuchiwacz audytowy ma wysoki priorytet, więc wykonuje się jako pierwszy; zapisuje ustrukturyzowane logi i dodaje na klasie bazowej obserwator obejmujący wszystkie zdarzenia, aby zapewnić kompletność.

<?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);
}
}
  • Klasy final. EventDispatcher i ListenerProviderfinal. Komponuj je; nie dziedzicz po nich.
  • Pusta klasa zdarzenia zgłasza wyjątek. addListener('', ...) zgłasza InvalidConfigException. Zawsze przekazuj stałą będącą nazwą klasy (class-string).
  • Koszt wieloznaczności. Nasłuchiwacz na AbstractEvent uruchamia się dla każdego zdarzenia. Nadawaj nasłuchiwaczom obejmującym wszystko niski priorytet i dbaj, aby były tanie.
  • Modyfikacja danych wyjściowych. DocumentOutputEvent przenosi bajty formatu Portable Document Format (PDF). Silnik odczytuje je ponownie po wysyłce. Jeśli zmienisz te bajty, zyskujesz dużą kontrolę, ale bierzesz na siebie duże ryzyko. Błędne przesunięcie bajtu uszkadza PDF i może zepsuć podpis. Domyślnie tylko obserwuj, chyba że odpowiadasz za deterministyczność wyniku i podpisy.
  • Brak dyspozytora, brak zdarzeń. Dokument bez dyspozytora ustawionego przez EventAwareDocumentTrait nie emituje żadnych zdarzeń. To zamierzona ścieżka bez narzutu, a nie błąd konfiguracji.

Szybka ścieżka sprowadza się do jednego sprawdzenia łańcucha klas nadrzędnych przez hasListeners(). Bez nasłuchiwaczy wysyłka jest niemal darmowa. Dostawca buforuje posortowaną listę nasłuchiwaczy dla każdej klasy zdarzenia i czyści ten bufor tylko wtedy, gdy nasłuchiwacze się zmieniają. Dbaj, aby nasłuchiwacze były nieblokujące, ponieważ działają bezpośrednio na ścieżce renderowania.

SignatureAppliedEvent i EncryptionAppliedEvent to kotwice audytu. Rejestruj nasłuchiwacze o wysokim priorytecie, aby zapisywać podpisywanie i szyfrowanie do magazynu z wykrywaniem manipulacji. Nie zatrzymuj łańcucha na zdarzeniu bezpieczeństwa, chyba że zamierzasz wyciszyć późniejsze nasłuchiwacze. Zatrzymanie go może po cichu wyłączyć punkty zaczepienia audytu, które działają później.

Ta strona nie zawiera żadnych twierdzeń normatywnych poza zgodnością z PSR-14. Ta zgodność opiera się wyłącznie na kaczym typowaniu i nie wymaga pakietu PSR-14.

NextPDF Enterprise dostarcza audytowane nasłuchiwacze zdarzeń podpisywania i szyfrowania, które zasilają dziennik audytu z wykrywaniem manipulacji. Ponieważ kontrakt nasłuchiwacza jest publicznym API zdarzeń, własne nasłuchiwacze mogą współistnieć z tymi z edycji Enterprise w ramach tego samego dostawcy.

Słownik definiuje terminy nasłuchiwacz zdarzeń, dyspozytor zdarzeń, dostawca nasłuchiwaczy i zdarzenie zatrzymywalne używane na tej stronie. Kanoniczne definicje znajdziesz w opublikowanym słowniku.