ย้ายโค้ดเบส TCPDF 6.x ไปยัง NextPDF
ภาพรวมโดยย่อ
หัวข้อที่มีชื่อว่า “ภาพรวมโดยย่อ”แพ็กเกจ nextpdf/compat-legacy เปิดให้ใช้ชื่อเมธอดสาธารณะ ลำดับพารามิเตอร์ และค่าเริ่มต้นของ TCPDF 6.x บนเอนจิน NextPDF core ผ่านอะแดปเตอร์ NextPDF\Compat\Tcpdf\TCPDF ให้ย้ายตามลำดับนี้: เปลี่ยนไปใช้เอนจินด้วยการแก้ไขให้น้อยที่สุด ยืนยันว่าส่วนใดยังทำงานได้อยู่ เปิด strict mode เพื่อหาจุดที่ยังทำงานไม่ได้ แก้ไข call site ทีละจุด แล้วจึงเลิกใช้อะแดปเตอร์และเปลี่ยนไปใช้ API สมัยใหม่ อะแดปเตอร์มีไว้รองรับการย้าย ไม่ใช่ปลายทางสุดท้าย
ข้อกำหนดเบื้องต้นก่อนเริ่ม:
- ติดตั้ง NextPDF core และ
nextpdf/compat-legacyแล้ว - มีโค้ดเบส TCPDF 6.x ที่มีอยู่พร้อมชุดทดสอบ ชุดทดสอบนี้เป็นกลไกป้องกันความเสี่ยงสำหรับแต่ละขั้นตอนด้านล่าง
หน้านี้เป็นคู่มือเชิงปฏิบัติ สำหรับพฤติกรรมรายเมธอดของการเรียก TCPDF หนึ่งครั้ง ให้อ่านหน้า method-coverage หากต้องการกลยุทธ์แบบครบถ้วนทีละไฟล์พร้อมโค้ด ให้อ่านหน้า migration ต้นทาง ลิงก์ทั้งสองอยู่ในส่วน ดูเพิ่มเติม
การติดตั้ง
หัวข้อที่มีชื่อว่า “การติดตั้ง”ติดตั้งอะแดปเตอร์ควบคู่กับ core อย่าเพิ่งลบไลบรารี TCPDF จริง — การเก็บทั้งสองไว้ช่วยให้เปรียบเทียบเอาต์พุตระหว่างการย้ายได้
composer require nextpdf/compat-legacyก่อนเปลี่ยนแปลงโค้ดใดๆ ให้ยืนยันว่าลิงก์ของเอนจินถูก resolve (nextpdf/core ^3.0) และชุดทดสอบยังคงรันได้
ภาพรวมเชิงแนวคิด
หัวข้อที่มีชื่อว่า “ภาพรวมเชิงแนวคิด”อะแดปเตอร์เป็นเลเยอร์ความเข้ากันได้ ไม่ใช่ fork ของ TCPDF และไม่ใช่โคลนที่เหมือนกันระดับไบต์ จากเมธอดสาธารณะของ TCPDF 6.x ที่สำรวจไว้ราว 120 เมธอด ประมาณ 94 เมธอดแมปไปยังการดำเนินการของ NextPDF\Core\Document โดยตรงและทำงานเข้ากันได้กับพารามิเตอร์ที่มีเอกสารกำกับ เมธอดส่วนน้อยที่ระบุไว้แบ่งเป็นกลุ่มที่รับพารามิเตอร์รุ่นเก่าที่เอนจินไม่รองรับแล้วละเว้นอย่างเงียบ (silent-ignore) หรือกลุ่มที่ไม่สร้างเอาต์พุต (unimplemented หรือ not-applicable) เมทริกซ์ความครอบคลุมที่เป็นทางการและผ่านการตรวจสอบด้วยการทดสอบอยู่ในที่เก็บแพ็กเกจที่ docs/TCPDF_COVERAGE.md หากคู่มือนี้ขัดแย้งกับเมทริกซ์นั้น ให้ยึดตามเมทริกซ์
ข้อเท็จจริงสองข้อต่อไปนี้กำหนดรูปแบบการย้ายทั้งหมด:
- ไบต์ของเอาต์พุตแตกต่างกัน เอนจินเป็น implementation ของ PDF 2.0 ที่พัฒนาขึ้นอย่างอิสระ ดังนั้นไบต์เอาต์พุตจึงแตกต่างจากเอาต์พุตของ TCPDF แม้ว่าผลลัพธ์ที่มองเห็นจะดูเหมือนกันก็ตาม การทดสอบที่ assert ว่าไบต์ PDF ตรงกันทุกตัวจำเป็นต้องปรับเส้นฐานใหม่ให้วัดจากเนื้อหาที่เรนเดอร์หรือคุณสมบัติเชิงโครงสร้าง
- Strict mode คือเครื่องมือตรวจสอบของคุณ เมื่อปิด strict mode (ค่าเริ่มต้น) เมธอดที่ไม่สามารถจำลองพฤติกรรมของ TCPDF ได้จะถูกลดทอนอย่างเงียบๆ เมื่อเปิด strict mode การเรียกเหล่านั้นจะโยน
TcpdfNotImplementedExceptionพร้อมระบุพารามิเตอร์ที่ถูกละเว้นอย่างชัดเจนและให้คำแนะนำสำหรับการย้าย รัน strict mode ในรอบการตรวจสอบเฉพาะ ไม่ใช่ในระบบโปรดักชัน
อะแดปเตอร์ยังเปิดเผยอ็อบเจ็กต์เอกสารของเอนจินที่ห่อหุ้มอยู่ผ่าน getDocument() ซึ่งคืนค่า NextPDF\Core\Document ใช้เป็นเส้นทางออก แล้วย้าย call site ไปยัง API สมัยใหม่ทีละจุดจนกว่าจะลบอะแดปเตอร์ได้
พื้นผิว API
หัวข้อที่มีชื่อว่า “พื้นผิว API”| ประเด็น | พื้นผิว |
|---|---|
| การสร้างอินสแตนซ์ | new NextPDF\Compat\Tcpdf\TCPDF('P', 'mm', 'A4') |
| global alias แบบเลือกเปิดใช้ | NextPDF\Compat\Tcpdf\LegacyBootstrap::enableAliases() |
| เปิดใช้การตรวจสอบ | TCPDF::setStrictMode(true) |
| ข้อยกเว้นของการตรวจสอบ | NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException |
| ทางออกฉุกเฉินสู่ API สมัยใหม่ | 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 เฉพาะเมื่อคลาสเหล่านั้นยังไม่มีอยู่ หน้า method-coverage และ quickstart ที่ลิงก์ไว้ในส่วน ดูเพิ่มเติม ครอบคลุมพฤติกรรมรายเมธอดและปลายทางเอาต์พุตอย่างครบถ้วน
ตัวอย่างโค้ด — เริ่มต้นอย่างรวดเร็ว
หัวข้อที่มีชื่อว่า “ตัวอย่างโค้ด — เริ่มต้นอย่างรวดเร็ว”เปลี่ยน import แต่เก็บการเรียกแบบ TCPDF เดิมไว้ แล้วสร้าง PDF
<?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() ของอะแดปเตอร์ไม่ echo ไปยังบัฟเฟอร์เอาต์พุตที่ทำงานอยู่ คุณจึงเรียกใช้ภายใน queue worker หรือ HTTP handler ที่ควบคุม response ของตนเองได้อย่างปลอดภัย
หากยังเปลี่ยน call site ที่สร้าง new \TCPDF(...) กับ global namespace ไม่ได้ ให้เปิดใช้ alias แบบเลือกเปิดใช้หนึ่งครั้งตอนบูต
<?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');อย่าเปิดใช้ alias ขณะที่ไลบรารี TCPDF จริงยังสามารถ autoload ได้ alias จะถูกข้ามเมื่อมีคลาส \TCPDF อยู่แล้ว ดังนั้นคุณอาจยังใช้ TCPDF รุ่นเก่าโดยไม่รู้ตัว ระหว่างการย้ายควรใช้ import แบบรายไฟล์
ตัวอย่างโค้ด — โปรดักชัน
หัวข้อที่มีชื่อว่า “ตัวอย่างโค้ด — โปรดักชัน”ขั้นตอนที่ปลอดภัยสำหรับการย้ายคือการตรวจสอบด้วย strict mode โดยรันเส้นทางโปรดักชันที่เป็นตัวแทนหรือชุดทดสอบขณะเปิด strict mode และรวบรวม TcpdfNotImplementedException ทุกรายการ ข้อยกเว้นแต่ละรายการคืองานหนึ่งรายการ โดยระบุชื่อเมธอด พารามิเตอร์ที่ถูกละเว้น และคำแนะนำ
<?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");}สำหรับช่องว่างแต่ละจุด ให้เลือกการแก้ไขที่ถูกต้องและประหยัดที่สุด ละทิ้งพารามิเตอร์ที่ไม่เคยพึ่งพา หรือแสดงเจตนาผ่าน API สมัยใหม่ด้วย getDocument() ทางออกฉุกเฉินนี้ใช้จัดการสิ่งใดๆที่พื้นผิว TCPDF ไม่สามารถแสดงออกได้
<?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');รัน strict mode เป็นงาน continuous integration (CI) แยกเฉพาะ จากนั้นปิดและปรับใช้เส้นทางโค้ดที่ผ่านการตรวจสอบแล้ว เก็บงาน CI แบบ strict mode ไว้เป็นระยะ เพื่อจับ regression ขณะ refactor
กรณีขอบและข้อควรระวัง
หัวข้อที่มีชื่อว่า “กรณีขอบและข้อควรระวัง”MultiCell()คืนค่า1Write()คืนค่า0ค่าเหล่านี้เป็นตัวยึดตำแหน่งเพื่อความเข้ากันได้ ไม่ใช่ค่าที่คำนวณได้ ปรับโค้ดใดๆที่ branch ตามค่าที่คืนเหล่านี้Error()โยนข้อยกเว้นแทนการเรียกdie()อะแดปเตอร์โยนRuntimeExceptionโค้ดที่พึ่งพาการสิ้นสุดโปรเซสต้องดักจับข้อยกเว้น- พารามิเตอร์ที่ถูกละเว้นอย่างเงียบๆ เมธอดอย่าง
Image()writeHTML()SetProtection()และBookmark()รับพารามิเตอร์รุ่นเก่าที่ถูกละเว้น ใช้ strict mode เพื่อค้นหาพารามิเตอร์เหล่านั้น สำหรับรูปภาพที่คลิกได้ ให้วาดรูปภาพ จากนั้นเพิ่มDocument::link()ครอบรูปสี่เหลี่ยมเดียวกัน - เมธอดที่ยังไม่ได้พัฒนา
setSignature()addEmptySignatureAppearance()และendPage()เป็น no-op ที่โยนข้อยกเว้นใน strict mode ส่วนOpen()เป็น no-op ที่ปลอดภัยและไม่โยนข้อยกเว้นเลย ลบendPage()และOpen()การลงนามต้องใช้ NextPDF รุ่นเชิงพาณิชย์ผ่าน signature API สมัยใหม่ - เวอร์ชัน PDF ถูกกำหนดตายตัว
setPDFVersion()ไม่สามารถลดเป้าหมายไปยังเวอร์ชัน PDF ที่เก่ากว่าได้ เอาต์พุตเป็น PDF 2.0 เสมอsetUserRights()ถูกเลิกใช้ใน PDF 2.0 และถูกละเว้นพร้อมแจ้งเตือน - ความขัดแย้งของ alias หากยังมีส่วนใด resolve ไปยังคลาส TCPDF จริงหลังจากที่ลบ
tecnickcom/tcpdfแล้ว ข้อควรระวังเรื่อง alias จะมีผล — ให้ import อะแดปเตอร์อย่างชัดเจนที่ call site เหล่านั้น
ประสิทธิภาพ
หัวข้อที่มีชื่อว่า “ประสิทธิภาพ”อะแดปเตอร์มอบหมายงานให้เอนจิน ต้นทุนการสร้างเอกสารจึงแปรผันตามเนื้อหา ไม่ใช่ตามเลเยอร์ของอะแดปเตอร์ เนื่องจาก Output() ของอะแดปเตอร์ไม่เขียนลงในบัฟเฟอร์เอาต์พุต จึงปลอดภัยภายใน queue worker — ให้ย้ายการสร้างแบบ TCPDF ที่หนักออกจากเธรดของ request เช่นเดียวกับที่ย้ายการสร้าง NextPDF ใดๆ การปรับเส้นฐานของการทดสอบระดับไบต์ใหม่ให้ยึดเนื้อหาที่เรนเดอร์เป็นต้นทุนครั้งเดียว และทำให้ได้การทดสอบที่ทนต่อการอัปเกรดเอนจินในอนาคต
หมายเหตุด้านความปลอดภัย
หัวข้อที่มีชื่อว่า “หมายเหตุด้านความปลอดภัย”- การเข้ารหัสลับ
SetProtection()ละเว้นพารามิเตอร์รุ่นเก่าmodeและpubkeysเอนจินใช้ AES-256 สำหรับ handler มาตรฐาน สำหรับการเข้ารหัสลับแบบใช้ใบรับรอง ให้ใช้จุดเข้าใช้งานการเข้ารหัสลับด้วยกุญแจสาธารณะสมัยใหม่ที่อะแดปเตอร์เปิดเผย ไม่ใช่พารามิเตอร์รุ่นเก่า - การลงนามถูกจำกัดสิทธิ์ การรองรับลายเซ็นพื้นฐานเป็นความสามารถของรุ่นเชิงพาณิชย์ที่เข้าถึงได้ผ่าน signature API สมัยใหม่ด้วย value object ของใบรับรอง ส่วน
setSignature()รุ่นเก่าเป็น no-op คู่มือนี้ไม่อ้างถึง long-term-validation หรือโปรไฟล์ลายเซ็นที่ประทับเวลาสำหรับรุ่นใดๆ - ล้มเหลวอย่างชัดเจนระหว่างการตรวจสอบ strict mode ทำให้การสูญเสียพารามิเตอร์อย่างเงียบๆมองเห็นได้ คุณจึงทราบเมื่ออะแดปเตอร์ไม่สามารถทำตามเจตนาของผู้เรียกได้ ถือว่าข้อยกเว้นที่รวบรวมได้เป็นรายการงานสำหรับการย้าย ไม่ใช่พฤติกรรมในโปรดักชัน
- อย่าเขียนบล็อก
catchที่ว่างเปล่าเด็ดขาด ตัวอย่างการตรวจสอบดักจับTcpdfNotImplementedExceptionและเขียนบรรทัดรายการงานตามที่กำหนดไว้
แนวปฏิบัติด้านการเข้ารหัสลับและลายเซ็นทั้งหมดระหว่างการย้ายอยู่ในหน้า security-and-operations ของ compat-legacy
ความสอดคล้อง
หัวข้อที่มีชื่อว่า “ความสอดคล้อง”คู่มือนี้ไม่ได้สร้างข้อกล่าวอ้างเชิงบรรทัดฐานใหม่ของตนเอง อะแดปเตอร์สร้างเอาต์พุต PDF 2.0 (ISO 32000-2) และไม่สามารถลดเป้าหมายไปยังเวอร์ชันที่เก่ากว่าได้ พฤติกรรมและข้อกำหนดดังกล่าวถูกตรึงไว้ในหน้า method-coverage ต้นทาง ซึ่งยังบันทึกหลักการ fail-explicitly ของ OWASP ที่อยู่เบื้องหลัง strict mode และกรอบความครบถ้วนเชิงฟังก์ชันตาม ISO/IEC 25023 ของการตรวจสอบความครอบคลุม หน้า cookbook นี้ทบทวนการใช้งานซ้ำ โดยให้หน้าต้นทางเป็นแหล่งอ้างอิงสำหรับรายละเอียดเหล่านั้น
ดูเพิ่มเติม
หัวข้อที่มีชื่อว่า “ดูเพิ่มเติม”- คืน PDF ที่สร้างจาก controller — คืนเอาต์พุตของอะแดปเตอร์เป็น HTTP response
- compat-legacy quickstart — เอกสารฉบับแรก ปลายทางเอาต์พุต และทางออกฉุกเฉิน
- ความครอบคลุมเมธอดของ TCPDF — การตรวจสอบรายเมธอดและเมทริกซ์ที่เป็นทางการ
- ย้ายจาก TCPDF 6.x ไปยัง NextPDF — กลยุทธ์หกขั้นตอนแบบเต็มพร้อมโค้ด