コンテンツにスキップ

コントラクト:41 個の公開インターフェイス(SPI)

NextPDF\Contracts は公開サービスプロバイダーインターフェイス(SPI)です。src/Contracts/ 配下の 41 個のインターフェイスと列挙型で構成され、いずれも明示的な @stability タグと後方互換性の保証を備えています。拡張パッケージ、フレームワークブリッジ、Pro エディションおよび Enterprise エディションは、具象クラスではなく、これらの型を対象にプログラミングします。

Terminal window
composer require nextpdf/core:^3

エンジンは 2 つの側面を分離しています。src/Core/src/Html/src/Writer/ 配下の具象クラスには互換性の保証がありません。これらはマイナーバージョン間で自由に変更されます。Contracts 名前空間はその逆です。ここは厳選された型の集合であり、各型が宣言する安定性ティアに従ってシグネチャが凍結されています。エンジン外部のものはすべて、この名前空間に依存し、それより深い部分には依存しません。これには Laravel、Symfony、CodeIgniter の各ブリッジ、compat-tcpdf シム、NextPDF Server、Pro エディションおよび Enterprise エディションが含まれます。

各コントラクトは、その PHPDoc で 4 つのティアのいずれか 1 つを宣言します。stable コントラクトは、マイナーリリースまたはパッチリリースでの破壊的変更を一切許容しません。新しいメソッドは、デフォルト実装を伴う場合にのみ追加されます。experimental コントラクトは、非推奨通知を伴ってマイナーリリースで変更される場合があります。deprecated コントラクトは、置き換え先を明示します。StreamingWriterInterfaceCursorInterface のように、コントラクトだけが存在するものも少数あります。これらの型は公開され凍結されていますが、本番向けの実装はまだ提供されていません。

正式なティアの一覧は docs/extension-points.json です(マニフェストバージョン 3.0.0、ContractsEvent にまたがる 67 個の公開ポイントを含みます)。機械的に検証できるテスト tests/Unit/Contracts/StabilityContractTest.php が、そのマニフェストを読み取ります。このテストは、次の 5 つの条件でビルドを失敗させます。1 つ目は、一覧に記載された型が存在しない場合です。2 つ目は、リフレクションで得られた種別がマニフェストと食い違う場合です。3 つ目は、@stability PHPDoc タグがマニフェストから乖離している場合です。4 つ目は、src/Contracts/ 配下のコントラクトがマニフェストに存在しない場合です。5 つ目は、@internal 型がそこに混入している場合です。コントラクトの公開面は、検知されないまま乖離することはありません。

コントラクトは 9 つのドメインに分類され、それぞれに専用ページがあります。ドキュメント構築、署名、バーコードエンコード、タイポグラフィ、セキュリティポリシー、抽出、可観測性、ストリーミングです。この分割は、インテグレーターがエンジンを導入する流れを反映しています。PDF を生成するには、ドキュメントコントラクトに依存します。署名を追加するには、署名コントラクトに依存します。信頼できない HTML を制約するには、セキュリティポリシーコントラクトに依存します。

オプション実装の resolve(解決)は、エンジン全体で 1 つのパターンに従います。Core は class_exists() で具象クラスの存在を確認し、それをコントラクトにキャストします。LtvManagerInterfacePdfAManagerInterface は、この方法で Pro 実装を解決します。したがって Core は Apache-2.0 のまま保たれ、商用コードへのハードな依存を持ちません。

コントラクト種別安定性導入バージョンドメイン
PdfDocumentInterfaceinterfacestable1.0.0document
DocumentFactoryInterfaceinterfacestable1.7.0document
ResettableServiceinterfacestable1.7.0document
OutputDestinationenumstable1.0.0document
Orientationenumstable1.0.0document
Alignmentenumstable1.0.0document
SignerInterfaceinterfacestable1.0.0signing
HsmSignerInterfaceinterfacestable1.0.0signing
DeferredSignerInterfaceinterfaceexperimental3.0.0signing
TimestampProviderInterfaceinterfaceexperimental3.0.0signing
LtvManagerInterfaceinterfacestable1.10.0signing
CryptoPolicyInterfaceinterfacestable1.9.0signing
Barcode1DEncoderInterfaceinterfacestable1.0.0barcode
Barcode2DEncoderInterfaceinterfacestable1.0.0barcode
BarcodeEncoderInterfaceinterfacestable3.0.0barcode
Gs1DataParserInterfaceinterfacestable1.0.0barcode
FontRegistryInterfaceinterfacestable1.7.0typography
TextPreprocessorInterfaceinterfacestable1.9.0typography
HtmlSecurityPolicyInterfaceinterfacestable3.1.0security-policy
ExternalResourcePolicyInterfaceinterfacestable4.0.0security-policy
InspectorInterfaceinterfaceexperimental2.2.0extraction
EmbeddingServiceInterfaceinterfaceexperimental2.1.0extraction
VectorIndexInterfaceinterfaceexperimental2.1.0extraction
JobNotificationInterfaceinterfaceexperimental2.2.0observability
SpectrumInterfaceinterfaceexperimental2.1.0observability
StreamingWriterInterfaceinterfaceexperimental3.1.0streaming
CursorInterfaceinterfaceexperimental3.1.0streaming

