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

โมเดลไปป์ไลน์

Spec: 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 มีความปลอดภัย

วิธีที่ชัดเจนที่สุดในการทำความเข้าใจโมเดลนี้คือการติดตามเอกสารตั้งแต่การเรียกใช้ไปจนถึงไบต์

  1. Document facade Fluent, use-once builder; records intent via concern traits.
  2. Content production Direct drawing or the HTML/CSS engine — both build one document model.
  3. Document model Accumulated pages, content, and resources held as typed state.
  4. PDF writer Serialises the model; selects a PDF 1.4 / 1.7 / 2.0 strategy.
  5. Conforming PDF Header, object body, cross-reference table, trailer.
เส้นทางของเอกสารผ่าน NextPDF: แต่ละสเตจมีความรับผิดชอบเดียวและมีขอบเขตที่กำหนดชนิดข้อมูล จึงสามารถใช้เหตุผลพิจารณาและทดสอบได้อย่างเป็นอิสระ

การตัดสินใจด้านการออกแบบสองประการทำให้สิ่งนี้เป็นมากกว่าแผนภาพ

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 การรวมภาระหน้าที่นั้นไว้ในสเตจเดียว คือสิ่งที่ทำให้เอนจินส่วนที่เหลือยังคงมุ่งเน้นเนื้อหา แทนที่จะมุ่งเน้นการประกอบโครงสร้างไฟล์

หน้าที่ของ 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/ ของรีโพซิทอรีหลัก

โมเดลไปป์ไลน์เหมือนกันทุกรุ่น โดยแต่ละรุ่นเพิ่มความสามารถภายในสเตจที่มีอยู่ ไม่ใช่เพิ่มสเตจใหม่:

Pipeline model (โมเดลแบบไปป์ไลน์) — edition availability
Edition Availability
Core Core นำไปป์ไลน์แบบ facade → content → writer ฉบับเต็มมาใช้งาน
Pro Pro เพิ่มความสามารถภายในสเตจที่มีอยู่ ไม่ใช่เพิ่มสเตจใหม่
Enterprise Enterprise เพิ่มความสามารถภายในสเตจที่มีอยู่ ไม่ใช่เพิ่มสเตจใหม่
  • 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 — ออกแบบมาให้สถานะระดับอายุโปรเซสถูกใช้ร่วมกันอย่างปลอดภัย ขณะที่สถานะแบบต่อคำขอถูกสร้างขึ้นใหม่และไม่นำกลับมาใช้ซ้ำ