ข้ามไปยังเนื้อหา

Contracts / เอกสาร

โดเมนเอกสารเก็บ contract ที่ใช้สร้างเอาต์พุต Portable Document Format (PDF) ได้แก่ PdfDocumentInterface สำหรับเนื้อหา DocumentFactoryInterface สำหรับการสร้างที่ปลอดภัยต่อ worker contract ของรีจิสทรีฟอนต์และรูปภาพ และ enum สำหรับการส่งมอบกับเค้าโครงอีกสามตัว ทั้งหมดอยู่ในระดับ stable ตั้งแต่ 1.0.0 หรือ 1.7.0

Terminal window
composer require nextpdf/core:^3

PdfDocumentInterface เป็นพื้นผิว application programming interface (API) หลัก อินเทอร์เฟซนี้กำหนดการจัดการหน้า การเลือกฟอนต์ การจัดวางข้อความแบบ cell และ multi-cell การเรนเดอร์ Hypertext Markup Language (HTML) การฝังรูปภาพ และเอาต์พุตสุดท้าย ทุกเมท็อดคืนค่า static จึงเชนการเรียกได้ Document::createStandalone() คืนอินสแตนซ์รูปธรรมที่สอดคล้องกับอินเทอร์เฟซ ให้ระบุชนิด (type-hint) เป็นอินเทอร์เฟซในบริการของคุณเอง เพื่อให้ภายในของเอนจินยังสลับเปลี่ยนได้

การสร้างเอกสารมีสองเส้นทาง ในคำขอ PHP FastCGI Process Manager (PHP-FPM) แบบคลาสสิก createStandalone() จะสร้างเอกสารแบบเบ็ดเสร็จในตัวพร้อมรีจิสทรีส่วนตัว ส่วน worker ที่ทำงานยาวนาน เช่น RoadRunner Swoole และ Laravel Octane ใช้อีกเส้นทางหนึ่ง ในกรณีนั้น DocumentFactoryInterface::create() คืน Document ตัวใหม่ที่ใช้แล้วทิ้งได้ เอกสารอ่านจากรีจิสทรีที่มีอายุเท่ากับโปรเซส แต่ไม่เปลี่ยนแปลงรีจิสทรีเหล่านั้น แฟกทอรีถือ singleton ของ FontRegistryInterface และ ImageRegistryInterface เอกสารแต่ละชุดมีบริบทการเรนเดอร์และตัวเขียน (writer) เป็นของตนเอง แนวทางนี้จำกัดขอบเขตความล้มเหลว เพราะเอกสารหนึ่งไม่สามารถทำให้สถานะที่ใช้ร่วมกันซึ่งเอกสารอื่นพึ่งพาเสียหายได้

contract ของรีจิสทรีช่วยให้ worker ทำงานได้รวดเร็ว FontRegistryInterface แจงไฟล์ฟอนต์เพียงครั้งเดียว และแคชเมทาดาทาที่แจงแล้วไว้ตลอดอายุของโปรเซส คุณสามารถล็อกรีจิสทรีหลังวอร์มอัป เพื่อไม่ให้ทราฟฟิกในโปรดักชันเปลี่ยนแปลงได้ ImageRegistryInterface แคชข้อมูลไบนารีของรูปภาพที่ถอดรหัสแล้วภายใต้นโยบาย least-recently-used แบบมีขอบเขตจำกัด เมทาดาทาของรูปภาพยังคงอยู่ในหน่วยความจำ แม้ว่าไบนารีจะถูกขับออกไปแล้ว รีจิสทรีทั้งสองเปิดเผย memoryUsage() สำหรับการวางแผนความจุ ImageRegistryInterface สืบทอดจาก ResettableService ซึ่งขับข้อมูลที่แคชไว้ออกโดยไม่ทำลายเมทาดาทาเชิงโครงสร้าง worker จึงทิ้งแคชรูปภาพภายใต้แรงกดดันด้านหน่วยความจำและให้บริการต่อไปได้

