跳到內容

排解 NextPDF Symfony bundle 的問題

大多數問題都落在四個面向:探索、組態驗證、容器接線,或 Messenger 路由。以下各節會將症狀對應到 bundle 原始碼中負責驗證的行為,並提供一個主控台指令,用來確認修正是否生效。

症狀PdfFactory 無法自動注入,或 debug:container nextpdf 找不到任何項目。

原因:bundle 未加入 config/bundles.php。可能是 Flex 未執行,也可能是應用程式並未使用 Flex。

解法

Terminal window
php bin/console debug:container nextpdf

如果結果為空,請手動加入這個 bundle:

return [
NextPDF\Symfony\NextPdfBundle::class => ['all' => true],
];

自動註冊提示寫在 bundle 的 composer.json 裡,位於 extra.symfony.bundles 之下。它只會套用在啟用 Flex 的應用程式上。

症狀:核心在啟動時拋出 RuntimeException,訊息提到 ext-mbstringext-zlib

原因:這是 bundle 刻意設計的快速失敗(fail-fast)防護 NextPdfExtension::guardRequiredExtensions(),並不是缺陷。

解法:在 php.ini 中啟用指定的擴充套件,然後重新啟動執行環境。以下列指令確認:

Terminal window
php -m | grep -E 'mbstring|zlib'

症狀:出現 Symfony\Component\Config\Definition\Exception\InvalidConfigurationException,發生在 cache:clearcache:warmup 期間。

原因:某個值落在 schema 允許範圍之外。這些限制來自 Configuration.php

  • page_format 必須是 A4A3A5LetterLegalTabloid 其中之一。
  • orientation 必須是 PL
  • unit 必須是 ptmmcmin 其中之一。
  • pdfa 必須是 null44e,或 4f
  • image_cache_mb 必須 >= 0

解法:列印合併後的組態,再修正有問題的鍵:

Terminal window
php bin/console debug:config nextpdf

症狀pdfasignature 區段已設定,但輸出卻是一般的 PDF。

原因:這些功能需要 nextpdf/premiumPdfFactory 只有在編譯期偵測到 Pro 擴充套件時,才會套用 PDF/A。編譯器流程(compiler pass)只有signature.enabled 為 true signature.certificate 已設定時,才會註冊簽章器。

解法:確認 Premium 已安裝,且簽章器服務確實存在:

Terminal window
composer show nextpdf/premium
php bin/console debug:container --show-private | grep -i signer

若未安裝 Premium,bundle 會儲存該組態,但依設計會讓它維持不生效。bundle 文件所記載、搭配 Pro 的簽章能力,是基準的 B-B 設定檔。NextPDF Premium 文件則涵蓋 B-B 以外的其他設定檔。

症狀artisan 組態被忽略。

原因:Chrome CDP 算繪需要 nextpdf/artisan。編譯器流程會在編譯期以 class_exists 探測它。若缺少這個擴充套件,renderer(渲染器)就不會接線。

解法

Terminal window
composer show nextpdf/artisan
php bin/console cache:clear # re-run the compile-time probe

這項探測會在容器編譯期間執行。因此安裝完擴充套件後,要重新執行一次 cache:clear

症狀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。請先註冊該建構器,再從定位器引用它。

檢查路由與定位器:

Terminal window
php bin/console debug:messenger
php 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()。切勿將回傳的文件儲存在共用服務上。

Terminal window
php bin/console debug:container nextpdf # bundle services
php bin/console debug:config nextpdf # merged configuration
php bin/console debug:container --show-private # internal definitions
php bin/console debug:messenger # message routing
php bin/console messenger:consume <t> -vv # verbose consume

每一列都是本頁提出的一項規範性主張,並釘選到一個來自受管 SDO 語料庫的完整 64 位十六進位 reference_id。 provenance(來源資訊)涵蓋語料庫資訊清單與檢索傳輸,記載於 _sidecars/rag-citations.yaml 一檔。

規範條款參考 ID主張
PSR-11psr_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/ — 安全標頭與路徑驗證。