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

العقود: 41 واجهة عامة (SPI)

NextPDF\Contracts هي واجهة مزوِّد الخدمة (⁨SPI⁩) العامة: تضم 41 واجهة وتعدادًا ضمن src/Contracts/، ولكلٍ منها وسم @stability صريح ووعد بالتوافق العكسي. تعتمد حِزَم الامتدادات وجسور أُطُر العمل وإصدارا ⁨Pro⁩ و⁨Enterprise⁩ على هذه الأنواع، لا على الأصناف المحسوسة إطلاقًا.

Terminal window
composer require nextpdf/core:^3

يعرض المحرّك سطحين. الأصناف المحسوسة ضمن src/Core/ وsrc/Html/ وsrc/Writer/ لا تحمل أيَّ وعد بالتوافق، وقد تتغيّر بين الإصدارات الثانوية. أمّا فضاء الأسماء Contracts فيعمل بطريقة مختلفة: فهو مجموعة منتقاة من الأنواع ذات تواقيع مجمَّدة وفق مستوى الاستقرار الذي تُعلِنه. يعتمد كل ما هو خارج المحرّك على فضاء الأسماء هذا، ولا يعتمد على ما هو أعمق منه. يشمل ذلك جسور ⁨Laravel⁩ و⁨Symfony⁩ و⁨CodeIgniter⁩، وطبقة التوافق compat-tcpdf، و⁨NextPDF Server⁩، وإصدارَي ⁨Pro⁩ و⁨Enterprise.⁩

يُعلِن كل عقد عن أحد أربعة مستويات في توثيق ⁨PHPDoc⁩ الخاص به. لا يجيز العقد stable أيَّ تغيير كاسر في إصدار ثانوي أو تصحيحي. لا تُضاف طرائق جديدة إلا مع تنفيذات افتراضية. قد يتغيّر العقد experimental في إصدار ثانوي مع إشعار إهمال. ويُسمِّي العقد deprecated بديلَه. بعض هذه الأنواع عقود فقط، مثل StreamingWriterInterface وCursorInterface: النوع منشور ومجمَّد، لكن لا يُشحَن له بعدُ أيُّ تنفيذ إنتاجي.

قائمة مستويات الاستقرار المرجعية هي docs/extension-points.json (إصدار البيان 3.0.0، 67 نقطة منشورة عبر Contracts وEvent). يقرأ الاختبار الآلي القابل للتحقق tests/Unit/Contracts/StabilityContractTest.php ذلك البيان ويُفشِل البناء في خمس حالات: أولًا، غياب نوع مدرَج. ثانيًا، اختلاف نوع مُستنبَط عن البيان. ثالثًا، انحراف وسم @stability في توثيق ⁨PHPDoc⁩ عن البيان. رابعًا، غياب عقد واقع ضمن src/Contracts/ عن البيان. خامسًا، تسرُّب نوع @internal إليه. لذلك لا يمكن أن ينحرف سطح العقود دون أن يُكتشَف.

تقع العقود في تسعة مجالات، يغطّي كلًّا منها صفحة مخصَّصة: إنشاء المستندات، والتوقيع، وترميز الباركود، والطباعة، وسياسة الأمان، والاستخراج، وقابلية المراقبة، والتدفّق. يعكس هذا التقسيم طريقة تبنّي المحرّك. اعتمد على عقد المستند لتوليد ملفات تنسيق المستندات المحمولة (⁨PDF⁩). واعتمد على عقود التوقيع لإضافة توقيع. واعتمد على عقود سياسة الأمان لتقييد ⁨HTML⁩ غير الموثوق.

يتّبع اكتشاف التنفيذ الاختياري نمطًا واحدًا عبر المحرّك. تتحقّق النواة من وجود صنف محسوس عبر class_exists() ثم تُحوِّله إلى العقد. يحلّ LtvManagerInterface وPdfAManagerInterface تنفيذاتهما في ⁨Pro⁩ بهذه الطريقة. وهكذا تبقى النواة ⁨Apache-2.0⁩ دون أيِّ اعتماد صارم على شِفرة تجارية.

