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

ترحيل قاعدة شيفرة TCPDF 6.x إلى NextPDF

توفّر حزمة nextpdf/compat-legacy أسماء الطرائق العامة في ⁨TCPDF 6.x⁩ وترتيب معاملاتها وقيمها الافتراضية فوق محرك نواة ⁨NextPDF⁩ عبر المحوّل NextPDF\Compat\Tcpdf\TCPDF. رحّل بهذا الترتيب: انتقل إلى المحرك بأصغر تغيير ممكن، وثبّت ما يعمل بالفعل، وفعّل الوضع الصارم لاكتشاف ما لا يعمل، وأصلح مواضع الاستدعاء واحدًا تلو الآخر، ثم أوقف المحوّل واستخدم الواجهة البرمجية الحديثة. يدعم المحوّل عملية الترحيل؛ وهو ليس الوجهة النهائية.

ابدأ بالمتطلبات المسبقة:

  • نواة ⁨NextPDF⁩ وnextpdf/compat-legacy مثبَّتتان.
  • لديك قاعدة شيفرة ⁨TCPDF 6.x⁩ قائمة ومزوّدة بمجموعة اختبارات. تمثّل مجموعة الاختبارات شبكة الأمان لكل مرحلة من المراحل أدناه.

هذا دليل إجرائي. للاطلاع على سلوك كل طريقة من طرائق ⁨TCPDF⁩، اقرأ صفحة تغطية الطرائق. وللاطلاع على الاستراتيجية الكاملة ملفًا بملف مع الشيفرة، اقرأ صفحة الترحيل في المستودع الأصلي. ستجد الرابطين كليهما ضمن قسم اطّلع أيضًا.

ثبّت المحوّل إلى جانب النواة. لا تُزِل مكتبة ⁨TCPDF⁩ الحقيقية بعد — فالاحتفاظ بكلتيهما يتيح لك مقارنة الناتج أثناء الترحيل.

Terminal window
composer require nextpdf/compat-legacy

قبل أن تغيّر أي شيفرة، تأكّد من أن قيد المحرك قابل للحل (nextpdf/core ^3.0) وأن مجموعة الاختبارات لا تزال تعمل.

المحوّل طبقة توافق، وليس تفريعًا من ⁨TCPDF⁩ ولا نسخة مطابقة بايتًا ببايت. من بين نحو 120 طريقة عامة شملها المسح في ⁨TCPDF 6.x⁩، ترتبط نحو 94 طريقة مباشرةً بعملية في NextPDF\Core\Document وتعمل على نحو متوافق مع المعاملات الموثّقة. أما أقلية محدّدة فإما تقبل معاملات قديمة لا يراعيها المحرك (تجاهل صامت)، أو لا تنتج أي ناتج (غير مُنفَّذة أو غير منطبقة). توجد مصفوفة التغطية المرجعية المتحقَّق منها بالاختبارات في مستودع الحزمة عند docs/TCPDF_COVERAGE.md. وعند تعارض هذا الدليل مع تلك المصفوفة، فالمرجع هو المصفوفة.

تحكم حقيقتان عملية الترحيل بأكملها:

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

يوفّر المحوّل أيضًا مستند المحرك المُغلَّف عبر getDocument()، الذي يعيد NextPDF\Core\Document. استخدم ذلك بوصفه مسار الخروج: رحّل مواضع الاستدعاء إلى الواجهة البرمجية الحديثة واحدًا تلو الآخر حتى تتمكّن من إزالة المحوّل.

الموضوعالسطح
الإنشاءnew NextPDF\Compat\Tcpdf\TCPDF('P', 'mm', 'A4')
أسماء عامة بديلة اختياريةNextPDF\Compat\Tcpdf\LegacyBootstrap::enableAliases()
تفعيل التدقيقTCPDF::setStrictMode(true)
استثناء التدقيقNextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException
مخرج طوارئ نحو الواجهة البرمجية الحديثةTCPDF::getDocument(): NextPDF\Core\Document
الإخراجTCPDF::Output(string $name, string $dest)S، F، E، I، D

LegacyBootstrap::enableAliases() غير حسّاس للتكرار (⁨idempotent⁩). فهو يسجّل \TCPDF و\TCPDF_STATIC و\TCPDF_FONTS و\TCPDF_COLORS و\TCPDF_IMAGES فقط عندما لا تكون تلك الأصناف موجودة أصلًا. توضّح صفحتا تغطية الطرائق والبدء السريع المرتبطتان ضمن قسم اطّلع أيضًا السلوك الكامل لكل طريقة ووجهات الإخراج.

