Bỏ qua để đến nội dung

Hướng dẫn dành cho nhà phát triển Symfony

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.

LớpSở hữu bởiTrách nhiệmKhông đặt vào đây
ControllerỨng dụngKiể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ụngTải dữ liệu nghiệp vụ và chọn builder.Logic biên dịch container Symfony.
Service builderỨng dụngTriể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 Symfonynextpdf/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õinextpdf/nextpdfTạo và tuần tự hóa tài liệu.Hành vi của response Symfony hoặc Messenger.
Giai đoạnHành viHành động của nhà phát triển
Khởi động bundleNextPdfBundle::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ìnhNextPdfExtension::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 factoryPdfFactory::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 controllerPdfResponse 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 MessengerGeneratePdfMessage 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ý messageGeneratePdfHandler 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).
Đường dẫnMụ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;
}
}
<?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.

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.

Điểm mở rộngDùng choRà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.
OptionalExtensionPassBậ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 SymfonyGiá 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 serviceGiớ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.
  1. Thêm một service builder với dữ liệu đầu vào có tính tất định.
  2. Dùng PdfFactory::create() trong một controller hoặc service.
  3. Thêm một bài kiểm thử response cho tên tệp, kiểu nội dung, và các header.
  4. Đăng ký builder với Messenger khi cùng một tài liệu cần được tạo bất đồng bộ.
  5. 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.
  6. 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.
  7. Đ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.
LỗiNơ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 builderCá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ànConstructor 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ụngHà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ạiRanh 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.
Mối quan tâmMặc địnhKhi nào nên ghi đè
Vòng đời của factoryService 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ệuMộ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 raConstructor 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 responsedocument.pdf.Ghi đè bằng các định danh nghiệp vụ đã được làm sạch.
Transport của Messengerasync.Dùng transport riêng khi công việc PDF nặng.
  • 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.