Symfony 開発者ガイド
Symfony パッケージはサービスファーストです。PdfFactory をインジェクトし、ドキュメントごとに create() を呼び出し、非同期生成には Messenger ビルダーを使用します。呼び出しのたびに新しいドキュメントが返されるため、ファクトリーはコンテナサービスとして扱えます。
コントローラー、サービス、Messenger ハンドラー、またはバンドルレベルの拡張ポイントを nextpdf/symfony を軸に設計するときは、このガイドを参照してください。
アーキテクチャの境界
「アーキテクチャの境界」という見出しのセクション| レイヤー | 所有者 | 責務 | ここに置かないもの |
|---|---|---|---|
| コントローラー | アプリケーション | リクエスト認可、入力収集、PdfResponse の返却。 | ユースケース間で共有される PDF レイアウト。 |
| アプリケーションサービス | アプリケーション | ドメインデータの読み込みとビルダー選択。 | Symfony コンテナコンパイラーのロジック。 |
| ビルダーサービス | アプリケーション | 同期またはキュー実行でドキュメントを構築するための PdfBuilderInterface 実装。 | リクエストオブジェクト、エンティティマネージャー、またはシリアライズできないコンテキスト。 |
| Symfony バンドル | nextpdf/symfony | サービス、設定ツリー、オプションの拡張パス、レスポンスヘルパー、Messenger DTO の登録。 | テナント固有のストレージポリシー。 |
| コアエンジン | nextpdf/nextpdf | ドキュメントの作成とシリアライズ。 | Symfony のレスポンスまたは Messenger の動作。 |
ランタイムのライフサイクル
「ランタイムのライフサイクル」という見出しのセクション| ステージ | 動作 | 開発者のアクション |
|---|---|---|
| バンドルのブート | NextPdfBundle::build() によるオプション拡張機能検出の登録。 | Symfony によるバンドル検出、または bundles.php への登録。 |
| 設定の読み込み | NextPdfExtension::load() による nextpdf: 設定の処理とサービス定義の読み込み。 | 明示的で環境を考慮した設定。 |
| ファクトリーの使用 | PdfFactory::create() による設定済みの新規ドキュメントの返却。 | ドキュメントをサービスに保存しないこと。 |
| コントローラーの出力 | PdfResponse による完成済みドキュメントのレスポンス変換。 | ヘッダーを手動で組み立てず、ヘルパーを使用すること。 |
| Messenger のディスパッチ | GeneratePdfMessage によるビルダークラス、出力パス、シリアライズ可能なコンテキストの伝達。 | 最小限でスカラー値中心のコンテキスト。 |
| メッセージの処理 | GeneratePdfHandler によるサービスロケーターからのビルダーの解決とドキュメント保存。 | 決定論的かつ冪等なビルダー。 |
推奨されるアプリケーション構成
「推奨されるアプリケーション構成」という見出しのセクション| パス | 目的 |
|---|---|
src/Pdf/Builder/* | PdfBuilderInterface を実装するサービス。 |
src/Pdf/Data/* | ビルダーコンテキスト用の小さな DTO または配列。 |
src/Pdf/Storage/* | ストレージルートの選択と出力ファイル名のポリシー。 |
src/Controller/* | 同期レスポンスのエントリーポイント。 |
tests/Pdf/* | ビルダー、レスポンス、Messenger、設定のテスト。 |
静的ヘルパー関数よりもビルダーサービスを優先してください。ビルダーサービスは、タグ付け、デコレーション、テスト、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'); }}コントローラーのコンテキストは小さく保ってください。ビルダーが多数のドメインオブジェクトを必要とする場合は、オーケストレーションをアプリケーションサービスへ移し、DTO または正規化済みの配列をビルダーに渡してください。
Messenger のパターン
「Messenger のパターン」という見出しのセクションGeneratePdfMessage はディスパッチ前にビルダークラスと出力パスを検証します。ハンドラーは実行時にもパスを再検証します。
<?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 エンティティ、オープンストリーム、クロージャ、リクエストオブジェクト、サービスオブジェクトを builderContext に含めないでください。
拡張ポイント
「拡張ポイント」という見出しのセクション| 拡張ポイント | 用途 | 制約 |
|---|---|---|
PdfFactory サービスのデコレーション | ドキュメントがコントローラーに到達する前のアプリケーションデフォルトの適用。 | 新しいドキュメントのセマンティクス維持。 |
PdfBuilderInterface | キュー実行または再利用可能なドキュメントビルダーの定義。 | Document の返却。 |
OptionalExtensionPass | コンパイル時のオプション Artisan または Premium 機能の有効化。 | 利用可否はリクエスト状態ではなく、コンテナのコンパイル状態に基づくこと。 |
| Symfony 設定ツリー | デフォルト、PDF/A、レンダラー設定、署名、TSA、Messenger。 | 無効な設定によるコンテナビルド時の失敗。 |
GeneratePdfHandler サービスの配線 | キューされたメッセージから到達可能なビルダーの制限。 | 承認済みビルダーサービスのみを公開するサービスロケーター。 |
開発ワークフロー
「開発ワークフロー」という見出しのセクション- 決定論的な入力を受け取るビルダーサービスを追加します。
- コントローラーまたはサービスで
PdfFactory::create()を使用します。 - ファイル名、コンテンツタイプ、ヘッダーに関するレスポンステストを追加します。
- 同じドキュメントを非同期で生成する必要がある場合は、ビルダーを Messenger 用に登録します。
- クラス名、出力パス、コンテキストの形状について、無効なメッセージのテストを追加します。
- 最小構成と本番構成でのコンテナコンパイルテストを追加します。
- 本番環境と同じ PHP 設定で、レンダリング時間とメモリを測定します。
| 障害 | 処理すべき場所 | 推奨される対応 |
|---|---|---|
| 無効な設定 | コンテナコンパイル。 | トラフィックがアプリに到達する前にデプロイを失敗させること。 |
| ビルダーサービスの欠落 | Messenger ハンドラーのテストとサービスタグ。 | メッセージの失敗化と担当チームへの通知。 |
| 安全でない出力パス | メッセージコンストラクターとストレージポリシー。 | ディスパッチ前の拒否と、多層防御としてのハンドラー検証の維持。 |
| オプション拡張機能の利用不可 | コンパイラーパスとファクトリーの動作。 | オプション機能の無効化、またはインストールの明示化。 |
| サービスの変換またはレンダリングの失敗 | ビルダーの境界。 | ユースケースに文書化されたフォールバックがない限り、フェイルクローズすること。 |
安全なデフォルト
「安全なデフォルト」という見出しのセクション| 関心事 | デフォルト | オーバーライドする時期 |
|---|---|---|
| ファクトリーのライフタイム | コンテナサービス。 | 維持すること。ファクトリーはドキュメントを作成するだけなので安全です。 |
| ドキュメントのライフタイム | 1 つの作業単位。 | リクエストやメッセージをまたいで共有しないこと。 |
| 出力パスの検証 | メッセージコンストラクターとハンドラー。 | アプリケーションコードでのテナントまたはストレージルート制約の追加。 |
| レスポンスのファイル名 | document.pdf。 | サニタイズ済みビジネス識別子によるオーバーライド。 |
| Messenger のトランスポート | async。 | PDF 処理が重い場合の専用トランスポートの使用。 |
テストチェックリスト
「テストチェックリスト」という見出しのセクション- コンテナテストは最小構成と本番構成でバンドルをコンパイルします。
- レスポンステストはセキュリティヘッダーとファイル名の取り扱いを検証します。
- Messenger テストは無効なパスと無効なビルダークラス名がディスパッチ前に失敗することを検証します。
- ハンドラーテストは実際のビルダーサービスと一時的な出力ディレクトリを使用します。
- ビルダーテストは代表的なドキュメントをレンダリングし、本番に近いファイルシステム権限で保存します。
- オプション拡張機能のテストは、Artisan が利用できない場合、Premium が利用できない場合、設定された PDF/A プロファイルの動作を網羅します。