غيّر سطر الاستيراد، واحتفظ باستدعاءات نمط ⁨TCPDF⁩، وأنتج ملف ⁨PDF.⁩

quickstart-first.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF('P', 'mm', 'A4');
$pdf->SetCreator('Quickstart');
$pdf->SetTitle('First Document');
$pdf->SetFont('helvetica', '', 12);
$pdf->AddPage();
$pdf->Cell(0, 10, 'Hello from the NextPDF engine', 1, 1, 'C');
$pdf->Output(__DIR__ . '/quickstart.pdf', 'F');

Output($name, 'F') يكتب الملف ويعيد سلسلة فارغة. وعلى خلاف ⁨TCPDF⁩ القديم، لا تكتب Output() الخاصة بالمحوّل إلى مخزن الإخراج النشط، لذا يمكنك استدعاؤها بأمان داخل عامل طابور أو معالِج ⁨HTTP⁩ يتحكّم في استجابته الخاصة.

عندما يتعذّر عليك تغيير مواضع الاستدعاء التي تنشئ new \TCPDF(...) في النطاق العام، فعّل الأسماء البديلة الاختيارية مرة واحدة عند الإقلاع.

quickstart-alias.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\LegacyBootstrap;
LegacyBootstrap::enableAliases();
// Legacy code now resolves \TCPDF to the adapter:
$pdf = new \TCPDF('P', 'mm', 'A4');
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Legacy call site, modern engine');
$pdf->Output(__DIR__ . '/aliased.pdf', 'F');

لا تفعّل الأسماء البديلة بينما مكتبة ⁨TCPDF⁩ الحقيقية لا تزال قابلة للتحميل التلقائي. يُتخطّى الاسم البديل عندما يكون الصنف \TCPDF موجودًا أصلًا، لذا قد تستمر في استخدام ⁨TCPDF⁩ القديم دون أن تدري. أثناء الترحيل، فضّل عمليات الاستيراد لكل ملف على حدة.

الخطوة الآمنة للترحيل هي تدقيق الوضع الصارم. شغّل مسارًا تمثيليًا من الإنتاج، أو مجموعة الاختبارات، مع تفعيل الوضع الصارم، واجمع كل TcpdfNotImplementedException. كل استثناء هو بند عمل: فهو يسمّي الطريقة، ويحدّد المعاملات المتجاهَلة، ويقدّم تلميحًا.

migration-audit.php
<?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 $exception) {
// Each message names the method, the ignored parameters, and a hint.
fwrite(STDERR, 'MIGRATION GAP: ' . $exception->getMessage() . "\n");
}

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

migration-escape-hatch.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
// Legacy path stays for the parts that already work:
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Header line', 0, 1);
// Modern path for what the TCPDF surface cannot express here —
// for example a clickable image (the legacy Image() link parameter
// is one of the silently ignored parameters):
$document = $pdf->getDocument();
$document->image('logo.png', 10, 30, 40, 0);
$document->link(10, 30, 40, 20, 'https://example.com');