العقدالنوعالاستقرارمنذالمجال
PdfDocumentInterface⁨interface⁩⁨stable⁩1.0.0⁨document⁩
DocumentFactoryInterface⁨interface⁩⁨stable⁩1.7.0⁨document⁩
ResettableService⁨interface⁩⁨stable⁩1.7.0⁨document⁩
OutputDestination⁨enum⁩⁨stable⁩1.0.0⁨document⁩
Orientation⁨enum⁩⁨stable⁩1.0.0⁨document⁩
Alignment⁨enum⁩⁨stable⁩1.0.0⁨document⁩
SignerInterface⁨interface⁩⁨stable⁩1.0.0⁨signing⁩
HsmSignerInterface⁨interface⁩⁨stable⁩1.0.0⁨signing⁩
DeferredSignerInterface⁨interface⁩⁨experimental⁩3.0.0⁨signing⁩
TimestampProviderInterface⁨interface⁩⁨experimental⁩3.0.0⁨signing⁩
LtvManagerInterface⁨interface⁩⁨stable⁩1.10.0⁨signing⁩
CryptoPolicyInterface⁨interface⁩⁨stable⁩1.9.0⁨signing⁩
Barcode1DEncoderInterface⁨interface⁩⁨stable⁩1.0.0⁨barcode⁩
Barcode2DEncoderInterface⁨interface⁩⁨stable⁩1.0.0⁨barcode⁩
BarcodeEncoderInterface⁨interface⁩⁨stable⁩3.0.0⁨barcode⁩
Gs1DataParserInterface⁨interface⁩⁨stable⁩1.0.0⁨barcode⁩
FontRegistryInterface⁨interface⁩⁨stable⁩1.7.0⁨typography⁩
TextPreprocessorInterface⁨interface⁩⁨stable⁩1.9.0⁨typography⁩
HtmlSecurityPolicyInterface⁨interface⁩⁨stable⁩3.1.0⁨security-policy⁩
ExternalResourcePolicyInterface⁨interface⁩⁨stable⁩4.0.0⁨security-policy⁩
InspectorInterface⁨interface⁩⁨experimental⁩2.2.0⁨extraction⁩
EmbeddingServiceInterface⁨interface⁩⁨experimental⁩2.1.0⁨extraction⁩
VectorIndexInterface⁨interface⁩⁨experimental⁩2.1.0⁨extraction⁩
JobNotificationInterface⁨interface⁩⁨experimental⁩2.2.0⁨observability⁩
SpectrumInterface⁨interface⁩⁨experimental⁩2.1.0⁨observability⁩
StreamingWriterInterface⁨interface⁩⁨experimental⁩3.1.0⁨streaming⁩
CursorInterface⁨interface⁩⁨experimental⁩3.1.0⁨streaming⁩

يسرد الجدول العقود الأساسية. أمّا الأنواع المتبقّية، بما فيها كائنات نقل البيانات للكائنات القيمية (⁨DTOs⁩) (TextSegment، TextPreprocessResult)، وفضاء الأسماء الفرعي EInvoice، وتعدادات السلوك (DegradationPolicy، UnderlineStyle)، وعقود الاستيراد (ImportedFormObjectInterface، EmbeddedPdfObjectInterface، ChromeRenderResultInterface)، فهي موثَّقة في صفحات المجالات ضمن انظر أيضًا. القائمة الكاملة القابلة للقراءة آليًا هي docs/extension-points.json، وهي منعكسة إلى .ai/contracts-map.md.

examples/01-hello-world.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Hello World');
$doc->addPage();
$doc->setFont('helvetica', '', 24);
$doc->cell(0, 15, 'Hello, NextPDF!', newLine: true);
$doc->save(__DIR__ . '/output/01-hello-world.pdf');

تُعيد Document::createStandalone() كائن Document محسوسًا يُحقِّق PdfDocumentInterface. حدِّد الواجهة بوصفها تلميح نوع في خدماتك كي تبقى الأجزاء الداخلية للمحرّك قابلة للاستبدال.

examples/14-worker-factory.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Core\PdfFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
// Created once at process boot in a RoadRunner/Swoole/Octane worker.
$fontRegistry = new FontRegistry();
$imageRegistry = new ImageRegistry(maxCacheBytes: 50 * 1024 * 1024);
$documentFactory = new DocumentFactory($fontRegistry, $imageRegistry);
$factory = PdfFactory::new()
->withCompress(true)
->withDocumentFactory($documentFactory);
for ($request = 1; $request <= 3; $request++) {
$doc = $factory->create();
$doc->setTitle("Worker Request #{$request}");
$doc->addPage();
$doc->setFont('helvetica', 'B', 16);
$doc->cell(0, 12, "Worker Request #{$request}", newLine: true);
$doc->save(__DIR__ . "/output/14-worker-request-{$request}.pdf");
}

