เริ่มต้นใช้งาน NextPDF Symfony แบบรวดเร็ว
ภาพรวมโดยย่อ
หัวข้อที่มีชื่อว่า “ภาพรวมโดยย่อ”Inject PdfFactory เพื่อสร้าง Document แล้วส่งคืนผ่าน PdfResponse เมื่อต้องการสร้างเอกสารในเบื้องหลัง ให้ dispatch GeneratePdfMessage ไปยัง transport ของ Messenger
ขั้นที่ 1 — สร้าง PDF ใน controller
หัวข้อที่มีชื่อว่า “ขั้นที่ 1 — สร้าง PDF ใน controller”Inject NextPDF\Symfony\Service\PdfFactory เมท็อด create() จะส่งคืน NextPDF\Core\Document ใหม่ และใช้ค่าเริ่มต้นที่กำหนดไว้สำหรับผู้สร้าง ผู้แต่ง และภาษา ใช้ NextPDF\Symfony\Http\PdfResponse เพื่อส่งคืนเอกสาร
<?php
declare(strict_types=1);
namespace App\Controller;
use NextPDF\Symfony\Http\PdfResponse;use NextPDF\Symfony\Service\PdfFactory;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\Routing\Attribute\Route;
final class InvoiceController{ #[Route('/invoice/{number}', name: 'invoice_pdf')] public function download(PdfFactory $pdf, string $number): Response { $doc = $pdf->create(); $doc->addPage(); $doc->cell(0, 10, "Invoice #{$number}", newLine: true); $doc->cell(0, 10, 'Thank you for your business.');
return PdfResponse::download($doc, "invoice-{$number}.pdf"); }}PdfResponse::download() จะส่งคืน Symfony\Component\HttpFoundation\Response โดยตั้งค่า Content-Type: application/pdf, disposition แบบ attachment, Content-Length และ security header ที่ bundle กำหนดไว้ตายตัว เอกสารของ Symfony อธิบายคลาส Response มาตรฐานและโมเดล header ไว้ที่ (https://symfony.com/doc/current/components/http_foundation.html)
ขั้นที่ 2 — แสดง PDF แบบ inline
หัวข้อที่มีชื่อว่า “ขั้นที่ 2 — แสดง PDF แบบ inline”ใช้ inline() เมื่อต้องการให้เบราว์เซอร์แสดง PDF แทนการดาวน์โหลด:
return PdfResponse::inline($doc, 'preview.pdf');disposition จะเปลี่ยนเป็น inline ส่วน header อื่นทั้งหมดจะคงเดิม
ขั้นที่ 3 — สตรีม PDF ขนาดใหญ่
หัวข้อที่มีชื่อว่า “ขั้นที่ 3 — สตรีม PDF ขนาดใหญ่”สำหรับเอกสารขนาดใหญ่ ให้ใช้รูปแบบการสตรีม ซึ่งจะส่งออก PDF เป็นชังก์ขนาด 64 KB เพื่อช่วยลดการใช้หน่วยความจำสูงสุด โดยจะส่งคืน Symfony\Component\HttpFoundation\StreamedResponse และเว้น Content-Length ไว้
return PdfResponse::streamDownload($doc, 'annual-report.pdf');ใช้ streamInline() สำหรับการสตรีมแบบ inline เอกสารของ Symfony อธิบายสัญญาของ callback ของ StreamedResponse ว่าเป็น callable แบบ void ที่ flush เอาต์พุต (https://symfony.com/doc/current/components/http_foundation.html)
ขั้นที่ 4 — สร้าง PDF แบบอะซิงโครนัส
หัวข้อที่มีชื่อว่า “ขั้นที่ 4 — สร้าง PDF แบบอะซิงโครนัส”หลังจากติดตั้ง symfony/messenger แล้ว สามารถย้ายงานสร้างออกจากเธรดของคำขอได้
4a — สร้าง builder
หัวข้อที่มีชื่อว่า “4a — สร้าง builder”สร้าง implementation ของ NextPDF\Symfony\Message\PdfBuilderInterface handler จะมอบ Document ใหม่ที่กำหนดค่าไว้ล่วงหน้า พร้อม context ที่ serialize ได้จากข้อความให้กับ implementation นั้น
<?php
declare(strict_types=1);
namespace App\Pdf;
use NextPDF\Core\Document;use NextPDF\Symfony\Message\PdfBuilderInterface;
final class InvoicePdfBuilder implements PdfBuilderInterface{ public function build(Document $document, array $context): Document { $document->addPage(); $document->setFont('dejavusans', '', 12); $document->cell(0, 10, 'Invoice #' . $context['invoice_id']);
return $document; }}4b — ลงทะเบียน builder ใน locator
หัวข้อที่มีชื่อว่า “4b — ลงทะเบียน builder ใน locator”handler จะ resolve builder จาก service locator ตาม PHP Standard Recommendation 11 (PSR-11) โดยใช้ชื่อคลาสเป็นคีย์ เฉพาะ builder ที่ลงทะเบียนแล้วเท่านั้นจึงจะเข้าถึงได้ เพิ่ม builder ลงใน locator ภายใน config/services.yaml:
services: App\Pdf\InvoicePdfBuilder: ~
nextpdf.pdf_builder_locator: class: Symfony\Component\DependencyInjection\ServiceLocator arguments: - 'App\Pdf\InvoicePdfBuilder': '@App\Pdf\InvoicePdfBuilder' tags: ['container.service_locator']
NextPDF\Symfony\Message\GeneratePdfHandler: arguments: $builderLocator: '@nextpdf.pdf_builder_locator'handler จะร้องขอ builder จาก locator ด้วย id ที่เป็น class-string ของ builder นั้น ใน PSR-11 ตัวระบุของ container คือสตริงที่ระบุรายการได้อย่างไม่ซ้ำกัน (PSR-11 §1.1.2)
4c — Dispatch ข้อความ
หัวข้อที่มีชื่อว่า “4c — Dispatch ข้อความ”Inject Symfony\Component\Messenger\MessageBusInterface แล้ว dispatch ข้อความ:
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Pdf\InvoicePdfBuilder;use NextPDF\Symfony\Message\GeneratePdfMessage;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\Messenger\MessageBusInterface;use Symfony\Component\Routing\Attribute\Route;
final class ReportController{ #[Route('/invoice/{id}/queue', name: 'invoice_queue')] public function queue(MessageBusInterface $bus, int $id): Response { $bus->dispatch(new GeneratePdfMessage( builderClass: InvoicePdfBuilder::class, outputPath: '/var/storage/invoices/' . $id . '.pdf', builderContext: ['invoice_id' => $id], ));
return new Response('PDF generation queued.', 202); }}GeneratePdfMessage เป็น data transfer object (DTO) แบบ readonly โดย constructor จะปฏิเสธพาธเอาต์พุตที่ว่างเปล่า ไม่ลงท้ายด้วย .pdf มีส่วนที่เป็น path-traversal ใช้สคีมแบบ stream-wrapper หรือมี null byte นอกจากนี้ยังบังคับให้ builderClass ต้องเป็นชื่อคลาสที่ถูกต้องตามไวยากรณ์ handler จะตรวจสอบพาธเอาต์พุตอีกครั้งตอนทำงานก่อนเขียน หากพาธปลอดภัยตอน dispatch แต่ไม่ปลอดภัยตอน consume handler ก็ยังคงปฏิเสธพาธนั้น แอตทริบิวต์ #[AsMessageHandler] และสัญญาการ dispatch ของ MessageBusInterface เป็นไปตามโมเดล Symfony Messenger มาตรฐาน (https://symfony.com/doc/current/messenger.html)
4d — กำหนดเส้นทางข้อความและรัน worker
หัวข้อที่มีชื่อว่า “4d — กำหนดเส้นทางข้อความและรัน worker”ใน config/packages/messenger.yaml ให้กำหนดเส้นทางข้อความไปยัง transport:
framework: messenger: transports: async: '%env(MESSENGER_TRANSPORT_DSN)%' routing: NextPDF\Symfony\Message\GeneratePdfMessage: asyncจากนั้นรัน worker:
php bin/console messenger:consume asyncตรวจสอบว่าทำงานได้
หัวข้อที่มีชื่อว่า “ตรวจสอบว่าทำงานได้”php bin/console debug:container --tag=container.service_locatorphp bin/console messenger:consume async --limit=1 -vvคำสั่งแรกยืนยันว่า builder locator ถูกลงทะเบียนแล้ว คำสั่งที่สองจะ consume ข้อความในคิวหนึ่งข้อความและพิมพ์ความคืบหน้าของ handler
ขั้นตอนถัดไป
หัวข้อที่มีชื่อว่า “ขั้นตอนถัดไป”- /integrations/symfony/configuration/ — ปรับค่าเริ่มต้น ฟอนต์ และ document service
- /integrations/symfony/production-usage/ — ทบทวนความปลอดภัยของ worker และการสตรีมภายใต้ภาระงานสูง
- /integrations/symfony/troubleshooting/ — แก้ปัญหาที่พบบ่อยตอน boot และ runtime
ความสอดคล้อง
หัวข้อที่มีชื่อว่า “ความสอดคล้อง”แต่ละแถวคือข้อความเชิงบรรทัดฐานที่ระบุในหน้านี้ และเชื่อมโยงกับ reference_id แบบ 64-hex เต็มจากคลังของ standards development organization (SDO) ที่มีการควบคุมการเข้าถึง _sidecars/rag-citations.yaml มีข้อมูลแหล่งที่มา รวมถึง manifest ของคลังและ transport สำหรับการเรียกข้อมูล
| ข้อกำหนด | ข้อ | รหัสอ้างอิง (reference_id) | ข้อความที่อ้าง |
|---|---|---|---|
| PSR-11 | psr_11_container#1.1.2.p4 | สัญญาตัวระบุของ has()/get() ของ Container |
ดูเพิ่มเติม
หัวข้อที่มีชื่อว่า “ดูเพิ่มเติม”- /integrations/symfony/overview/ — ทบทวนสรุปความสามารถ
- /integrations/symfony/install/ — ติดตั้งและลงทะเบียน bundle
- /integrations/symfony/integration/ — ทบทวนเอกสารอ้างอิงการเชื่อมต่อแบบ end-to-end