شغّل الوضع الصارم بوصفه مهمة تكامل مستمر (⁨CI⁩) مخصّصة، ثم أوقفه وانشر مسار الشيفرة المُدقَّق. احتفظ بمهمة تكامل مستمر دورية تعمل بالوضع الصارم لالتقاط الانحدارات أثناء إعادة الهيكلة.

  • تعيد MultiCell() القيمة 1، وتعيد Write() القيمة 0. هذه قيم موضوعة للتوافق، وليست قيمًا محسوبة. عدّل أي شيفرة تتفرّع بناءً على تلك القيم المُعادة.
  • تطرح Error() استثناءً بدلًا من استدعاء die(). يطرح المحوّل RuntimeException. يجب أن تلتقط الشيفرة التي تعتمد على إنهاء العملية هذا الاستثناء.
  • المعاملات ذات التجاهل الصامت. تقبل طرائق مثل Image() وwriteHTML() وSetProtection() وBookmark() معاملات قديمة يجري تجاهلها. استخدم الوضع الصارم للعثور عليها. لإنشاء صورة قابلة للنقر، ارسم الصورة، ثم أضف Document::link() فوق المستطيل نفسه.
  • الطرائق غير المُنفَّذة. setSignature() وaddEmptySignatureAppearance() وendPage() هي عمليات لا أثر لها وتطرح استثناءً في الوضع الصارم؛ أما Open() فهي عملية آمنة لا أثر لها ولا تطرح استثناءً أبدًا. أزِل endPage() وOpen(). يتطلّب التوقيع إصدارًا تجاريًا من ⁨NextPDF⁩ عبر الواجهة البرمجية الحديثة للتوقيع.
  • إصدار ⁨PDF⁩ ثابت. لا يمكن لـ setPDFVersion() أن تستهدف إصدار ⁨PDF⁩ أقدم؛ فالناتج دائمًا ⁨PDF 2.0.⁩ setUserRights() مهملة في ⁨PDF 2.0⁩ ويجري تجاهلها مع إصدار إشعار.
  • تعارض الأسماء البديلة. إذا ظل أي شيء يُحلّ إلى صنف ⁨TCPDF⁩ الحقيقي بعد إزالتك tecnickcom/tcpdf، فإن التحذير الخاص بالأسماء البديلة ينطبق — استورد المحوّل صراحةً في مواضع الاستدعاء تلك.

يفوّض المحوّل العمل إلى المحرك؛ وتتناسب كلفة بناء المستند مع المحتوى، لا مع طبقة المحوّل. ولأن Output() الخاصة بالمحوّل لا تكتب إلى مخزن الإخراج، فهي آمنة داخل عامل طابور — انقل التوليد الثقيل بأسلوب ⁨TCPDF⁩ بعيدًا عن خيط الطلب بالطريقة نفسها التي تنقل بها أي توليد في ⁨NextPDF.⁩ تُعدّ إعادة ضبط مراجع الاختبارات من مستوى البايت إلى المحتوى المعروض كلفة لمرة واحدة، وهي تمنحك اختبارات تصمد أمام ترقيات المحرك المستقبلية.

  • التشفير. تتجاهل SetProtection() المعاملين القديمين mode وpubkeys؛ ويستخدم المحرك ⁨AES-256⁩ للمعالِج القياسي. للتشفير المعتمد على الشهادات، استخدم نقطة دخول التشفير بالمفتاح العام الحديثة التي يوفّرها المحوّل، لا المعاملات القديمة.
  • التوقيع مقيَّد. دعم التوقيع الأساسي قدرة خاصة بالإصدار التجاري يجري الوصول إليها عبر الواجهة البرمجية الحديثة للتوقيع باستخدام كائن قيمة شهادة؛ أما setSignature() القديمة فهي عملية لا أثر لها. لا يقدّم هذا الدليل أي ادعاء بشأن ملفات تعريف التوقيع ذات التحقق طويل الأمد أو الموسومة زمنيًا لأي إصدار.
  • اجعل الإخفاق صريحًا أثناء التدقيق. يجعل الوضع الصارم الفقد الصامت للمعاملات مرئيًا، فتعرف متى لم يلتزم المحوّل بمقصد المستدعي. تعامل مع الاستثناءات المجمّعة بوصفها قائمة عمل الترحيل، لا بوصفها سلوك الإنتاج.
  • لا تكتب أبدًا كتلة catch فارغة. يلتقط مثال التدقيق TcpdfNotImplementedException ويكتب سطر بند عمل محدَّد.

تجد تفاصيل التشفير والتوقيع الكاملة أثناء الترحيل في صفحة الأمان والتشغيل الخاصة بـ ⁨compat-legacy.⁩

لا يقدّم هذا الدليل أي ادعاء معياري خاص به. يكتب المحوّل ناتج ⁨PDF 2.0⁩ (⁨ISO 32000-2⁩) ولا يمكنه استهداف إصدار أقدم. هذا السلوك وهذا القيد موثّقان في صفحة تغطية الطرائق في المستودع الأصلي، التي تسجّل أيضًا مبدأ ⁨OWASP⁩ في الإخفاق الصريح وراء الوضع الصارم وإطار اكتمال الوظائف وفق ⁨ISO/IEC 25023⁩ لتدقيق التغطية. تعيد هذه الصفحة العملية عرض الاستخدام وتحيل تلك الاستشهادات إلى صفحة المستودع الأصلي.