跳转到内容

Symfony 开发者指南

Symfony 包采用 service 优先的设计。注入 PdfFactory,为每份文档调用 create(),并通过 Messenger builder 处理异步生成。由于每次调用都会返回一份全新的文档,这个 factory 可以作为 container service 注册。

当你设计 controller、service、Messenger handler,或围绕 nextpdf/symfony 的 bundle 层扩展点时,请参考本指南。

层级负责方职责不要放这里
Controller(控制器)应用程序对请求进行授权、收集输入,并返回 PdfResponse跨多个使用场景复用的 PDF 版式。
应用程序 service应用程序加载领域数据,并选择一个 builder。Symfony container 编译逻辑。
Builder service(构建器服务)应用程序实现 PdfBuilderInterface,用于同步构建或入队后的文档构建。请求对象、entity manager 或不可序列化的 context。
Symfony bundle(包)nextpdf/symfony注册 service、config tree、可选的 extension pass、响应辅助工具和 Messenger DTO。租户专属的存储策略。
核心引擎nextpdf/nextpdf构建并序列化文档。Symfony 响应或 Messenger 行为。
阶段行为开发者动作
Bundle 启动NextPdfBundle::build() 会注册对可选扩展功能的检测。让 Symfony 自动发现该 bundle,或在 bundles.php 中手动注册。
加载配置NextPdfExtension::load() 会处理 nextpdf: 配置并加载 service 定义。保持配置明确,并让其感知环境。
使用 factoryPdfFactory::create() 会返回一份全新且已完成配置的文档。不要把文档保存在 service 中。
Controller 输出PdfResponse 会将完成的文档转换为响应。使用此辅助工具,不要手动组装标头。
Messenger 派发GeneratePdfMessage 会携带 builder 类、输出路径和可序列化的 context。让 context 保持精简,并以标量为主。
处理消息GeneratePdfHandler 会通过 service locator 解析 builder 并保存文档。保持 builder 的确定性与幂等性。
路径用途
src/Pdf/Builder/*实现 PdfBuilderInterface 的 service。
src/Pdf/Data/*用作 builder context 的小型 DTO 或数组。
src/Pdf/Storage/*存储根目录的选择与输出文件名策略。
src/Controller/*同步响应入口。
tests/Pdf/*builder、响应、Messenger 和配置测试。

优先使用 builder service,而不是静态辅助函数。它们更易于标记、装饰和测试,也便于从 Messenger 中使用。

<?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');
}
}

让 controller 的 context 保持精简。如果某个 builder 需要大量领域对象,请把这段协调逻辑移到应用程序 service,再将 DTO 或规范化后的数组传给 builder。

GeneratePdfMessage 会在派发前验证 builder 类和输出路径。handler 会在执行时再次验证该路径。

<?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>',
],
));

不要把 Doctrine entity、打开的流、closure、请求对象或 service 对象放入 builderContext

扩展点适用场景限制
PdfFactory service 装饰在文档到达 controller 之前应用应用程序层面的默认值。必须保留全新文档的语义。
PdfBuilderInterface定义可入队或可复用的文档 builder。必须返回一个 Document
OptionalExtensionPass在编译期启用可选的 Artisan 或 Premium 功能。可用与否取决于 container 编译状态,而非请求状态。
Symfony config tree(配置树)默认值、PDF/A、renderer 设置、签名、TSA、Messenger。无效的配置应在 container 构建时就失败。
GeneratePdfHandler service 接线限制排队消息可访问的 builder。service locator 只应暴露已核准的 builder service。
  1. 新增一个输入具备确定性的 builder service。
  2. 在 controller 或 service 中使用 PdfFactory::create()
  3. 针对文件名、内容类型和标头新增响应测试。
  4. 当同一份文档必须异步生成时,为 Messenger 注册该 builder。
  5. 针对类名、输出路径和 context 结构,新增无效消息测试。
  6. 使用最小配置和生产环境配置,新增一个 container 编译测试。
  7. 在与生产环境相同的 PHP 设置下,测量 render 时间和内存用量。
失败应在何处处理建议的响应
无效配置Container 编译。在流量到达应用程序之前使部署失败。
缺少 builder serviceMessenger handler 测试与 service tag。让消息失败,并通知负责团队。
不安全的输出路径消息构造函数与存储策略。在派发前拒绝;handler 验证保留为纵深防御。
可选扩展功能不可用compiler pass 与 factory 行为。停用可选功能,或明确要求安装它。
service 转换或 render 失败builder 边界。除非该使用场景有书面记录的回退机制,否则一律 fail closed。
关注点默认值何时覆盖
Factory 生命周期Container service(容器服务)。保留此设置;factory 是安全的,因为它只负责创建文档。
文档生命周期一个工作单元。绝不要跨请求或跨消息共用。
输出路径验证消息构造函数与 handler。在应用程序代码中添加租户或存储根目录限制。
响应文件名document.pdf以净化后的业务标识符覆盖。
Messenger transport(Messenger 传输)async当 PDF 工作量很重时,使用专属 transport。
  • container 测试会使用最小配置和生产环境配置编译此 bundle。
  • 响应测试会验证安全标头和文件名处理。
  • Messenger 测试会验证无效路径和无效 builder 类名在派发前失败。
  • handler 测试会使用真实 builder service 和临时输出目录。
  • builder 测试会 render 一份有代表性的文档,并在类似生产环境的文件系统权限下保存它。
  • 可选扩展功能测试涵盖 Artisan 不可用、Premium 不可用以及已配置的 PDF/A profile 行为。