ข้ามไปยังเนื้อหา

ตัวกระตุ้นการทำงานและตัวรับฟังเหตุการณ์

NextPDF ส่งเหตุการณ์ในวงจรชีวิตผ่านระบบ NextPDF\Event ที่เข้ากันได้กับ PHP Standards Recommendation 14 (PSR-14) คุณสามารถลงทะเบียนตัวรับฟัง เลือกลำดับความสำคัญ และตอบสนองเมื่อมีการสร้างเอกสาร เพิ่มหน้า โหลดฟอนต์ ดำเนินการลงนามหรือเข้ารหัสลับ เขียนไบต์ หรือเริ่มส่งเอาต์พุต หยุดลำดับการทำงานเฉพาะเมื่อจำเป็นเท่านั้น

Terminal window
composer require nextpdf/core:^3

ระบบเหตุการณ์มีส่วนสาธารณะสองส่วน ListenerProvider จับคู่คลาสเหตุการณ์แต่ละคลาสกับรายการตัวรับฟัง callable ที่เรียงลำดับแล้ว EventDispatcher วนผ่านรายการนั้นและเรียกตัวรับฟังแต่ละตัวตามลำดับความสำคัญ คลาสทั้งสองเป็น final จึงควรขยายพฤติกรรมด้วยการประกอบแทนการสืบทอดเป็นคลาสย่อย

คลาสทั้งสองตรงกับ PSR-14 โดยใช้ duck typing EventDispatcher::dispatch() ใช้ลายเซ็น dispatch() ของ PSR-14 และคืนค่าเหตุการณ์หลังจากตัวรับฟังทุกตัวทำงานเสร็จ ListenerProvider::getListenersForEvent() ใช้ลายเซ็นของ provider ตาม PSR-14 NextPDF ไม่จำเป็นต้องใช้แพ็กเกจ PSR-14 หากโปรเจกต์ติดตั้งแพ็กเกจนั้นไว้ อินเทอร์เฟซก็ยังสอดคล้องกัน

มีพฤติกรรมสองอย่างที่สำคัญสำหรับผู้พัฒนาส่วนขยาย:

  • การรับฟังแบบไวลด์การ์ด ระหว่างการค้นหาตัวรับฟัง provider จะวนผ่านคลาสแม่และอินเทอร์เฟซของเหตุการณ์ ผูกตัวรับฟังกับคลาสฐาน AbstractEvent เพื่อเฝ้าดูทุกเหตุการณ์ในวงจรชีวิต หรือผูกตัวรับฟังกับอินเทอร์เฟซเพื่อจับเหตุการณ์ทั้งตระกูล
  • ลำดับความสำคัญและการแพร่กระจาย ลำดับความสำคัญที่สูงกว่าจะทำงานก่อน ลำดับความสำคัญที่เท่ากันจะคงลำดับการลงทะเบียนไว้ ทุกเหตุการณ์ที่ขยายจาก AbstractEvent สามารถหยุดได้ ตัวรับฟังสามารถเรียก stopPropagation() ได้ หลังจากนั้นตัวจัดส่งจะข้ามตัวรับฟังที่เหลือ

ตัวจัดส่งมีเส้นทางด่วนแบบไม่มีต้นทุน เมื่อไม่มีตัวรับฟังผูกกับคลาสเหตุการณ์หรือคลาสแม่ใดๆ dispatch() จะคืนค่าทันทีหลังจากตรวจสอบ hasListeners() เพียงครั้งเดียว

เหตุการณ์เนมสเปซส่งเมื่อเสถียรภาพ
DocumentCreatedEventNextPDF\Event\Documentสร้างเอกสารเสร็จสิ้นexperimental
PageAddedEventNextPDF\Event\Documentกำหนดค่าเริ่มต้นของหน้าเสร็จสมบูรณ์experimental
ContentRenderedEventNextPDF\Event\Contentเรนเดอร์เนื้อหาไปยังหน้าแล้วexperimental
FontLoadedEventNextPDF\Event\Contentโหลดตระกูลฟอนต์และสไตล์เป็นครั้งแรกexperimental
SignatureAppliedEventNextPDF\Event\Securityมีการฝังไบต์ของลายเซ็นexperimental
EncryptionAppliedEventNextPDF\Event\Securityมีการกำหนดค่าการเข้ารหัสลับexperimental
PdfSerializedEventNextPDF\Event\Writerทำให้เป็นอนุกรมเสร็จสมบูรณ์experimental
DocumentOutputEventNextPDF\Event\Documentกำลังจะเริ่มส่งมอบเอาต์พุตexperimental

ตัวจัดส่ง, provider, อินเทอร์เฟซตัวบ่งชี้ และคลาสฐานเป็น stable (ตั้งแต่ 3.0.0) เพย์โหลดของเหตุการณ์เป็น experimental อาร์กิวเมนต์ตัวสร้างและคุณสมบัติแบบ readonly ของเพย์โหลดอาจเปลี่ยนแปลงได้ในรุ่นย่อย รุ่นแพตช์มีเฉพาะการเพิ่มเติมเท่านั้น ให้ผูกกับชื่อคุณสมบัติของเพย์โหลดโดยคำนึงถึงข้อจำกัดนี้

