CodeIgniter 4 正式環境使用
快速總覽
標題為「快速總覽」的區段正式環境中的控制器會依賴具體的 NextPDF 服務。這些控制器會明確處理已記載的例外階層,並發出可觀測性訊號。耗時的 PDF 工作會透過 CodeIgniter 4 Queue 移出請求流程之外執行。
概念總覽
標題為「概念總覽」的區段CodeIgniter 4 會透過自身的定位器(locator)來 resolve(解析)此套件的服務。服務定位器(service locator)模式會把容器(container)交給某個物件,讓該物件自行取出所需的依賴。此模式並不建議使用(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) 每次呼叫都會回傳全新的函式庫與全新的底層文件。因此,並行請求之間絕不會共用文件狀態。此套件的功能測試會驗證這項行為。
worker 安全的服務生命週期
標題為「worker 安全的服務生命週期」的區段字型與影像登錄表(registry)的設計,就是行程生命週期內的單例(singleton)。字型登錄表只會預熱並鎖定一次。影像登錄表是一個有界的最近最少使用(LRU)快取。在長駐的 worker(CodeIgniter spark 伺服器、RoadRunner 風格的執行器,或佇列 worker)中,這正是預期行為:昂貴的登錄表會持續保留,而每份文件都是全新的。請勿在請求或工作程式碼中索取共用文件(Services::pdfDocument(true));它只供測試重設使用,否則會在多個請求之間共用內容。
以 CodeIgniter Queue 進行非同步產生
標題為「以 CodeIgniter Queue 進行非同步產生」的區段GeneratePdfJob 會透過 codeigniter4/queue 把 PDF 產生工作移出請求流程之外執行。佇列執行期會強制執行兩項事實,而這兩項你都必須正確設定。
1. 以名稱註冊工作處理器
標題為「1. 以名稱註冊工作處理器」的區段佇列會以**名稱鍵(name key)**解析工作,而不是以類別字串解析。佇列處理器會比對推入的工作名稱與 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. 以註冊的名稱派送」的區段請以註冊的名稱作為第二個引數推入工作。第一個引數是佇列名稱。第三個引數是工作資料陣列。
<?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 底下實作建構器」的區段此工作會把建構器(builder)可呼叫項限制在 App\PdfBuilders 命名空間(namespace),並把輸出路徑限定在 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; }}執行 worker
標題為「執行 worker」的區段php spark queue:work pdf-queue每次工作執行都會透過 Services::pdfDocument() 從全新文件開始。它會套用建構器,再儲存到已驗證的路徑。此套件的測試會驗證連續兩次工作執行不會共用文件狀態。
邊界情況與陷阱
標題為「邊界情況與陷阱」的區段- 佇列在推入時會拒絕以
GeneratePdfJob::class作為工作名稱,因為它不是已註冊的鍵'generate-pdf'。請務必推入jobHandlers的鍵。 - 建構器字串必須完全符合
App\PdfBuilders\<Class>::<method>。函式、其他命名空間,或帶有 prefixed/suffixed 的酬載,都會在任何程式碼執行之前引發InvalidArgumentException。 - 輸出路徑必須解析到
WRITEPATH/pdfs/內部,並以.pdf結尾(不分大小寫)。路徑穿越與同層前綴的路徑都會被拒絕。 codeigniter4/queue是此套件僅供開發使用的依賴。請在實際執行 worker 的應用程式中安裝它。
登錄表在每個 worker 行程中只會建立一次。文件建構成本會隨內容而變,與轉接器(adapter)無關。對大型批次工作,請優先採用佇列路徑,讓請求 worker 保持回應能力。在任何有可量測目標的 recipe(範例)中,都請設定 performance_budget。
安全注意事項
標題為「安全注意事項」的區段佇列工作是風險最高的介面。當 broker(訊息中介者)可被觸及時,佇列酬載可能受到攻擊者影響。其可呼叫項允許清單與路徑限定,連同已驗證的拒絕案例,記載於 /integrations/codeigniter/security-and-operations/ 一節。
符合性
標題為「符合性」的區段- 控制器收到的是具體服務,而非容器;這與 PSR-11 §1.3 的服務定位器指引一致。
商業情境
標題為「商業情境」的區段NextPDF 核心採用 Apache-2.0 授權。在佇列工作中產生簽章與 PDF/A 輸出,需要在 worker 環境安裝 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/ —— 接線參考與煙霧測試。