この表は主要なコントラクトを示しています。残りの型 — 値オブジェクト DTO(TextSegmentTextPreprocessResult)、EInvoice サブ名前空間、振る舞いを表す列挙型(DegradationPolicyUnderlineStyle)、インポートコントラクト(ImportedFormObjectInterfaceEmbeddedPdfObjectInterfaceChromeRenderResultInterface) — は、関連項目 配下のドメインページで説明しています。機械可読な完全一覧は docs/extension-points.json で、.ai/contracts-map.md にミラーリングされています。

examples/01-hello-world.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Hello World');
$doc->addPage();
$doc->setFont('helvetica', '', 24);
$doc->cell(0, 15, 'Hello, NextPDF!', newLine: true);
$doc->save(__DIR__ . '/output/01-hello-world.pdf');

Document::createStandalone() は、具象の Document を返します。この DocumentPdfDocumentInterface を満たします。エンジン内部を差し替え可能な状態に保つため、独自サービスではインターフェイスを型ヒントに指定してください。

examples/14-worker-factory.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Core\PdfFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
// Created once at process boot in a RoadRunner/Swoole/Octane worker.
$fontRegistry = new FontRegistry();
$imageRegistry = new ImageRegistry(maxCacheBytes: 50 * 1024 * 1024);
$documentFactory = new DocumentFactory($fontRegistry, $imageRegistry);
$factory = PdfFactory::new()
->withCompress(true)
->withDocumentFactory($documentFactory);
for ($request = 1; $request <= 3; $request++) {
$doc = $factory->create();
$doc->setTitle("Worker Request #{$request}");
$doc->addPage();
$doc->setFont('helvetica', 'B', 16);
$doc->cell(0, 12, "Worker Request #{$request}", newLine: true);
$doc->save(__DIR__ . "/output/14-worker-request-{$request}.pdf");
}

DocumentFactoryDocumentFactoryInterface を実装します。これはプロセスのライフタイムにわたる FontRegistryInterfaceImageRegistryInterface のシングルトンを保持し、使い捨ての各 Document に注入します。そのため、ワーカーは数千件のリクエストを処理する間、各フォントを 1 回だけ解析します。

  • コントラクトのみの型はコンパイルできますが、ランタイム上の実体はありません。まだどのクラスも実装していないため、newStreamingWriterInterfaceCursorInterface に対して呼び出しても成功しません。これらは前方宣言された API として扱ってください。
  • この @stability PHPDoc タグは、単一の型に関する信頼できる情報源です。docs/extension-points.json は、集合に関する信頼できる情報源です。両者が食い違うと StabilityContractTest が失敗します。どちらか一方を編集して食い違いを隠さないでください。
  • experimental は実際には不安定であるという意味ではなく、互換性の保証がより弱いという意味です。コントラクトに固定する前に、各コントラクトの bc_promise フィールドを .ai/contracts-map.md でお読みください。
  • ある @internal クラスは、たとえ他のパッケージが技術的に参照できたとしても、決してコントラクトではありません。安定性テストは、マニフェストに現れるあらゆる @internal 型を拒否します。
  • ある stable インターフェイスへのメソッド追加は、そのメソッドがデフォルト実装を伴って提供されない限り、実装者にとって破壊的変更です。エンジンは、既存のインターフェイスを拡張するのではなく、新しいインターフェイスを通じて機能を追加します。

この Contracts に対してプログラミングしても、測定可能なランタイムコストは加わりません。インターフェイスの型ヒントは、呼び出しごとではなくリンク時に解決されます。このページのワーカー例の performance_budget は、3 つのドキュメント全体で実時間 1500 ms、ピーク 64 MB です。最初のリクエストでのフォント解析が、その予算の大半を占めます。以降のリクエストはレジストリキャッシュを再利用し、コントラクトに起因する処理は 1 桁ミリ秒まで低下します。コストモデルはコントラクトのディスパッチごとに O(1) です。実際の処理は具象実装の中にあり、各ドメインページで説明しています。

SPI はセキュリティ境界でもあります。HtmlSecurityPolicyInterfaceExternalResourcePolicyInterface は、信頼できない HTML がレンダラーに到達する前に、その挙動を制約するデフォルト拒否のコントラクトです。CryptoPolicyInterface は、署名と暗号化に対するアルゴリズムと鍵強度の選択を制御します。これらはコントラクトであるため、インテグレーターはエンジンをフォークすることなく、より厳格なポリシーを提供できます。セキュリティに関わるポリシーは、stable ティアに固定してください。experimental のポリシーコントラクトは、マイナーリリース間で形が変わる場合があります。署名およびセキュリティポリシーの各ドメインページに、完全な脅威モデルと規範的参照が記載されています。

この概要は直接的な規範的主張を行いません。各ドメインページが独自の citations ブロックをレンダリングします。署名コントラクトは、ISO 32000-2 §12.8(電子署名)および ETSI EN 319 142(PAdES ベースライン)に対応付けられます。PDF/A マネージャーは ISO 19005-4 に対応付けられます。節レベルの適合性表については、署名、セキュリティポリシー、抽出の各ページを参照してください。

Pro エディションと Enterprise エディションは、いくつかのコアコントラクトの背後にある本番コードを実装しています。LtvManagerInterface(長期検証)、PdfAManagerInterface(PDF/A の強制)、ハードウェアセキュリティモジュール(HSM)と遅延署名者、バーコードエンコーダー、そして埋め込みおよびベクトルインデックスのコントラクトです。Core はインターフェイスを公開して凍結し、Premium パッケージが実装を提供します。これにより、オープンソースエンジンは Apache-2.0 のまま保たれ、同時に商用デプロイには API を変更せずにそのまま導入できるアップグレードを提供します。