NextPDF\Event\ListenerProvider (เสถียร, 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รีเซ็ต provider

NextPDF\Event\EventDispatcher (เสถียร, final):

เมท็อดคืนค่าวัตถุประสงค์
dispatch(EventInterface $event)EventInterfaceเรียกใช้ตัวรับฟังตามลำดับความสำคัญ เคารพการหยุดแพร่กระจาย และคืนค่าเหตุการณ์
getListenerProvider()ListenerProviderเข้าถึง provider เพื่อเพิ่มตัวรับฟังระหว่างรันไทม์

เอกสารที่ส่งเหตุการณ์ใช้ NextPDF\Event\EventAwareDocumentTrait เมท็อด setEventDispatcher() เชื่อมตัวจัดส่งเข้ากับเอกสารหนึ่งฉบับ เมื่อไม่มีตัวจัดส่ง ตัวช่วยส่งเหตุการณ์ทุกตัวจะไม่ทำงานใดๆ

<?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 มีไบต์ Portable Document Format (PDF) มาด้วย หลังจากส่งแล้ว เอนจินจะอ่านไบต์เหล่านั้นกลับมา หากคุณเปลี่ยนไบต์เหล่านั้น คุณจะได้อำนาจควบคุมสูง แต่ความเสี่ยงก็สูงตาม ออฟเซ็ตไบต์ที่ผิดจะทำให้ PDF เสียหายและอาจทำให้ลายเซ็นเสียได้ ควรเลือกเพียงการเฝ้าสังเกต เว้นแต่คุณเป็นผู้รับผิดชอบความกำหนดได้แน่นอนของเอาต์พุตและลายเซ็นเอง
  • ไม่มีตัวจัดส่ง ไม่มีเหตุการณ์ เอกสารที่ไม่มีการตั้งตัวจัดส่งผ่าน EventAwareDocumentTrait จะไม่ส่งเหตุการณ์ใด นี่เป็นเส้นทางแบบไม่มีต้นทุนที่ออกแบบไว้ ไม่ใช่ข้อผิดพลาดในการตั้งค่า

เส้นทางด่วนคือการตรวจสอบ hasListeners() บนสายลำดับคลาสแม่เพียงครั้งเดียว เมื่อไม่มีตัวรับฟัง การส่งแทบไม่มีต้นทุน provider จะแคชรายการตัวรับฟังที่เรียงลำดับแล้วต่อคลาสเหตุการณ์ และล้างแคชนั้นเฉพาะเมื่อมีการเปลี่ยนแปลงตัวรับฟัง ควรทำให้ตัวรับฟังไม่บล็อกการทำงาน เพราะตัวรับฟังทำงานแบบอินไลน์บนเส้นทางการเรนเดอร์

SignatureAppliedEvent และ EncryptionAppliedEvent เป็นจุดเชื่อมต่อสำหรับการตรวจสอบ ลงทะเบียนตัวรับฟังลำดับความสำคัญสูงเพื่อบันทึกการลงนามและการเข้ารหัสลับลงในที่จัดเก็บแบบตรวจพบการดัดแปลงได้ อย่าหยุดลำดับการทำงานบนเหตุการณ์ด้านความปลอดภัย เว้นแต่คุณตั้งใจจะปิดการทำงานของตัวรับฟังลำดับถัดไป การหยุดลำดับการทำงานอาจปิดการทำงานของฮุกการตรวจสอบที่ตามมาอย่างเงียบๆ

หน้านี้ไม่ได้กล่าวอ้างเชิงบรรทัดฐานใดๆ นอกเหนือจากความเข้ากันได้กับ PSR-14 ความเข้ากันได้นั้นเป็นแบบ duck-type เท่านั้นและไม่จำเป็นต้องใช้แพ็กเกจ PSR-14

NextPDF Enterprise มาพร้อมตัวรับฟังที่ได้รับการตรวจสอบสำหรับเหตุการณ์ลายเซ็นและการเข้ารหัสลับ ซึ่งป้อนข้อมูลให้ล็อกการตรวจสอบแบบตรวจพบการดัดแปลงได้ เนื่องจากสัญญาของตัวรับฟังอยู่ที่ application programming interface (API) ของเหตุการณ์สาธารณะ ตัวรับฟังของคุณเองจึงสามารถใช้งานร่วมกับตัวรับฟังของ Enterprise บน provider เดียวกันได้

อภิธานศัพท์อธิบายคำว่า event listener, event dispatcher, listener provider และ stoppable event ที่ใช้ในหน้านี้ โปรดดูคำนิยามมาตรฐานในอภิธานศัพท์ที่เผยแพร่แล้ว