Sử dụng trong môi trường production với CodeIgniter 4
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Trong môi trường production, controller nhận trực tiếp các service NextPDF cụ thể. Controller xử lý rõ ràng cây phân cấp exception đã được tài liệu hóa và phát tín hiệu quan sát. Hãy chuyển các tác vụ Portable Document Format (PDF) chạy lâu ra khỏi luồng request thông qua CodeIgniter 4 Queue.
Tổng quan khái niệm
Phần tiêu đề “Tổng quan khái niệm”CodeIgniter 4 phân giải các service của package thông qua locator của framework. Trong mẫu service locator, một đối tượng nhận một container và dùng container đó để lấy các dependency của chính nó. Hướng dẫn PHP Standard Recommendation (PSR) khuyến cáo không nên dùng mẫu này (PSR-11 §1.3, từ tình thái SHOULD NOT). Để tuân theo hướng dẫn đó, hãy phân giải mỗi service NextPDF một lần tại ranh giới controller, rồi truyền đối tượng cụ thể vào bên trong. Đừng truyền lớp Services hoặc một container vào mã domain của bạn.
Mỗi mẫu PHP đặt declare(strict_types=1); trên dòng riêng của nó (PSR-12 §x1.x3.p34).
Bề mặt API
Phần tiêu đề “Bề mặt API”| Vấn đề trong production | Bề mặt đã kiểm chứng |
|---|---|
| Phân giải service | Services::pdf(false), Services::pdfDocument(false), Services::documentFactory() |
| Tạo response | PdfResponse::download() / inline() → DownloadResponse |
| Bắt lỗi khi thất bại | NextPDF\Exception\NextPdfException (kiểu cơ sở của hệ sinh thái) |
| Tạo tài liệu bất đồng bộ | GeneratePdfJob được đăng ký trong Config\Queue::$jobHandlers |
| Cơ chế bảo vệ đường dẫn / callable | GeneratePdfJob ném ra InvalidArgumentException |
Controller production — xử lý lỗi và khả năng quan sát
Phần tiêu đề “Controller production — xử lý lỗi và khả năng quan sát”Các exception do core engine ném ra đều kế thừa từ NextPDF\Exception\NextPdfException. Hãy bắt đúng kiểu duy nhất này để bao quát lỗi của core và extension. Khối catch này ghi log ngữ cảnh và trả về một error response đã được định nghĩa, tuyệt đối không để catch rỗng.
<?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) trả về một library mới và một tài liệu nền mới cho mỗi lần gọi. Các request đồng thời không bao giờ dùng chung trạng thái tài liệu. Các functional test của package xác nhận hành vi này.
Vòng đời service an toàn cho worker
Phần tiêu đề “Vòng đời service an toàn cho worker”Theo thiết kế, registry phông chữ và hình ảnh là singleton tồn tại trong suốt vòng đời tiến trình. Registry phông chữ được làm nóng và khóa một lần. Registry hình ảnh là một cache least recently used (LRU) có giới hạn. Trong một worker chạy lâu (CodeIgniter spark server, runner kiểu RoadRunner, hoặc một queue worker), đây là chủ ý: các registry tốn kém vẫn được giữ lại, còn mọi tài liệu đều là mới. Đừng yêu cầu một tài liệu dùng chung (Services::pdfDocument(true)) trong mã của request hay job; nó chỉ tồn tại để reset trong test và sẽ dùng chung nội dung giữa các request.
Tạo tài liệu bất đồng bộ với CodeIgniter Queue
Phần tiêu đề “Tạo tài liệu bất đồng bộ với CodeIgniter Queue”GeneratePdfJob đưa việc tạo PDF ra khỏi luồng request thông qua codeigniter4/queue. Runtime của hàng đợi cần hai thiết lập. Hãy cấu hình đúng cả hai.
1. Đăng ký job handler theo tên
Phần tiêu đề “1. Đăng ký job handler theo tên”Hàng đợi phân giải một job theo khóa tên, chứ không theo chuỗi tên lớp. Queue handler đối chiếu tên job được đẩy vào với các khóa trong Config\Queue::$jobHandlers. Nó từ chối tên không xác định bằng CodeIgniter\Queue\Exceptions\QueueException. Hãy đăng ký job trong 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. Điều phối theo tên đã đăng ký
Phần tiêu đề “2. Điều phối theo tên đã đăng ký”Hãy đẩy job với tên đã đăng ký làm đối số thứ hai. Đối số đầu tiên là tên hàng đợi. Đối số thứ ba là mảng dữ liệu cho job.
<?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. Triển khai builder bên trong App\PdfBuilders
Phần tiêu đề “3. Triển khai builder bên trong App\PdfBuilders”Job chỉ cho phép các callable builder trong namespace App\PdfBuilders và giới hạn đường dẫn đầu ra trong WRITEPATH/pdfs/. Hãy triển khai builder dưới dạng một phương thức static. Phương thức này nhận một Document mới cùng mảng context, rồi trả về tài liệu.
<?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; }}Chạy worker
Phần tiêu đề “Chạy worker”php spark queue:work pdf-queueMỗi lần chạy job bắt đầu với một tài liệu mới từ Services::pdfDocument(). Job áp dụng builder, rồi lưu vào đường dẫn đã được xác thực. Các test của package xác minh rằng hai lần chạy job liên tiếp không dùng chung trạng thái tài liệu.
Trường hợp biên & điểm cần lưu ý
Phần tiêu đề “Trường hợp biên & điểm cần lưu ý”- Hàng đợi từ chối
GeneratePdfJob::classkhi dùng làm tên job lúc đẩy vào, vì đó không phải là khóa đã đăng ký'generate-pdf'. Hãy luôn đẩy khóajobHandlers. - Chuỗi builder phải khớp chính xác với
App\PdfBuilders\<Class>::<method>. Các hàm, namespace khác, hoặc payload có thêm tiền tố hay hậu tố sẽ làm phát sinhInvalidArgumentExceptiontrước khi bất kỳ mã nào được chạy. - Đường dẫn đầu ra phải phân giải vào bên trong
WRITEPATH/pdfs/và kết thúc bằng.pdf(không phân biệt chữ hoa chữ thường). Các đường dẫn dạng traversal và sibling-prefix đều bị từ chối. codeigniter4/queuelà dependency chỉ dành cho phát triển của package. Hãy require dependency này trong ứng dụng chạy các worker.
Hiệu năng
Phần tiêu đề “Hiệu năng”Các registry được tạo một lần cho mỗi tiến trình worker. Chi phí dựng tài liệu tỷ lệ theo nội dung, chứ không theo adapter. Với các batch job lớn, hãy dùng đường đi qua hàng đợi để những worker xử lý request vẫn phản hồi tốt. Hãy đặt một performance_budget trong bất kỳ recipe nào có mục tiêu đo lường được.
Lưu ý bảo mật
Phần tiêu đề “Lưu ý bảo mật”Queue job là bề mặt có rủi ro cao nhất. Khi broker có thể truy cập được, payload của hàng đợi có thể chịu ảnh hưởng từ kẻ tấn công. Danh sách cho phép callable và việc giới hạn đường dẫn được trình bày trong /integrations/codeigniter/security-and-operations/, cùng các trường hợp từ chối đã được kiểm chứng.
Sự tuân thủ
Phần tiêu đề “Sự tuân thủ”- Controller nhận các service cụ thể, chứ không phải một container, nhất quán với hướng dẫn về service locator của PSR-11 §1.3.
Bối cảnh thương mại
Phần tiêu đề “Bối cảnh thương mại”NextPDF core dùng giấy phép Apache-2.0. Để tạo đầu ra đã ký và PDF/A trong các queue job, hãy cài đặt NextPDF Pro hoặc Enterprise trong môi trường worker. Package CodeIgniter cung cấp các phương thức service tương ứng. Các phương thức này trả về null cho đến khi package Premium tương ứng được cài đặt. Xem </get-license/?intent=codeigniter-async-signing>.
Xem thêm
Phần tiêu đề “Xem thêm”- /integrations/codeigniter/quickstart/ — phiên bản tối giản của các controller này.
- /integrations/codeigniter/configuration/ — cấu hình ký, Time Stamping Authority (TSA) và đường dẫn.
- /integrations/codeigniter/security-and-operations/ — mô hình mối đe dọa của hàng đợi và cách tăng cường bảo mật.
- /integrations/codeigniter/troubleshooting/ — các chế độ lỗi của hàng đợi và discovery.
- /integrations/codeigniter/integration/ — tài liệu tham khảo về wiring và smoke test.