排查 NextPDF Symfony bundle 问题
重点摘要
标题为“重点摘要”的章节多数问题集中在四个方面:发现、配置验证、容器接线或 Messenger 路由。以下各节都会把一个症状对应到 bundle 源码中负责验证的行为,并提供一条控制台命令,用来确认修复是否生效。
bundle 未注册
标题为“bundle 未注册”的章节症状:PdfFactory 无法自动注入,或者 debug:container nextpdf 找不到任何条目。
原因:bundle 未加入 config/bundles.php。可能是 Flex 没有执行,也可能是该应用根本没有使用 Flex。
解法:
php bin/console debug:container nextpdf如果结果为空,请手动加入这个 bundle:
return [ NextPDF\Symfony\NextPdfBundle::class => ['all' => true],];自动注册提示写在 bundle 的 composer.json 中,位于 extra.symfony.bundles 下。它只会在启用 Flex 的应用中生效。
启动失败,缺少 PHP 扩展
标题为“启动失败,缺少 PHP 扩展”的章节症状:核心在启动期间抛出 RuntimeException,消息中提到 ext-mbstring 或 ext-zlib。
原因:这是 bundle 有意设计的快速失败(fail-fast)防护,位于 NextPdfExtension::guardRequiredExtensions()。这不是缺陷。
解法:在 php.ini 中启用消息中指明的扩展,然后重启执行环境。使用以下命令确认:
php -m | grep -E 'mbstring|zlib'配置在构建期被拒绝
标题为“配置在构建期被拒绝”的章节症状:出现 Symfony\Component\Config\Definition\Exception\InvalidConfigurationException,发生于 cache:clear 或 cache:warmup 期间。
原因:某个值超出了 schema 允许的范围。这些限制定义在 Configuration.php 中:
page_format必须是A4、A3、A5、Letter、Legal或Tabloid之一。orientation必须是P或L。unit必须是pt、mm、cm或in之一。pdfa必须是null、4、4e或4f。image_cache_mb必须满足>= 0。
解法:打印合并后的配置,并修正出问题的键:
php bin/console debug:config nextpdfPDF/A 或签章未生效
标题为“PDF/A 或签章未生效”的章节症状:pdfa 或 signature 区段已设置,但输出仍是普通 PDF。
原因:这些功能需要 nextpdf/premium。PdfFactory 只有在编译期检测到 Pro 扩展时,才会应用 PDF/A。编译器流程(compiler pass)只有在 signature.enabled 为 true 且 signature.certificate 已设置时,才会注册签章器。
解法:确认 Premium 已安装,并且签章器服务确实存在:
composer show nextpdf/premiumphp bin/console debug:container --show-private | grep -i signer如果没有安装 Premium,bundle 会保存该配置,但按设计不会让它生效。bundle 文档中记载的、与 Pro 搭配使用的签章能力,是基准的 B-B 配置文件。NextPDF Premium 文档涵盖 B-B 以外的其他配置文件。
Chrome 渲染没有响应
标题为“Chrome 渲染没有响应”的章节症状:artisan 配置被忽略。
原因:Chrome CDP 渲染需要 nextpdf/artisan。编译器流程会在编译期通过 class_exists 探测它。如果缺少这个扩展,renderer(渲染器)就不会接入容器。
解法:
composer show nextpdf/artisanphp bin/console cache:clear # re-run the compile-time probe这项探测会在容器编译期间执行。因此安装完扩展后,需要重新执行一次 cache:clear。
Messenger 处理器从未被调用
标题为“Messenger 处理器从未被调用”的章节症状:GeneratePdfMessage 已派送,但没有写出任何 PDF。
原因与解法:
- 消息未路由 — 添加一条路由设置,把
NextPDF\Symfony\Message\GeneratePdfMessage对应到config/packages/messenger.yaml中的某个传输(transport),再启动一个 worker(php bin/console messenger:consume <transport>)。 - 构建器不在定位器中 — 处理器会使用类字符串 ID 从 PSR-11 定位器(locator)取得构建器。容器标识符是一个字符串,用来唯一标识某个项目(PSR-11 §1.1.2)。如果定位器没有注册该构建器类,处理器就会抛出
RuntimeException,说明所设置的构建器必须实现PdfBuilderInterface。请先注册该构建器,再从定位器引用它。
查看路由与定位器:
php bin/console debug:messengerphp bin/console debug:container --tag=container.service_locator消息在派送时被 InvalidArgumentException 拒绝
标题为“消息在派送时被 InvalidArgumentException 拒绝”的章节症状:构建 GeneratePdfMessage 时抛出 InvalidArgumentException。
原因:消息的数据传输对象(DTO)会校验输入。当前会拒绝的规则如下:
- 输出路径为空,或路径中含有 null 字节;
- 使用了 stream-wrapper 协议(例如
php://...); - 含有
..的路径穿越(path-traversal)片段(POSIX 或 Windows 分隔符均适用); - 输出路径未以
.pdf结尾(不区分大小写); - 它的
builderClass不是语法上有效的类名称。
解法:传入一个以 .pdf 结尾的绝对文件系统路径,以及一个真实、完全限定的构建器类名称。
文件包含过时数据
标题为“文件包含过时数据”的章节症状:生成的 PDF 含有上一次请求的内容。
原因:某个 Document 实例在长时间运行的 worker 中跨请求被保留下来。文件服务被刻意设置为非共享,正是为了防止这种情况。
解法:在请求作用域内的方法中调用 PdfFactory::create()。切勿把返回的文件存储在共享服务上。
诊断命令参考
标题为“诊断命令参考”的章节php bin/console debug:container nextpdf # bundle servicesphp bin/console debug:config nextpdf # merged configurationphp bin/console debug:container --show-private # internal definitionsphp bin/console debug:messenger # message routingphp bin/console messenger:consume <t> -vv # verbose consume符合性
标题为“符合性”的章节每一行都是本页提出的一项规范性主张,并固定关联到一个来自受管 SDO 语料库的完整 64 位十六进制 reference_id。provenance(来源信息)涵盖语料库信息清单与检索传输,记录在 _sidecars/rag-citations.yaml 文件中。
| 规范 | 条款 | 参考 ID | 主张 |
|---|---|---|---|
| PSR-11 | psr_11_container#1.1.2.p4 | 容器 has()/get() 标识符合约 |
另请参阅
标题为“另请参阅”的章节- /integrations/symfony/install/ — 安装与注册。
- /integrations/symfony/configuration/ — 完整 schema 与限制。
- /integrations/symfony/boot-and-discovery/ — 发现与启动顺序。
- /integrations/symfony/security-and-operations/ — 安全标头与路径验证。