跳到內容

擴充功能開發:公開 SPI 總覽

NextPDF 對外開放一組精簡且有意設計的公開契約,全部位於 NextPDF\ContractsNextPDF\Event 這兩個命名空間(namespace)裡。實作這些契約後,你就能加入字型、攔截文字、觀察文件生命週期,或提供自己的簽章後端(backend),完全不必 fork 這個引擎。

Terminal window
composer require nextpdf/core:^3

NextPDF 將**公開服務供應介面(SPI)**與內部程式碼分開。SPI 是一組供你實作或觀察的型別。其餘一切都屬於私有範圍,可能在不另行通知的情況下變動。

公開 SPI 有三種型態:

  • **註冊表契約。**這是行程生命週期層級的服務,你會在建立文件前先完成設定;FontRegistryInterfaceImageRegistryInterface 是主要例子。你註冊這些資產,引擎再讀取它們。
  • **策略契約。**這是引擎在算繪過程中呼叫的單次任務掛鉤。TextPreprocessorInterface 負責版面配置階段的文字攔截,而 HtmlSecurityPolicyInterface 則用來控管 HTML 功能。你提供行為,引擎負責驅動。
  • **簽章契約。**這是密碼學後端(backend)契約。SignerInterfaceHsmSignerInterfaceDeferredSignerInterface 讓你自行提供金鑰保管與簽章產生。引擎建構 CMS 結構,而你的程式碼掌握金鑰。

觀察功能則由 NextPDF\Event 中一套獨立、相容於 PSR-14 的事件系統負責。生命週期事件讓你能回應文件建立、新頁面、字型載入、簽章與寫出。它們不會改變引擎的行為。

每個契約在其原始碼的 PHPDoc 裡都帶有一個 @stability 標籤:stable(穩定)、experimental(實驗性)或 deprecated(已棄用)。這個標籤加上每個契約各自的向後相容承諾,會說明你可以預期的變動幅度。完整政策請見 SPI 穩定性規則一節。

功能公開契約穩定性
字型註冊與查詢NextPDF\Contracts\FontRegistryInterface穩定(自 1.7.0 起)
影像快取與解碼NextPDF\Contracts\ImageRegistryInterface穩定(自 2.0.0 起)
版面配置階段的文字攔截NextPDF\Contracts\TextPreprocessorInterface穩定(自 1.9.0 起)
HTML 功能控管NextPDF\Contracts\HtmlSecurityPolicyInterface穩定(自 3.1.0 起)
文件工廠串接NextPDF\Contracts\DocumentFactoryInterface穩定(自 1.7.0 起)
同步簽章NextPDF\Contracts\SignerInterface穩定(自 1.0.0 起)
硬體後端簽章NextPDF\Contracts\HsmSignerInterface穩定(自 1.0.0 起)
延後簽章與批次簽章NextPDF\Contracts\DeferredSignerInterface實驗性(自 3.0.0 起)
RFC 3161 時間戳記NextPDF\Contracts\TimestampProviderInterface實驗性(自 3.0.0 起)
生命週期觀察NextPDF\Event\*(相容於 PSR-14)派發器穩定;酬載為實驗性

以下這些都屬於內部範圍。請勿匯入、繼承或依賴它們:

  • 任何位於 NextPDF\ContractsNextPDF\Event 命名空間以外的類別,除非它的 PHPDoc 帶有 @stability 標籤。
  • 具體的引擎程式碼,例如 HTML 剖析器、寫出器、版面配置流程與字型子集化器。
  • NextPDF Pro 與 NextPDF Enterprise 套件。它們的內部類別並不屬於開放原始碼的對外範圍。當付費版本隨附某個 SPI 實作時,你使用的是公開契約,而不是它的內部型別。

權威清單是自動產生的契約對照表。它會在每次發行時從原始碼重新建立。請把每個介面檔案裡的 @stability PHPDoc 標籤視為唯一的事實來源。上表僅供輔助閱讀。

先註冊一個字型,再觀察它何時載入。這兩個步驟都只使用公開型別。

<?php
declare(strict_types=1);
use NextPDF\Contracts\FontRegistryInterface;
use NextPDF\Event\Content\FontLoadedEvent;
use NextPDF\Event\EventDispatcher;
use NextPDF\Event\ListenerProvider;
/** @var FontRegistryInterface $fonts */
$fonts->register('/srv/fonts/Inter-Regular.ttf', 'Inter');
$listeners = new ListenerProvider();
$listeners->addListener(
FontLoadedEvent::class,
static function (FontLoadedEvent $event): void {
\error_log("Font loaded: {$event->family} {$event->style}");
},
);
$dispatcher = new EventDispatcher($listeners);

針對長時間執行的 worker(工作行程),請在啟動時建立一次這些註冊表並鎖定,再透過文件工廠注入共用的派發器。

<?php
declare(strict_types=1);
use NextPDF\Contracts\DocumentFactoryInterface;
use NextPDF\Contracts\FontRegistryInterface;
use NextPDF\Event\EventDispatcher;
use NextPDF\Event\ListenerProvider;
use Psr\Log\LoggerInterface;
final class DocumentBootstrap
{
public function __construct(
private readonly FontRegistryInterface $fonts,
private readonly DocumentFactoryInterface $factory,
private readonly LoggerInterface $logger,
) {}
public function warmup(): EventDispatcher
{
$this->fonts->warmup([
'/srv/fonts/Inter-Regular.ttf',
'/srv/fonts/Inter-Bold.ttf',
]);
$this->fonts->lock();
$listeners = new ListenerProvider();
$listeners->addListener(
\NextPDF\Event\Security\SignatureAppliedEvent::class,
fn (object $event): mixed => $this->logger->info('Signature applied'),
);
return new EventDispatcher($listeners);
}
}
  • **註冊表鎖定。**呼叫 FontRegistryInterface::lock() 之後,會變更狀態的方法會擲出 LogicException。請只在暖機完成後才鎖定。
  • **穩定性不一致。**標示為 experimental 的契約,可能在次要版本中變動。在正式環境依賴某個契約之前,請先確認它所宣告的穩定性。
  • **命名空間紀律。**位於 NextPDF\ContractsNextPDF\Event 以外、且沒有 @stability 標籤的型別,都屬於內部。即使它在技術上是 public,這一點依然成立。

未使用 SPI 時不會產生任何開銷。當某個事件類別沒有綁定任何監聽器時,事件派發器會在單次 hasListeners() 檢查後立即返回。註冊表只保存純 PHP 資料,而且支援啟動時暖機,以分攤首次請求的延遲。

簽章契約屬於安全性敏感的介面範圍。HsmSignerInterface 要求私密金鑰絕不離開硬體邊界。你的實作必須遵守這一點。關於第三方簽章後端契約及其威脅模型,請見 KMS 供應者契約一節。

這份總覽頁面不做任何規範性主張。各契約的符合性(PAdES、金鑰管理)請以相關的 SPI 頁面為準。

NextPDF Pro 與 NextPDF Enterprise 為數項簽章與驗證契約提供正式環境等級的實作,包括以金鑰管理系統為後端的簽章。你依賴的是公開契約,實作則由該版本提供,因此你的程式碼能在各版本之間保持可移植。

詞彙表定義了 SPI擴充點穩定性標籤向後相容承諾;各項正式定義請見已發布的詞彙表。