enum สามตัวเติมเต็มโดเมนนี้ OutputDestination เลือกการแสดงผลแบบอินไลน์ การบังคับดาวน์โหลด การเขียนลงระบบไฟล์ หรือการคืนค่าเป็นสตริงดิบ Orientation เลือกแนวตั้งหรือแนวนอน Alignment เลือกข้อความชิดซ้าย กึ่งกลาง ชิดขวา หรือเต็มแนว แต่ละ enum ใช้โค้ด TCPDF ดั้งเดิมเป็นค่าของ enum ดังนั้นบริดจ์ compat-tcpdf จึงแมปได้อย่างหมดจด คำมั่นด้านความเข้ากันได้ย้อนหลังของ enum เหล่านี้เป็นแบบเพิ่มเติม ไม่มีการลบ case ใดออก และ case ใหม่อาจมาในรุ่นย่อย (minor release)

ชนิดประเภทสมาชิกหลักความเสถียรตั้งแต่
PdfDocumentInterfaceinterfaceaddPage(), setMargins(), setFont(), cell(), multiCell(), writeHtml(), image(), output(), save()stable1.0.0
DocumentFactoryInterfaceinterfacecreate(?Config): Documentstable1.7.0
ResettableServiceinterfacereset(): voidstable1.7.0
FontRegistryInterfaceinterfaceregister(), get(), warmup(), lock(), isLocked(), registerFromBinary(), memoryUsage()stable1.7.0
ImageRegistryInterfaceinterfaceload(), loadFromString(), getMetadata(), memoryUsage() (สืบทอดจาก ResettableService)stable2.0.0
OutputDestinationenum (string)Inline, Download, File, Stringstable1.0.0
Orientationenum (string)Portrait, Landscapestable1.0.0
Alignmentenum (string)Left, Center, Right, Justifystable1.0.0

หน้า typography มีเอกสารฉบับเต็มของ FontRegistryInterface และ ImageRegistryInterface หน้านี้กล่าวถึงบทบาทของอินเทอร์เฟซเหล่านั้นในวงจรชีวิตของการสร้าง

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->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'This is a minimal PDF generated with NextPDF.', newLine: true);
$doc->save(__DIR__ . '/output/01-hello-world.pdf');
examples/02-pdf-factory.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\PdfFactory;
use NextPDF\ValueObjects\{Margin, PageSize};
$factory = PdfFactory::new()
->withPageSize(PageSize::A4())
->withMargins(new Margin(15.0, 15.0, 15.0, 15.0))
->withCompress(true)
->withLang('en');
// The same configured factory creates independent documents.
$doc = $factory->create();
$doc->setTitle('PdfFactory Example');
$doc->setAuthor('NextPDF');
$doc->addPage();
$doc->setFont('helvetica', '', 16);
$doc->cell(0, 12, 'Created via PdfFactory', newLine: true);
$doc2 = $factory->create();
$doc2->addPage();
$doc2->setFont('helvetica', '', 12);
$doc2->cell(0, 10, 'Second document from the same factory.');
$doc->save(__DIR__ . '/output/02-pdf-factory.pdf');

PdfFactory เป็น builder ที่ไม่เปลี่ยนแปลงค่า (immutable) การเรียก with*() แต่ละครั้งคืนอินสแตนซ์ใหม่ เบื้องหลัง builder นี้ประกอบ DocumentFactoryInterface ดังนั้นโมเดลรีจิสทรีของ worker จากภาพรวมจึงใช้ได้โดยไม่ต้องเดินสายเพิ่ม

  • createStandalone() สร้างรีจิสทรีส่วนตัว ในลูปของ worker วิธีนี้จะแจงฟอนต์ทุกตัวใหม่ในทุกคำขอ ให้ใช้ DocumentFactoryInterface ที่มีรีจิสทรีใช้ร่วมกันแทน
  • อินสแตนซ์ Document ถูกออกแบบมาให้ใช้แล้วทิ้ง การใช้อินสแตนซ์เดียวซ้ำข้ามเอกสารเชิงตรรกะหลายชุดทำให้สถานะรั่วไหล ให้เรียก create() สำหรับเอกสารแต่ละชุด แล้วปล่อยให้ garbage collection เรียกคืนหน่วยความจำ
  • FontRegistryInterface::lock() ทำให้ register(), addFontDirectory(), และ warmup() โยน LogicException ให้ล็อกหลังจากวอร์มอัป อย่าล็อกระหว่างการจัดการคำขอ
  • OutputDestination::File เขียนลงระบบไฟล์ของเซิร์ฟเวอร์และคืนค่าเป็นไบต์ดิบ save() คือพาธไฟล์ที่ระบุอย่างชัดเจน อย่าใช้ทั้งสองวิธีปะปนกันสำหรับเอกสารชุดเดียวกัน
  • cell() รับ bool|string สำหรับอาร์กิวเมนต์ border เพื่อความเข้ากันได้กับ TCPDF สตริงว่างไม่เหมือนกับ false ให้ส่งค่าที่มีชนิดตรงตามที่คุณต้องการ