يُنفِّذ DocumentFactory الواجهة DocumentFactoryInterface. يحتفظ بمثيلَي FontRegistryInterface وImageRegistryInterface طوال عمر العملية ويحقنهما في كل كائن Document قابل للتخلّص، فيحلِّل العامل كل خط مرة واحدة عبر آلاف الطلبات.

  • النوع الذي يكون عقدًا فقط يُترجَم، لكنه لا يملك أيَّ سَنَد وقت التشغيل. لا يمكن أن ينجح تعبير new أمام StreamingWriterInterface أو CursorInterface لأنه لا يوجد صنف يُنفِّذهما بعد. تعامل معهما بوصفهما واجهة برمجة التطبيقات (⁨API⁩) مُصرَّحًا بها مسبقًا.
  • وسم @stability في توثيق ⁨PHPDoc⁩ هو مصدر الحقيقة لنوع مفرد. أمّا docs/extension-points.json فهو مصدر الحقيقة للمجموعة. عند تعارضهما يَفشَل StabilityContractTest. لا تُخفِ التعارض بتعديل أحد الطرفين.
  • لا تعني experimental أنها غير مستقرة عمليًا؛ بل تعني أن وعد التوافق أضعف. اقرأ حقل bc_promise لكل عقد في .ai/contracts-map.md قبل التثبيت عليه.
  • لا يكون الصنف @internal عقدًا أبدًا، حتى وإن أمكن للحِزَم الأخرى تقنيًا أن تُحيل إليه. يرفض اختبار الاستقرار أيَّ نوع @internal يظهر في البيان.
  • إضافة طريقة إلى واجهة stable تغيير كاسر للمنفِّذين ما لم تُشحَن الطريقة مع تنفيذ افتراضي. يضيف المحرّك القدرات عبر واجهات جديدة، لا عبر توسيع الواجهات القائمة.

البرمجة بمواجهة Contracts لا تضيف أيَّ كلفة قابلة للقياس وقت التشغيل: يُحلّ تلميح نوع الواجهة وقت الربط، لا في كل استدعاء. إن performance_budget لمثال العامل في هذه الصفحة هو 1500 ⁨ms⁩ زمن جداري و64 ⁨MB⁩ ذروة عبر ثلاثة مستندات. يهيمن تحليل الخطوط في الطلب الأول على تلك الميزانية. تُعيد الطلبات اللاحقة استخدام مخبأ السجل، وتهبط الأعمال المنسوبة إلى العقود إلى بضع مللي ثوانٍ فقط. نموذج الكلفة هو ⁨O⁩(1) لكل توزيع عقد؛ والعمل يقع في التنفيذ المحسوس، الموثَّق في كل صفحة مجال.

تُعد ⁨SPI⁩ حدًا أمنيًا أيضًا. HtmlSecurityPolicyInterface وExternalResourcePolicyInterface عقدان يرفضان افتراضيًا، ويقيّدان ما يمكن لـ ⁨HTML⁩ غير الموثوق فعلُه قبل أن يصل إلى مُصيِّر. يضبط CryptoPolicyInterface اختيار الخوارزمية وقوة المفتاح للتوقيع والتشفير. ولأن هذه عقود، يمكنك تزويد سياسة أكثر صرامة دون تفريع المحرّك. ثبِّت على المستوى stable لأيِّ سياسة ذات صلة بالأمان. قد تتغيّر بنية عقود السياسة التجريبية بين الإصدارات الثانوية. تتضمن صفحتا مجالَي التوقيع وسياسة الأمان نموذج التهديد الكامل والمراجع المعيارية.

لا تُطلِق هذه النظرة العامة أيَّ ادّعاء معياري مباشر؛ إذ تُصيِّر كل صفحة مجال كتلة citations الخاصة بها. تتطابق عقود التوقيع مع ⁨ISO 32000-2⁩ §12.8 (التواقيع الرقمية) و⁨ETSI EN 319 142⁩ (خطوط أساس ⁨PAdES⁩). ويتطابق مدير ⁨PDF/A⁩ مع ⁨ISO 19005-4.⁩ انظر صفحات التوقيع وسياسة الأمان والاستخراج للاطّلاع على جداول المطابقة على مستوى البنود.

يوفّر إصدارا ⁨Pro⁩ و⁨Enterprise⁩ الشِّفرة الإنتاجية وراء عدة عقود في النواة: LtvManagerInterface (التحقّق طويل الأمد)، وPdfAManagerInterface (إنفاذ ⁨PDF/A⁩)، وموقِّعا وحدة أمان العتاد (⁨HSM⁩) والتوقيع المؤجَّل، ومُرمِّزات الباركود، وعقدا التضمين وفهرس المتّجهات. تنشر النواة الواجهة وتُجمِّدها؛ وتشحن حزمة ⁨Premium⁩ التنفيذ. يُبقي هذا المحرّك مفتوح المصدر ⁨Apache-2.0⁩، ويمنح عمليات النشر التجارية ترقية جاهزة دون أيِّ تغيير في واجهة البرمجة.