CodeIgniter 4 での本番利用
本番コントローラーは、具体的な NextPDF サービスに依存します。これらのコントローラーは、ドキュメント化された例外階層を明示的に処理し、可観測性シグナルを出力します。時間のかかる PDF 処理は、CodeIgniter 4 Queue を通じてリクエストの外へ移します。
概念の概要
「概念の概要」という見出しのセクションCodeIgniter 4 は、ロケーターを通じてパッケージのサービスを resolve(解決)します。サービスロケーターパターンでは、オブジェクトが自身の依存関係を取得できるよう、コンテナーをオブジェクトに渡します。このパターンは推奨されません(PSR-11 §1.3、modal SHOULD NOT)。このガイダンスに従うには、各 NextPDF サービスをコントローラーの境界で一度だけ解決し、具体的なオブジェクトとして内側に渡します。Services クラス(またはコンテナー)をドメインコードに渡さないでください。
すべての PHP サンプルでは、declare(strict_types=1); を独立した行で宣言します(PSR-12 §x1.x3.p34)。
API サーフェス
「API サーフェス」という見出しのセクション| 本番での関心事 | 検証済みのサーフェス |
|---|---|
| サービスの解決 | Services::pdf(false), Services::pdfDocument(false), Services::documentFactory() |
| レスポンスの構築 | PdfResponse::download() / inline() → DownloadResponse |
| 失敗の捕捉 | NextPDF\Exception\NextPdfException(エコシステムの基底型) |
| 非同期生成 | GeneratePdfJob を登録する Config\Queue::$jobHandlers |
| パス/呼び出し可能オブジェクトのガード | GeneratePdfJob がスローする InvalidArgumentException |
本番コントローラー — エラー処理と可観測性
「本番コントローラー — エラー処理と可観測性」という見出しのセクションコアエンジンがスローする例外は、すべて NextPDF\Exception\NextPdfException を継承しています。この単一の型をキャッチすれば、コアと拡張の両方の失敗をカバーできます。ここでの catch ブロックは、コンテキスト付きでログを記録し、定義済みのエラーレスポンスを返します。空の catch にはしません。
<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\DownloadResponse;use CodeIgniter\HTTP\ResponseInterface;use NextPDF\CodeIgniter\Config\Services;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
final class InvoiceController extends BaseController{ public function download(int $id): DownloadResponse|ResponseInterface { /** @var LoggerInterface $logger */ $logger = \service('logger');
$start = \hrtime(true);
try { $pdf = Services::pdf(false); $pdf->document()->addPage(); $pdf->document()->cell(0, 10, "Invoice #{$id}");
$response = $pdf->download("invoice-{$id}.pdf");
$logger->info('pdf.invoice.generated', [ 'invoice_id' => $id, 'elapsed_ms' => (\hrtime(true) - $start) / 1_000_000, ]);
return $response; } catch (NextPdfException $e) { $logger->error('pdf.invoice.failed', [ 'invoice_id' => $id, 'exception' => $e::class, 'message' => $e->getMessage(), ]);
return $this->response ->setStatusCode(ResponseInterface::HTTP_INTERNAL_SERVER_ERROR) ->setJSON(['error' => 'pdf_generation_failed', 'invoice_id' => $id]); } }}Services::pdf(false) は、呼び出しごとに新しいライブラリと新しい基底ドキュメントを返します。そのため、並行するリクエスト間でドキュメントの状態が共有されることはありません。パッケージの機能テストでこの動作を検証しています。
ワーカーセーフなサービスのライフタイム
「ワーカーセーフなサービスのライフタイム」という見出しのセクションフォントレジストリと画像レジストリは、設計上、プロセスのライフタイム全体で維持されるシングルトンです。フォントレジストリは一度だけウォームアップされ、ロックされます。画像レジストリは、容量制限付きの LRU(最長未使用)キャッシュです。長時間稼働するワーカー(CodeIgniter spark サーバー、RoadRunner 型のランナー、またはキューワーカー)では、これは意図された動作です。コストの高いレジストリは保持され、各ドキュメントは新規に作成されます。リクエストコードやジョブコードで共有ドキュメント(Services::pdfDocument(true))を要求しないでください。これはテストのリセット専用で、リクエスト間でコンテンツを共有してしまいます。
CodeIgniter Queue を使った非同期生成
「CodeIgniter Queue を使った非同期生成」という見出しのセクションGeneratePdfJob は、codeigniter4/queue を通じてリクエストの外で PDF 生成を実行します。キューランタイムでは 2 つの条件が強制されるため、その両方を正しく設定する必要があります。
1. ジョブハンドラーを名前で登録する
「1. ジョブハンドラーを名前で登録する」という見出しのセクションキューは、クラス文字列ではなく 名前キー によってジョブを解決します。キューハンドラーは、プッシュされたジョブ名を Config\Queue::$jobHandlers のキーと照合して検証します。未知の名前は CodeIgniter\Queue\Exceptions\QueueException で拒否されます。ジョブを app/Config/Queue.php に登録します。
<?php
declare(strict_types=1);
namespace Config;
use CodeIgniter\Queue\Config\Queue as BaseQueue;use NextPDF\CodeIgniter\Jobs\GeneratePdfJob;
final class Queue extends BaseQueue{ /** @var array<string, class-string> */ public array $jobHandlers = [ 'generate-pdf' => GeneratePdfJob::class, ];}2. 登録した名前でディスパッチする
「2. 登録した名前でディスパッチする」という見出しのセクション登録した名前を第 2 引数に指定して、ジョブをプッシュします。第 1 引数はキュー名です。第 3 引数はジョブデータの配列です。
<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\ResponseInterface;
final class InvoiceController extends BaseController{ public function queueInvoice(int $id): ResponseInterface { \service('queue')->push('pdf-queue', 'generate-pdf', [ 'builder' => 'App\\PdfBuilders\\InvoiceBuilder::build', 'outputPath' => WRITEPATH . 'pdfs/invoice-' . $id . '.pdf', 'context' => ['invoice_id' => $id], ]);
return $this->response ->setStatusCode(ResponseInterface::HTTP_ACCEPTED) ->setJSON(['status' => 'queued', 'invoice_id' => $id]); }}3. App\PdfBuilders 配下にビルダーを実装する
「3. App\PdfBuilders 配下にビルダーを実装する」という見出しのセクションこのジョブは、ビルダーの呼び出し可能オブジェクトを App\PdfBuilders 名前空間に制限し、出力パスを WRITEPATH/pdfs/ 内に限定します。ビルダーは静的メソッドです。このメソッドは新しい Document とコンテキスト配列を受け取り、ドキュメントを返します。
<?php
declare(strict_types=1);
namespace App\PdfBuilders;
use NextPDF\Core\Document;
final class InvoiceBuilder{ /** @param array<string, mixed> $context */ public static function build(Document $document, array $context): Document { $invoiceId = (int) ($context['invoice_id'] ?? 0);
$document->addPage(); $document->cell(0, 10, "Invoice #{$invoiceId}");
return $document; }}ワーカーを実行する
「ワーカーを実行する」という見出しのセクションphp spark queue:work pdf-queue各ジョブの実行は、Services::pdfDocument() を介して新しいドキュメントから開始されます。ビルダーを適用した後、検証済みのパスに保存します。パッケージのテストでは、連続する 2 回のジョブ実行でドキュメントの状態が共有されないことを検証しています。
エッジケースと注意点
「エッジケースと注意点」という見出しのセクション- キューは、プッシュ時にジョブ名として
GeneratePdfJob::classを拒否します。これは登録済みのキー'generate-pdf'ではないためです。常にjobHandlersのキーをプッシュしてください。 - ビルダー文字列は
App\PdfBuilders\<Class>::<method>と完全に一致する必要があります。関数、別の名前空間、または prefixed/suffixed なペイロードは、コードが実行される前にInvalidArgumentExceptionを発生させます。 - 出力パスは
WRITEPATH/pdfs/内に解決され、.pdfで終わる必要があります(大文字・小文字は区別されません)。トラバーサルパスや兄弟プレフィックスのパスは拒否されます。 codeigniter4/queueは、パッケージの開発専用の依存関係です。ワーカーを実行するアプリケーションでこれを require してください。
パフォーマンス
「パフォーマンス」という見出しのセクションレジストリは、ワーカープロセスごとに一度だけ作成されます。ドキュメントの構築コストは、アダプターではなくコンテンツに比例して増加します。大規模なバッチジョブでは、リクエストワーカーの応答性を保つために、キュー経由の処理を優先してください。測定可能な目標があるレシピには、performance_budget を設定してください。
セキュリティに関する注意
「セキュリティに関する注意」という見出しのセクションキュージョブは、最もリスクの高いサーフェスです。ブローカーに到達できる場合、キューのペイロードは攻撃者の影響を受けます。呼び出し可能オブジェクトの許可リストとパスの限定については、検証済みの拒否ケースとともに /integrations/codeigniter/security-and-operations/ で説明しています。
- コントローラーは、PSR-11 §1.3 のサービスロケーターに関するガイダンスに従い、コンテナーではなく具体的なサービスを受け取ります。
商用に関する補足
「商用に関する補足」という見出しのセクションNextPDF コアは Apache-2.0 です。キュージョブで署名付き出力や PDF/A 出力を行うには、ワーカー環境に NextPDF Pro または Enterprise がインストールされている必要があります。CodeIgniter パッケージは、対応するサービスメソッドを公開します。これらのメソッドは、対応する Premium パッケージがインストールされるまで null を返します。</get-license/?intent=codeigniter-async-signing> を参照してください。
- /integrations/codeigniter/quickstart/ — これらのコントローラーの最小構成版です。
- /integrations/codeigniter/configuration/ — 署名、TSA、およびパスの設定です。
- /integrations/codeigniter/security-and-operations/ — キューの脅威モデルと堅牢化です。
- /integrations/codeigniter/troubleshooting/ — キューとディスカバリーの障害モードです。
- /integrations/codeigniter/integration/ — 配線リファレンスとスモークテストです。