تخطَّ إلى المحتوى

مشغّلات الإجراءات ومستمعو الأحداث

يُطلق ⁨NextPDF⁩ أحداث دورة الحياة عبر نظام في NextPDF\Event متوافق مع توصية معايير ⁨PHP⁩ رقم 14 (⁨PSR-14⁩). سجِّل مستمعًا، واختر أولوية، وتفاعل عند إنشاء مستند، أو إضافة صفحة، أو تحميل خط، أو تشغيل التوقيع أو التشفير، أو كتابة وحدات البايت، أو بدء الإخراج. أوقف السلسلة فقط عند الحاجة.

Terminal window
composer require nextpdf/core:^3

يتكوّن نظام الأحداث من جزأين عامّين. يربط ListenerProvider كل فئة حدث بقائمة مرتَّبة من المستمعين القابلين للاستدعاء. يمرّ EventDispatcher على تلك القائمة ويستدعي كل مستمع وفق ترتيب الأولوية. كلتا الفئتين final، لذا وسِّع السلوك بالتركيب لا بالتوريث.

تتوافق كلتا الفئتين مع ⁨PSR-14⁩ عبر التحقق من السلوك (⁨duck typing⁩). يستخدم EventDispatcher::dispatch() توقيع dispatch() الخاص بـ ⁨PSR-14⁩ ويعيد الحدث بعد تشغيل كل مستمع. ويستخدم ListenerProvider::getListenersForEvent() توقيع المزوِّد الخاص بـ ⁨PSR-14.⁩ لا يتطلب ⁨NextPDF⁩ حزمة ⁨PSR-14.⁩ وإذا ثبَّتها مشروعك، فستبقى الواجهات متوافقة.

يهمّ مؤلفي الامتدادات سلوكان:

  • الاستماع الشامل (⁨Wildcard⁩). عند تحليل المستمعين، يمرّ المزوِّد على الفئات الأصل للحدث وواجهاته. اربط مستمعًا بالفئة الأساس AbstractEvent لمراقبة كل أحداث دورة الحياة. واربط مستمعًا بواجهة لالتقاط عائلة منها.
  • الأولوية والانتشار. تعمل الأولوية الأعلى أولًا. وتحافظ الأولويات المتساوية على ترتيب التسجيل. كل حدث يوسِّع AbstractEvent قابل للإيقاف. يمكن لمستمع أن يستدعي stopPropagation()، فيتخطى الموزِّع حينها البقية.

للموزِّع مسار سريع بلا تكلفة. عندما لا يكون أي مستمع مرتبطًا بفئة حدث أو بأي فئة أصل، يعود dispatch() فورًا بعد فحص واحد لـ hasListeners().

الحدثمساحة الاسميُطلَق عندالاستقرار
DocumentCreatedEventNextPDF\Event\Documentانتهاء بناء المستندتجريبي
PageAddedEventNextPDF\Event\Documentتهيئة صفحة كاملةتجريبي
ContentRenderedEventNextPDF\Event\Contentعرض المحتوى على صفحةتجريبي
FontLoadedEventNextPDF\Event\Contentتحميل عائلة خط ونمطه لأول مرةتجريبي
SignatureAppliedEventNextPDF\Event\Securityتضمين وحدات بايت التوقيعتجريبي
EncryptionAppliedEventNextPDF\Event\Securityتهيئة التشفيرتجريبي
PdfSerializedEventNextPDF\Event\Writerاكتمال التسلسلتجريبي
DocumentOutputEventNextPDF\Event\Documentأوشك تسليم الإخراج على البدءتجريبي

الموزِّع، والمزوِّد، وواجهة العلامة، والفئة الأساس stable (منذ 3.0.0). حمولات الأحداث experimental. قد تتغير وسائط مُنشئها وخصائصها للقراءة فقط في إصدار ثانوي. أما إصدارات التصحيح فتضيف فقط. اربط بأسماء خصائص الحمولة مع مراعاة هذا القيد.

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إعادة ضبط المزوِّد.

NextPDF\Event\EventDispatcher (مستقر، ⁨final⁩):

الطريقةتُعيدالغرض
dispatch(EventInterface $event)EventInterfaceاستدعِ المستمعين وفق ترتيب الأولوية، واحترم إيقافات الانتشار، وأعِد الحدث.
getListenerProvider()ListenerProviderالوصول إلى المزوِّد لإضافة مستمعين في وقت التشغيل.

تستخدم المستندات التي تُطلق الأحداث 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 وحدات بايت تنسيق المستندات المحمول (⁨PDF⁩). يقرؤها المحرك مجددًا بعد الإطلاق. إذا غيّرت تلك البايتات، فستحصل على تحكُّم واسع ومخاطرة واسعة. إزاحة بايت خاطئة تُفسد ملف ⁨PDF⁩ وقد تكسر التوقيع. يُفضَّل الاكتفاء بالمراقبة ما لم تكن تتحكم في النتيجة للحتمية والتواقيع.
  • بلا موزِّع، بلا أحداث. المستند الذي لم يُضبط له موزِّع عبر EventAwareDocumentTrait لا يُطلق أي أحداث. هذا هو المسار المقصود بلا تكلفة، وليس خطأً في الإعداد.

المسار السريع هو فحص واحد لـ hasListeners() عبر سلسلة الفئات الأصل. ومن دون مستمعين، يكون الإطلاق شبه مجاني. يخزّن المزوِّد مؤقتًا قائمة المستمعين المرتَّبة لكل فئة حدث، ولا يمسح ذلك التخزين المؤقت إلا عند تغيّر المستمعين. أبقِ المستمعين غير حاجبين لأنهم يعملون مضمّنين على مسار العرض.

SignatureAppliedEvent وEncryptionAppliedEvent هما مرسَيا التدقيق. سجِّل مستمعين بأولوية عالية لتدوين التوقيع والتشفير في مخزن مُقاوِم للعبث. لا توقف السلسلة عند حدث أمني ما لم تكن تنوي إسكات المستمعين اللاحقين. فقد يؤدي إيقافها إلى تعطيل خطافات التدقيق اللاحقة بصمت.

لا تطرح هذه الصفحة أي ادعاءات معيارية تتجاوز التوافق مع ⁨PSR-14.⁩ يقتصر هذا التوافق على التحقق من السلوك (⁨duck-type⁩) ولا يتطلب حزمة ⁨PSR-14.⁩

يأتي ⁨NextPDF Enterprise⁩ بمستمعين مُدقَّقين لأحداث التوقيع والتشفير يغذّون سجل تدقيق مُقاوِمًا للعبث. ولأن عقد المستمع هو واجهة برمجة تطبيقات الأحداث العمومية (⁨API⁩)، يمكن لمستمعيك الخاصين التعايش مع مستمعي ⁨Enterprise⁩ على المزوِّد نفسه.

يُعرِّف المسرد المصطلحات مستمع الأحداث وموزِّع الأحداث ومزوِّد المستمعين والحدث القابل للإيقاف المستخدمة في هذه الصفحة. راجع المسرد المنشور للتعريفات المعتمدة.