โมเดลไปป์ไลน์
Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 Evidence: Code-backed
ภาพรวมโดยย่อ
หัวข้อที่มีชื่อว่า “ภาพรวมโดยย่อ”เอกสาร NextPDF ไม่ได้ถูกสร้างขึ้นด้วยขั้นตอนเดียวที่ทึบและมองไม่เห็น แต่เคลื่อนผ่านสเตจจำนวนน้อยที่กำหนดชัดเจน ได้แก่ facade ที่บันทึกเจตนา เลเยอร์เนื้อหาที่แปลงเจตนาเป็นโมเดล และ writer ที่ซีเรียไลซ์โมเดลนั้นเป็น PDF ที่สอดคล้องตามมาตรฐาน หน้านี้อธิบายโครงสร้างดังกล่าวและเหตุผลที่โครงสร้างนี้เหมาะกับเอนจิน
เหตุใดสิ่งนี้จึงสำคัญ
หัวข้อที่มีชื่อว่า “เหตุใดสิ่งนี้จึงสำคัญ”ตัวรูปแบบไฟล์ PDF เองก็เป็นโครงสร้างแบบแบ่งชั้น ได้แก่ ส่วนหัว ส่วนเนื้อหาของอ็อบเจกต์ ตารางการอ้างอิงข้าม และส่วนท้าย โดย writer ต้องประกอบทั้งหมดนี้ให้สอดคล้องกัน หากเอนจินที่สร้างไฟล์เป็นกระบวนการเดียวที่พันกันยุ่งเหยิง การเปลี่ยนแปลงทุกครั้งย่อมทำให้เอาต์พุตทุกรายการมีความเสี่ยง วิธีเดียวที่เหลือสำหรับสร้างความมั่นใจคือการเรนเดอร์เอกสารทั้งฉบับแล้วตรวจสอบด้วยสายตา ซึ่งช้า ทำซ้ำยาก และไม่น่าเชื่อถือเพียงพอ
ไปป์ไลน์ที่ชัดเจนพลิกสถานการณ์ดังกล่าว แต่ละสเตจมีหน้าที่เดียวและมีขอบเขตที่กำหนดชนิดข้อมูล คุณจึงสามารถใช้เหตุผลกับการเปลี่ยนแปลงและทดสอบในสเตจที่เกี่ยวข้องกับการเปลี่ยนแปลงนั้นได้ ไม่ใช่ทดสอบเฉพาะที่ปลายทางของไฟล์เท่านั้น สถาปัตยกรรมนี้เป็นการตัดสินใจเพื่อความสามารถในการทดสอบและการขยายความสามารถ ก่อนจะเป็นเรื่องอื่นใด
ฉบับย่อ
หัวข้อที่มีชื่อว่า “ฉบับย่อ”- จุดเข้าใช้งานสาธารณะคือ Document facade ซึ่งเป็น builder แบบ fluent ที่ใช้ครั้งเดียวและปลอดภัยสำหรับ worker โดยบันทึก สิ่งที่ คุณต้องการ ไม่ใช่ วิธีที่ สิ่งนั้นจะถูกซีเรียไลซ์
- facade มอบหมายงานให้ concern trait ที่มุ่งเน้นเฉพาะด้านประมาณสองโหล (การแสดงผลข้อความ การวาด หน้า ความปลอดภัย การนำทาง และอื่น ๆ) โดยแต่ละตัวมีความรับผิดชอบเดียว ไม่ใช่คลาสขนาดใหญ่เพียงคลาสเดียว
- เนื้อหาเข้าสู่ระบบได้สองเส้นทาง ได้แก่ การวาดโดยตรง (graphics primitive) หรือ เอนจิน HTML/CSS ทั้งสองเส้นทางสร้างโมเดลเอกสารภายในแบบเดียวกัน
- ตัว PDF writer ที่รับผิดชอบเฉพาะด้านจะซีเรียไลซ์โมเดลนั้น โดยเลือกกลยุทธ์แบบ PDF 1.4 / 1.7 / 2.0 การสร้างโครงสร้างไฟล์ที่ถูกต้องเกิดขึ้นที่นี่และไม่มีที่อื่น
- สถานะที่มีอายุยาว (registry ของฟอนต์และรูปภาพ) มีขอบเขตอยู่ที่ระดับโปรเซสและถูกใช้ร่วมกัน ส่วนสถานะแบบต่อคำขอ (เอกสาร) จะถูกสร้างขึ้นใหม่และไม่นำกลับมาใช้ซ้ำ ขอบเขตที่ชัดเจนนี้ทำให้รันไทม์แบบ worker มีความปลอดภัย
วิธีที่ NextPDF ดำเนินการกับสิ่งนี้
หัวข้อที่มีชื่อว่า “วิธีที่ NextPDF ดำเนินการกับสิ่งนี้”วิธีที่ชัดเจนที่สุดในการทำความเข้าใจโมเดลนี้คือการติดตามเอกสารตั้งแต่การเรียกใช้ไปจนถึงไบต์
- Document facade Fluent, use-once builder; records intent via concern traits.
- Content production Direct drawing or the HTML/CSS engine — both build one document model.
- Document model Accumulated pages, content, and resources held as typed state.
- PDF writer Serialises the model; selects a PDF 1.4 / 1.7 / 2.0 strategy.
- Conforming PDF Header, object body, cross-reference table, trailer.
การตัดสินใจด้านการออกแบบสองประการทำให้สิ่งนี้เป็นมากกว่าแผนภาพ
facade ถูกประกอบขึ้น ไม่ใช่แบบ monolithic Document ไม่ได้นำทุกฟีเจอร์มาทำเองทั้งหมด แต่มอบหมายแต่ละด้านให้ concern trait ที่มีหน้าที่เฉพาะ ได้แก่ การแสดงผลข้อความ การวาด หน้า ความปลอดภัย การจัดการตัวอักษร การนำทาง ทรานแซกชัน และอื่น ๆ เมธอดใหม่ของเอกสารควรอยู่ใน trait ที่เป็นเจ้าของด้านนั้น ไม่ใช่อยู่บน facade เอง คลาสที่คุณเรียกใช้จึงยังคงมีขนาดเล็ก และความรับผิดชอบยังคงแยกจากกัน
writer เป็นเจ้าของโครงสร้างไฟล์แต่เพียงผู้เดียว การผลิตเนื้อหาตัดสินใจว่า อะไร คือมาร์กและอ็อบเจกต์ที่มีอยู่ ส่วน writer ตัดสินใจว่าสิ่งเหล่านั้นจะกลายเป็นไฟล์ PDF ที่ถูกต้อง อย่างไร รวมถึงเลือกกลยุทธ์เวอร์ชันที่จะใช้ การแยกส่วนนี้ถูกบังคับใช้เป็นกฎทางสถาปัตยกรรม กล่าวคือ โค้ดด้านเค้าโครงและเนื้อหาจะไม่ปล่อยโครงสร้างไฟล์ขั้นสุดท้ายออกมา และ writer จะไม่ตัดสินใจด้านเค้าโครง ประโยชน์คือคำถามว่า “เอาต์พุตเป็น PDF ที่ถูกต้องหรือไม่?” มีพื้นที่ทดสอบเพียงแห่งเดียวเท่านั้น
ขอบเขตด้านอายุการใช้งานเป็นส่วนหนึ่งของโมเดล ไม่ใช่สิ่งที่ค่อยคิดภายหลัง registry ของฟอนต์และรูปภาพคงอยู่ตลอดอายุของโปรเซสและถูกใช้ร่วมกันข้ามคำขอ ส่วนเอกสาร บริบทการเรนเดอร์ของเอกสาร และ writer จะถูกสร้างขึ้นต่อคำขอและถูกทำลายทิ้งไป ในรันไทม์แบบ worker ความแตกต่างดังกล่าวคือเส้นแบ่งระหว่างการนำกลับมาใช้ซ้ำอย่างปลอดภัยกับการเสียหายของข้อมูลข้ามคำขอ ด้วยเหตุนี้ ประเด็นนี้จึงถูกระบุไว้ในสถาปัตยกรรม ไม่ได้ปล่อยให้ขึ้นอยู่กับวินัยในการปฏิบัติ
หลักฐานบ่งชี้อะไร
หัวข้อที่มีชื่อว่า “หลักฐานบ่งชี้อะไร”หน้านี้เป็น Evidence: Code-backed โดยสเตจต่าง ๆ จับคู่กับโครงสร้างจริงในรีโพซิทอรีหลัก ดังนี้:
- facade และการมอบหมายงานของ facade อยู่ใน
src/Core/Document.phpร่วมกับ concern trait ที่อยู่ในsrc/Core/Concerns/(การแสดงผลข้อความ เอาต์พุต การวาด หน้า ความปลอดภัย การจัดการตัวอักษร การนำทาง ทรานแซกชัน และอื่น ๆ โดยแต่ละตัวรับผิดชอบเรื่องเดียว) - เส้นทางเนื้อหาสองเส้นทางคือเอนจิน HTML/CSS (
src/Html/) และการวาดโดยตรง (src/Graphics/) ซึ่งทั้งสองเส้นทางป้อนเข้าสู่โมเดลภายใน - การซีเรียไลซ์และกลยุทธ์เวอร์ชัน PDF อยู่ใน
src/Writer/(PdfWriter.phpพร้อมคลาสกลยุทธ์ PDF 1.4 / 1.7 / 2.0 ที่ชัดเจน) - ขอบเขตระหว่างสถานะอายุระดับโปรเซสกับสถานะแบบต่อคำขอคือการออกแบบที่ปลอดภัยสำหรับ worker ซึ่งบันทึกไว้ในภาพรวมสถาปัตยกรรมและถูกนำมาใช้จริงในตัวอย่าง worker-factory ที่จัดส่งมาให้ โดยตัวอย่างนี้ใช้
FontRegistryและImageRegistryร่วมกันข้ามคำขอ ขณะที่สร้างDocumentขึ้นใหม่ทุกครั้ง
ปลายทางถูกกำหนดโดยรูปแบบไฟล์อย่างตายตัว เอาต์พุตจาก writer ต้องประกอบด้วยส่วนหัว ส่วนเนื้อหาของอ็อบเจกต์ ตารางการอ้างอิงข้าม และส่วนท้าย ตาม Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 การรวมภาระหน้าที่นั้นไว้ในสเตจเดียว คือสิ่งที่ทำให้เอนจินส่วนที่เหลือยังคงมุ่งเน้นเนื้อหา แทนที่จะมุ่งเน้นการประกอบโครงสร้างไฟล์
ตัวอย่างการใช้งานจริง
หัวข้อที่มีชื่อว่า “ตัวอย่างการใช้งานจริง”หน้าที่ของ facade คือทำให้เจตนาปรากฏในโค้ดอย่างตรงไปตรงมา เส้นทางเนื้อหาและ writer ยังคงถูกซ่อนไว้จากจุดเรียกใช้:
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone(); // facade$doc->setTitle('Quarterly Report'); // metadata concern$doc->addPage(); // pages concern$doc->setFont('helvetica', 'B', 16); // typography concern$doc->cell(0, 12, 'Summary', newLine: true); // text-output concern$doc->writeHtml('<p>Generated in-process.</p>'); // HTML content path$doc->save(__DIR__ . '/report.pdf'); // writer stageการเรียกใช้แต่ละครั้งจะส่งต่อไปยัง concern ที่แตกต่างกัน เส้นทางเนื้อหาสองเส้นทางป้อนข้อมูลเข้าสู่โมเดลเดียวกัน มีเพียงสเตจเดียวคือ save() ที่เปลี่ยนโมเดลให้กลายเป็นไบต์ของไฟล์ ไม่มีส่วนใดที่จุดเรียกใช้จำเป็นต้องรู้ว่าตารางการอ้างอิงข้ามถูกสร้างขึ้นอย่างไร
ความเข้าใจผิดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ความเข้าใจผิดที่พบบ่อย”การตีความผิดที่พบบ่อยคือการคิดว่า “pipeline” หมายถึง streaming push API ที่คุณต่อสายทีละสเตจ คล้ายกับ Unix pipe ความเป็นจริงไม่ใช่เช่นนั้น ไปป์ไลน์ในที่นี้คือการแยกย่อยเชิง สถาปัตยกรรม กล่าวคือ สเตจที่มีความรับผิดชอบเดียวและมีขอบเขตที่กำหนดชนิดข้อมูล คุณยังคงเขียนโปรแกรมโดยใช้ facade แบบ fluent อยู่ดี สเตจเหล่านี้เป็นวิธีที่เอนจินถูกสร้างและทดสอบ ไม่ใช่กลไกขนส่งข้อมูลที่คุณต้องประกอบเองด้วยมือ
ความเข้าใจผิดที่เกี่ยวข้องกันคือการสันนิษฐานว่า facade คือ เอนจิน facade เป็นจุดเข้าใช้งาน งานจริงถูกกระจายไปทั่ว concern trait เส้นทางเนื้อหาสองเส้นทาง และ writer การกระจายงานเช่นนี้เป็นเหตุผลโดยตรงที่ทำให้การเปลี่ยนแปลงฟีเจอร์หนึ่งไม่ทำให้เอาต์พุตทุกรายการตกอยู่ในความเสี่ยง
ข้อจำกัดและขอบเขต
หัวข้อที่มีชื่อว่า “ข้อจำกัดและขอบเขต”หน้านี้อธิบาย รูปทรง ของไปป์ไลน์ ไม่ใช่ API ภายในของสเตจใดสเตจหนึ่ง รายการ concern trait ที่แน่นอน กฎการเลือกกลยุทธ์ของ writer และฟิลด์ของโมเดลเนื้อหาถูกกำหนดโดยโค้ดและเอกสารอ้างอิง ไม่ใช่โดยคำอธิบายนี้ จำนวน trait ที่แน่นอนเป็นรายละเอียดการนำไปใช้งานซึ่งสามารถเปลี่ยนแปลงได้โดยไม่เปลี่ยนโมเดล หน้านี้ไม่ครอบคลุมสเตจภายในของเอนจิน HTML (เป็นหัวข้อแยกต่างหาก) หรือพฤติกรรมด้านการสตรีมและหน่วยความจำของ writer (แยกต่างหากเช่นกัน) ข้อกล่าวอ้างเชิงโครงสร้างถูกต้อง ณ วันที่ทบทวนของหน้านี้ แหล่งข้อมูลที่เชื่อถือได้คือ src/Core/ src/Html/ src/Graphics/ และ src/Writer/ ของรีโพซิทอรีหลัก
โมเดลไปป์ไลน์เหมือนกันทุกรุ่น โดยแต่ละรุ่นเพิ่มความสามารถภายในสเตจที่มีอยู่ ไม่ใช่เพิ่มสเตจใหม่:
| Edition | Availability |
|---|---|
| Core | Core นำไปป์ไลน์แบบ facade → content → writer ฉบับเต็มมาใช้งาน |
| Pro | Pro เพิ่มความสามารถภายในสเตจที่มีอยู่ ไม่ใช่เพิ่มสเตจใหม่ |
| Enterprise | Enterprise เพิ่มความสามารถภายในสเตจที่มีอยู่ ไม่ใช่เพิ่มสเตจใหม่ |
เอกสารที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “เอกสารที่เกี่ยวข้อง”- หน่วยความจำและการสตรีม — วิธีที่สเตจ writer ควบคุมหน่วยความจำให้อยู่ในขอบเขต
- ไปป์ไลน์ HTML — สเตจภายในของเส้นทางเนื้อหา HTML
- Strict types ทุกที่ — ขอบเขตที่กำหนดชนิดข้อมูลซึ่งทำให้แต่ละสเตจทดสอบได้อย่างเป็นอิสระ
อภิธานศัพท์
หัวข้อที่มีชื่อว่า “อภิธานศัพท์”- Facade — จุดเข้าใช้งานสาธารณะ โดย
Documentเป็น builder แบบ fluent ที่ใช้ครั้งเดียว ซึ่งบันทึกเจตนาและมอบหมายงานให้ concern trait - Concern trait — PHP trait ที่มุ่งเน้นเฉพาะด้านซึ่ง facade นำมาประกอบกัน โดยแต่ละตัวเป็นเจ้าของพื้นที่ฟีเจอร์เดียว (การแสดงผลข้อความ การวาด หน้า ความปลอดภัย และอื่น ๆ)
- Content path — หนึ่งในสองวิธีที่เนื้อหาเข้าสู่โมเดล ได้แก่ การวาดโดยตรงหรือเอนจิน HTML/CSS
- Document model — สถานะภายในเอนจินที่กำหนดชนิดข้อมูลสำหรับสะสมหน้า เนื้อหา และทรัพยากร ก่อนการซีเรียไลซ์
- Writer stage — คอมโพเนนต์ที่ซีเรียไลซ์โมเดลให้เป็น PDF ที่ถูกต้อง โดยเลือกกลยุทธ์แบบ PDF 1.4 / 1.7 / 2.0
- Worker-safe — ออกแบบมาให้สถานะระดับอายุโปรเซสถูกใช้ร่วมกันอย่างปลอดภัย ขณะที่สถานะแบบต่อคำขอถูกสร้างขึ้นใหม่และไม่นำกลับมาใช้ซ้ำ