Hướng dẫn dành cho nhà phát triển Symfony
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Bundle Symfony lấy service làm trọng tâm. Hãy inject PdfFactory, gọi create() cho từng tài liệu Portable Document Format (PDF), rồi dùng builder của Messenger để tạo bất đồng bộ. Bạn có thể giữ factory dưới dạng service trong container vì mỗi lần gọi đều trả về một tài liệu mới.
Hãy dùng hướng dẫn này khi thiết kế controller, service, handler của Messenger hoặc các điểm mở rộng cấp bundle cho nextpdf/symfony.
Ranh giới kiến trúc
Phần tiêu đề “Ranh giới kiến trúc”| Lớp | Sở hữu bởi | Trách nhiệm | Không đặt vào đây |
|---|---|---|---|
| Controller | Ứng dụng | Kiểm tra quyền của yêu cầu, thu thập dữ liệu đầu vào, và trả về PdfResponse. | Bố cục PDF dùng chung cho nhiều trường hợp sử dụng. |
| Service ứng dụng | Ứng dụng | Tải dữ liệu nghiệp vụ và chọn builder. | Logic biên dịch container Symfony. |
| Service builder | Ứng dụng | Triển khai PdfBuilderInterface để dựng tài liệu đồng bộ hoặc qua hàng đợi. | Đối tượng request, entity manager, hoặc ngữ cảnh không thể tuần tự hóa. |
| Bundle Symfony | nextpdf/symfony | Đăng ký các service, cây cấu hình, compiler pass tùy chọn, helper cho response, và các đối tượng truyền dữ liệu (DTO) của Messenger. | Chính sách lưu trữ riêng cho từng tenant. |
| Engine lõi | nextpdf/nextpdf | Tạo và tuần tự hóa tài liệu. | Hành vi của response Symfony hoặc Messenger. |
Vòng đời lúc chạy
Phần tiêu đề “Vòng đời lúc chạy”| Giai đoạn | Hành vi | Hành động của nhà phát triển |
|---|---|---|
| Khởi động bundle | NextPdfBundle::build() đăng ký cơ chế phát hiện phần mở rộng tùy chọn. | Hãy để Symfony tự phát hiện bundle hoặc đăng ký bundle trong bundles.php. |
| Tải cấu hình | NextPdfExtension::load() xử lý cấu hình nextpdf: và tải các định nghĩa service. | Giữ cấu hình rõ ràng và phù hợp với từng môi trường. |
| Dùng factory | PdfFactory::create() trả về một tài liệu mới đã được cấu hình. | Không lưu tài liệu trong các service. |
| Đầu ra của controller | PdfResponse biến một tài liệu đã hoàn tất thành một response. | Hãy dùng helper thay vì tự lắp ráp các header bằng tay. |
| Gửi qua Messenger | GeneratePdfMessage mang theo lớp builder, đường dẫn đầu ra, và ngữ cảnh có thể tuần tự hóa. | Giữ ngữ cảnh tối giản và thân thiện với kiểu vô hướng. |
| Xử lý message | GeneratePdfHandler phân giải builder từ service locator và lưu tài liệu. | Hãy thiết kế builder sao cho tất định và bất biến (idempotent). |
Cấu trúc ứng dụng được khuyến nghị
Phần tiêu đề “Cấu trúc ứng dụng được khuyến nghị”| Đường dẫn | Mục đích |
|---|---|
src/Pdf/Builder/* | Các service triển khai PdfBuilderInterface. |
src/Pdf/Data/* | Các DTO nhỏ hoặc mảng dùng làm ngữ cảnh cho builder. |
src/Pdf/Storage/* | Chính sách chọn thư mục gốc lưu trữ và đặt tên tệp đầu ra. |
src/Controller/* | Các điểm vào trả về response đồng bộ. |
tests/Pdf/* | Các bài kiểm thử cho builder, response, Messenger, và cấu hình. |
Hãy ưu tiên các service builder thay vì các hàm helper tĩnh. Chúng dễ gắn tag, decorate, kiểm thử và dùng từ Messenger hơn.
<?php
namespace App\Pdf\Builder;
use NextPDF\Core\Document;use NextPDF\Symfony\Message\PdfBuilderInterface;
final readonly class InvoicePdfBuilder implements PdfBuilderInterface{ public function build(Document $document, array $context): Document { $document->setTitle((string) $context['title']) ->addPage() ->writeHtml((string) $context['html']);
return $document; }}Mẫu response đồng bộ
Phần tiêu đề “Mẫu response đồng bộ”<?php
namespace App\Controller;
use App\Pdf\Builder\InvoicePdfBuilder;use NextPDF\Symfony\Http\PdfResponse;use NextPDF\Symfony\Service\PdfFactory;
final readonly class InvoiceController{ public function __invoke( PdfFactory $factory, InvoicePdfBuilder $builder, ) { $document = $builder->build($factory->create(), [ 'title' => 'Invoice 1234', 'html' => '<h1>Invoice 1234</h1>', ]);
return PdfResponse::download($document, 'invoice-1234.pdf'); }}Giữ ngữ cảnh của controller nhỏ gọn. Khi builder cần nhiều đối tượng nghiệp vụ, hãy chuyển phần điều phối vào service ứng dụng và truyền cho builder một DTO hoặc một mảng đã chuẩn hóa.
Mẫu Messenger
Phần tiêu đề “Mẫu Messenger”GeneratePdfMessage kiểm tra lớp builder và đường dẫn đầu ra trước khi gửi. Handler kiểm tra lại đường dẫn khi chạy.
<?php
use App\Pdf\Builder\InvoicePdfBuilder;use NextPDF\Symfony\Message\GeneratePdfMessage;
$bus->dispatch(new GeneratePdfMessage( builderClass: InvoicePdfBuilder::class, outputPath: $projectDir . '/var/pdfs/invoice-1234.pdf', builderContext: [ 'title' => 'Invoice 1234', 'html' => '<h1>Invoice 1234</h1>', ],));Không đặt entity của Doctrine, luồng đang mở, closure, đối tượng request hoặc đối tượng service vào builderContext.
Các điểm mở rộng
Phần tiêu đề “Các điểm mở rộng”| Điểm mở rộng | Dùng cho | Ràng buộc |
|---|---|---|
PdfFactory decorate service | Áp dụng các giá trị mặc định của ứng dụng trước khi tài liệu đến controller. | Phải giữ nguyên ngữ nghĩa tạo tài liệu mới. |
PdfBuilderInterface | Định nghĩa các builder tài liệu dùng cho hàng đợi hoặc có thể tái sử dụng. | Phải trả về một Document. |
OptionalExtensionPass | Bật các tính năng tùy chọn của Artisan hoặc Premium lúc biên dịch. | Tính khả dụng là trạng thái biên dịch container, không phải trạng thái của yêu cầu. |
| Cây cấu hình Symfony | Giá trị mặc định, PDF/A, thiết lập bộ kết xuất, chữ ký, cơ quan cấp dấu thời gian (TSA), và Messenger. | Cấu hình không hợp lệ phải gây lỗi trong quá trình dựng container. |
GeneratePdfHandler kết nối service | Giới hạn những builder có thể được truy cập từ các message trong hàng đợi. | Service locator chỉ nên phơi bày các service builder đã được phê duyệt. |
Quy trình phát triển
Phần tiêu đề “Quy trình phát triển”- Thêm một service builder với dữ liệu đầu vào có tính tất định.
- Dùng
PdfFactory::create()trong một controller hoặc service. - Thêm một bài kiểm thử response cho tên tệp, kiểu nội dung, và các header.
- Đăng ký builder với Messenger khi cùng một tài liệu cần được tạo bất đồng bộ.
- Thêm các bài kiểm thử message không hợp lệ cho tên lớp, đường dẫn đầu ra, và dạng của ngữ cảnh.
- Thêm một bài kiểm thử biên dịch container với cấu hình tối giản và cấu hình giống môi trường production.
- Đo thời gian kết xuất và bộ nhớ với cùng các thiết lập PHP như môi trường production.
Xử lý lỗi
Phần tiêu đề “Xử lý lỗi”| Lỗi | Nơi nên xử lý | Phản hồi được khuyến nghị |
|---|---|---|
| Cấu hình không hợp lệ | Biên dịch container. | Để triển khai thất bại trước khi lưu lượng đến được ứng dụng. |
| Thiếu service builder | Các bài kiểm thử handler của Messenger và các service tag. | Để message thất bại và cảnh báo nhóm phụ trách. |
| Đường dẫn đầu ra không an toàn | Constructor của message và chính sách lưu trữ. | Từ chối trước khi gửi; giữ phần kiểm tra ở handler như một lớp phòng vệ theo chiều sâu. |
| Phần mở rộng tùy chọn không khả dụng | Hành vi của compiler pass và factory. | Tắt tính năng tùy chọn hoặc yêu cầu cài đặt rõ ràng. |
| Chuyển đổi service hoặc kết xuất thất bại | Ranh giới của builder. | Thất bại an toàn (fail closed) trừ khi trường hợp sử dụng có phương án dự phòng đã được ghi chép. |
Giá trị mặc định an toàn
Phần tiêu đề “Giá trị mặc định an toàn”| Mối quan tâm | Mặc định | Khi nào nên ghi đè |
|---|---|---|
| Vòng đời của factory | Service trong container. | Hãy giữ mặc định này; factory an toàn vì nó tạo ra các tài liệu mới. |
| Vòng đời của tài liệu | Một đơn vị công việc. | Không bao giờ chia sẻ giữa các yêu cầu hoặc các message. |
| Kiểm tra đường dẫn đầu ra | Constructor của message và handler. | Thêm các ràng buộc về tenant hoặc thư mục gốc lưu trữ trong mã ứng dụng. |
| Tên tệp của response | document.pdf. | Ghi đè bằng các định danh nghiệp vụ đã được làm sạch. |
| Transport của Messenger | async. | Dùng transport riêng khi công việc PDF nặng. |
Danh sách kiểm tra khi kiểm thử
Phần tiêu đề “Danh sách kiểm tra khi kiểm thử”- Các bài kiểm thử container biên dịch bundle với cấu hình tối giản và cấu hình giống môi trường production.
- Các bài kiểm thử response xác nhận các header bảo mật và cách xử lý tên tệp.
- Các bài kiểm thử Messenger xác nhận đường dẫn không hợp lệ và tên lớp builder không hợp lệ sẽ thất bại trước khi gửi.
- Các bài kiểm thử handler dùng một service builder thật và một thư mục đầu ra tạm thời.
- Các bài kiểm thử builder kết xuất một tài liệu đại diện và lưu nó với quyền hệ thống tệp giống môi trường production.
- Các bài kiểm thử phần mở rộng tùy chọn bao gồm trường hợp Artisan không khả dụng, Premium không khả dụng, và hành vi của profile PDF/A đã cấu hình.