الترحيل من TCPDF 6.x إلى NextPDF
لمحة سريعة
قسم بعنوان «لمحة سريعة»رحّل وفق ترتيب واضح. انتقل أولاً إلى محرّك NextPDF بأقل قدر ممكن من التغيير. تحقّق مما يعمل بالفعل. دقّق فيما لا يعمل. أصلح كل موضع استدعاء. ثم أزل المحوّل. تدعم طبقة التوافق الخطوات من الثانية إلى الرابعة، لكنها ليست الوجهة النهائية.
تقدّم لك هذه الصفحة الاستراتيجية. للاطّلاع على السلوك الدقيق لأي طريقة بعينها، استخدم /integrations/tcpdf-compat/method-coverage/ مع المصفوفة المرجعية داخل المستودع docs/TCPDF_COVERAGE.md.
نموذج الترحيل
قسم بعنوان «نموذج الترحيل»تُبقي كل مرحلة تطبيقك قابلاً للإصدار. لا تحتاج أبداً إلى انتقال دفعة واحدة.
المرحلة 1 — استبدال التبعية
قسم بعنوان «المرحلة 1 — استبدال التبعية»ثبّت nextpdf/compat-legacy (راجع /integrations/tcpdf-compat/install/). لا تُزل tecnickcom/tcpdf بعدُ؛ فالإبقاء على كليهما يتيح لك مقارنة النتائج.
اختر كيفية حلّ مواضع الاستدعاء القديمة للصنف:
- المُفضّل: غيّر في كل ملف عبارة
use/requireإلىuse NextPDF\Compat\Tcpdf\TCPDF;. هذا أسلوب صريح وسهل البحث عنه. - عندما يتعذّر عليك حتى الآن تعديل مواضع الاستدعاء: فعّل الأسماء البديلة العامة الاختيارية مرة واحدة عند الإقلاع باستخدام
LegacyBootstrap::enableAliases()(راجع /integrations/tcpdf-compat/boot-and-discovery/). يؤدي ذلك إلى حلّ\TCPDFوالأصناف المساعدة الأربعة إلى المحوّل.
الاستراتيجيتان متنافيتان عملياً. إذا ظلّت مكتبة TCPDF الفعلية قابلة للتحميل التلقائي وفعّلت الأسماء البديلة العامة، فسيُتجاوز الاسم البديل عند وجود صنف
\TCPDFمسبقاً. وقد تستمر عندئذٍ في استخدام TCPDF القديمة دون أن تلاحظ ذلك. خلال المرحلة 1، فضّل عمليات الاستيراد على مستوى كل ملف لتعرف بالضبط أي صنف يستخدمه كل موضع استدعاء. راجع /integrations/tcpdf-compat/troubleshooting/.
المرحلة 2 — تشغيل مجموعة الاختبارات القائمة دون تغيير
قسم بعنوان «المرحلة 2 — تشغيل مجموعة الاختبارات القائمة دون تغيير»شغّل مجموعة اختباراتك الكاملة على المحوّل دون تغيير أي شيء آخر. تعمل معظم الطرق المفوَّضة (94 من نحو 120 طريقة جرى استقصاؤها) بشكل متوافق. توقّع نوعين من الإخفاقات المتوقّعة:
- التأكيدات على مستوى البايت. ستفشل الاختبارات التي تقارن بايتات Portable Document Format (PDF) بدقّة، لأن المحرّك تطبيق مستقل. هذا أمر متوقّع وليس عيباً. أجّل معالجتها إلى المرحلة 4.
- تفرّعات القيمة المُرجَعة. تُرجِع بضع طرق قيماً نائبة للتوافق بدلاً من قيم محسوبة. والأبرز أن
MultiCell()تُرجِع1، وWrite()تُرجِع0. تحتاج الشفرة التي تتفرّع استناداً إلى تلك القيم المُرجَعة إلى تعديل.
وثّق كل إخفاق. صنّف كل إخفاق على أنه خط أساس بايتي أو قيمة مُرجَعة أو فجوة سلوكية حقيقية.
المرحلة 3 — تدقيق الوضع الصارم
قسم بعنوان «المرحلة 3 — تدقيق الوضع الصارم»تجعل هذه المرحلة الترحيل آمناً. شغّل مجموعة الاختبارات، أو مساراً إنتاجياً تمثيلياً، مع تفعيل الوضع الصارم:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;use NextPDF\Compat\Tcpdf\TCPDF;
function renderInvoice(TCPDF $pdf): void{ // ... your existing rendering code, unchanged ...}
$pdf = new TCPDF('P', 'mm', 'A4');$pdf->setStrictMode(true);
try { renderInvoice($pdf); $pdf->Output(__DIR__ . '/audit.pdf', 'F');} catch (TcpdfNotImplementedException $e) { // Each message names the method, the ignored parameters, and a hint. fwrite(STDERR, 'MIGRATION GAP: ' . $e->getMessage() . "\n");}تعامل مع كل TcpdfNotImplementedException بوصفه بند عمل واحداً. تمنحك الرسالة الطريقة، وقائمة المعامِلات المتجاهَلة بدقّة، وتلميحاً للترحيل. مجموعة الطرق التي تطرح الاستثناءات محدودة ومؤكَّدة بالاختبار في tests/Unit/Compat/Tcpdf/TcpdfStrictModeTest.php. ومسوّغ كل حالة مذكور في docs/TCPDF_COVERAGE.md.
شغّل الوضع الصارم بوصفه مهمة تكامل مستمر (CI) مخصّصة، لا في الإنتاج. الغاية هي إظهار الفجوات، لا أن تجعل الإنتاج يطرح استثناءات.
المرحلة 4 — إصلاح مواضع الاستدعاء
قسم بعنوان «المرحلة 4 — إصلاح مواضع الاستدعاء»لكل فجوة، اختر الإصلاح الصحيح الأقل كلفة:
| نمط الفجوة | الإصلاح |
|---|---|
معامِل متجاهَل لا أهمية له (e.g. معامِل $align في TCPDF لم تعتمد عليه قط) | احذف المعامِل. يصبح الاستدعاء متوافقاً تماماً. |
معامِل متجاهَل كان ذا أهمية (e.g. رابط Image() قابل للنقر) | أعِد التعبير عنه باستخدام واجهة API الحديثة. ارسم الصورة، ثم أضف Document::link() فوق المستطيل. |
الطريقة غير مُنفَّذة (setSignature()، endPage()) | endPage() / Open(): أزل الاستدعاء. التوقيع: راجع /integrations/tcpdf-compat/security-and-operations/؛ فهو يتطلّب إصداراً تجارياً. |
طريقة غير منطبقة (setPDFVersion()، setUserRights()) | أزل الاستدعاء. المُخرَج دائماً PDF 2.0؛ وحقوق المستخدم مهملة في PDF 2.0. |
| تفرّع القيمة المُرجَعة | احسب القيمة بنفسك، أو انقل ذلك المنطق إلى واجهة API الحديثة. |
استخدم منفذ الالتفاف عندما يعجز سطح TCPDF عن التعبير عمّا تحتاج إليه:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();$pdf->AddPage();
// Legacy path stays as-is for the parts that work:$pdf->SetFont('helvetica', '', 12);$pdf->Cell(0, 10, 'Header line', 0, 1);
// Modern path for what the TCPDF surface cannot express here:$document = $pdf->getDocument();$document->image('logo.png', 10, 30, 40, 0);$document->link(10, 30, 40, 20, 'https://example.com');إعادة ضبط خط الأساس لاختبارات مستوى البايت
قسم بعنوان «إعادة ضبط خط الأساس لاختبارات مستوى البايت»استبدل التأكيدات على البايتات الدقيقة بتأكيدات على ما يهمّ فعلاً:
- يبدأ المُخرَج بـ
%PDFويُحلَّل (مستوى الفحص السريع). - محتوى النص المعروض موجود (استخرج النص وأكّد وجوده).
- الخصائص البنيوية (عدد الصفحات وحجم الصفحة ووجود مخطّط تفصيلي) متطابقة.
تدفع هذه الكلفة مرة واحدة لتحصل على اختبارات تصمد أمام ترقيات المحرّك المستقبلية.
المرحلة 5 — إزالة تبعية TCPDF
قسم بعنوان «المرحلة 5 — إزالة تبعية TCPDF»بعد نجاح تدقيق الوضع الصارم، وإيقاف الوضع الصارم off في الإنتاج، ونجاح مجموعة الاختبارات على التأكيدات التي أُعيد ضبط خط أساسها، أزل tecnickcom/tcpdf:
composer remove tecnickcom/tcpdfشغّل مجموعة الاختبارات مرة أخرى. إذا ظلّ أي شيء يُحلَّل إلى صنف TCPDF الفعلي، فقد انطبق تحذير الأسماء البديلة في المرحلة 1؛ أصلح مواضع الاستدعاء المتبقية لتستورد المحوّل صراحةً.
المرحلة 6 — سحب المحوّل من الخدمة
قسم بعنوان «المرحلة 6 — سحب المحوّل من الخدمة»المحوّل أداة مساعِدة للترحيل، لا طبقة دائمة. بعد التخلّص من TCPDF والتحقّق من المحرّك، اسحب المحوّل من الخدمة تدريجياً:
- في كل وحدة، استبدل
new TCPDF(...)بإنشاءNextPDF\Core\Documentالحديث. - استبدل استدعاءات طرق TCPDF بمكافئاتها الحديثة (استدعاءات
getDocument()التي أضفتها مسبقاً في المرحلة 4 هي القالب). - عندما تتوقّف وحدة عن الإشارة إلى المحوّل، احذف عمليات استيراد التوافق الخاصة بها.
- عندما لا تشير أي وحدة إلى المحوّل، أزل
nextpdf/compat-legacyمنcomposer.json.
عند تلك النقطة، تكون قد انتقلت إلى واجهة PDF 2.0 الحديثة دون أي طبقة توافق.
قائمة تحقّق الترحيل
قسم بعنوان «قائمة تحقّق الترحيل»- تثبيت
nextpdf/compat-legacy؛ والتحقّق من ارتباط المحرّك. - مواضع الاستدعاء تستورد المحوّل صراحةً (أو تمكين الأسماء البديلة مع إزالة TCPDF الفعلية من مسار التحميل التلقائي).
- تشغيل مجموعة الاختبارات الكاملة على المحوّل؛ وتصنيف الإخفاقات.
- إضافة مهمة CI للوضع الصارم؛ وتوثيق كل فجوة.
- إصلاح كل فجوة (حذف المعامِل / واجهة API الحديثة / إزالة الاستدعاء).
- إعادة ضبط خط أساس التأكيدات على مستوى البايت ليعتمد على المحتوى والبنية.
- إزالة
tecnickcom/tcpdf؛ ومجموعة الاختبارات ناجحة. - سحب المحوّل من الخدمة وحدةً تلو الأخرى؛ وإزالة التبعية.
انظر أيضاً
قسم بعنوان «انظر أيضاً»- /integrations/tcpdf-compat/method-coverage/ — سلوك كل طريقة وإرشادات الاستبدال
docs/TCPDF_COVERAGE.md— مصفوفة مرجعية مُتحقَّق منها بالاختبار- /integrations/tcpdf-compat/configuration/ — نقل الإعدادات بعيداً عن الثوابت العامة
- /integrations/tcpdf-compat/security-and-operations/ — التشفير والتوقيع أثناء الترحيل
- /integrations/tcpdf-compat/troubleshooting/ — تعارض alias/real-TCPDF ومزالق أخرى