รีจิสทรีฟอนต์และรูปภาพทำให้โดเมนเอกสารเป็นระบบที่มีหน่วยความจำจำกัด ไม่ใช่ระบบแบบต่อคำขอ การแจงฟอนต์ในคำขอแรกเป็นภาระหลัก performance_budget คือ 1500 ms wall และ 64 MB peak สำหรับเอกสารสามชุดในตัวอย่าง worker งบประมาณเกือบทั้งหมดคือการแจงฟอนต์ครั้งแรก หลังวอร์มอัป งานที่เกิดจาก contract ต่อเอกสารหนึ่งชุดเป็น O(1) ได้แก่ การค้นหาในรีจิสทรีและการจัดสรรบริบทหนึ่งครั้ง memoryUsage() ของรีจิสทรีใดก็ตามคืน MemoryReport สำหรับการวางแผนความจุแบบเรียลไทม์ ResettableService::reset() จำกัดขอบเขตหน่วยความจำสูงสุดภายใต้ภาระต่อเนื่อง

contract ของเอกสารไม่มีพื้นผิวด้านการเข้ารหัสลับ แต่มีความเสี่ยงเชิงปฏิบัติการอยู่สองประการ ประการแรก image() รับพาธหรือ Uniform Resource Locator (URL) ในสถานการณ์ที่อินพุตไม่น่าเชื่อถือ ให้จำกัดการดึงข้อมูลจากระยะไกลผ่าน ExternalResourcePolicyInterface (ดูหน้า security-policy) แทนการส่ง URL ที่ผู้ใช้ควบคุมเข้าไปโดยตรง ประการที่สอง writeHtml() เป็นจุดเข้าของไปป์ไลน์ HTML มาร์กอัปที่ไม่น่าเชื่อถือต้องผ่าน HtmlSecurityPolicyInterface ก่อนการเรนเดอร์ ชั้นเอกสารเองไม่ได้ sanitize นั่นเป็นหน้าที่ของโดเมน security-policy และเนื่องจากเป็น contract คุณจึงสามารถจัดหานโยบายที่เข้มงวดกว่าได้โดยไม่ต้อง fork

contract ของเอกสารนำโครงสร้างเอกสาร PDF 2.0 มาใช้ตามที่กำหนดไว้ใน ISO 32000-2 การจัดการเอาต์พุต หน้า และฟอนต์ ผลิต indirect object และ cross-reference stream ตาม ISO 32000-2 §7 ชั้นตัวเขียน (writer) ปล่อยเนื้อหาตาม contract ของชั้นเอนจิน architecture decision record (ADR-010) หน้านี้ไม่ได้ยืนยันข้อกล่าวอ้างระดับ clause ใดๆ นอกเหนือจากการสอดคล้องเชิงโครงสร้าง หน้าเกี่ยวกับการสกัดข้อมูลและการเข้าถึงได้มีเอกสารการสอดคล้องตาม PDF/A และ PDF/UA พร้อมตารางเชิงบรรทัดฐาน

  • Contracts: 41 public interfaces (SPI) — ภาพรวมของ service provider interface (SPI) และระดับความเสถียร
  • Contracts / Typography — เอกสารฉบับเต็มสำหรับ FontRegistryInterface
  • Contracts / Security Policy — นโยบายที่ควบคุม writeHtml() และ image() ทั้งสองเมท็อด
  • CoreDocument และ PdfFactory ที่เป็นคลาสรูปธรรม
  • Document — โมดูลการสร้างเอกสาร
  • Writer — ชั้นที่ปล่อยอ็อบเจกต์ PDF สำหรับ contract เหล่านี้