Bỏ qua để đến nội dung

NextPDF cho CodeIgniter 4

nextpdf/codeigniter kết nối engine Portable Document Format (PDF) của NextPDF với ứng dụng CodeIgniter 4 thông qua lớp Services của framework. Bạn dựng tài liệu PDF trong controller, job hoặc command, rồi trả chúng về dưới dạng phản hồi Hypertext Transfer Protocol (HTTP) gốc của CodeIgniter.

Terminal window
composer require nextpdf/codeigniter

Tệp composer.json của gói yêu cầu php >=8.4 <9.0, nextpdf/core ^3.0 || ^5.2codeigniter4/framework ^4.6. Nó cũng gợi ý nextpdf/artisan, nextpdf/premiumcodeigniter4/queue. Để xem đầy đủ yêu cầu, các gói tùy chọn và các bước xác minh, hãy xem /integrations/codeigniter/install/.

NextPDF là một engine PDF 2.0 viết bằng PHP 8.4. Engine lõi (nextpdf/core) không phụ thuộc vào framework nào. Nó không biết gì về HTTP, định tuyến hay việc nối kết phụ thuộc. nextpdf/codeigniter là adapter kết nối engine với ứng dụng CodeIgniter 4. Khi đã có adapter, bạn không phải tự nối các registry, factory hay phần xử lý phản hồi.

Gói này thêm bốn thứ vào một ứng dụng CodeIgniter 4:

  • Một lớp Services (NextPDF\CodeIgniter\Config\Services) mà CodeIgniter tự động phát hiện. Nó cung cấp các service có tên: fontRegistry, imageRegistry, documentFactory, pdfDocument, pdf, tsaClientpdfSigner.
  • Một thư viện Pdf (NextPDF\CodeIgniter\Libraries\Pdf) — một application programming interface (API) cấp cao cho controller. Nó bọc một tài liệu dùng một lần và biến tài liệu đó thành phản hồi chỉ trong một lệnh gọi.
  • Một helper PdfResponse (NextPDF\CodeIgniter\Http\PdfResponse) tạo một DownloadResponse của CodeIgniter để xem trực tiếp hoặc tải xuống. Nó đính kèm một bộ header cố định để tăng cường bảo mật cho phản hồi.
  • Hai hàm helper toàn cục, pdf()pdf_document(). Chúng được đăng ký thông qua mục autoload files của Composer và Registrar của gói.

Gói này cũng phát hiện các phần mở rộng NextPDF tùy chọn khi dựng tài liệu. Khi nextpdf/artisan được cài đặt và một binary Chrome đã được cấu hình, tài liệu sẽ dùng bộ kết xuất Chrome. Khi NextPDF Pro được cài đặt, đầu ra PDF/A và ký số sẽ khả dụng qua cùng bề mặt Services đó. Việc phát hiện diễn ra có điều kiện và âm thầm. Gói này không bao giờ yêu cầu một phần mở rộng không tồn tại.

Vì sao là một lớp Services chứ không phải một liên kết container

Phần tiêu đề “Vì sao là một lớp Services chứ không phải một liên kết container”

CodeIgniter 4 không đi kèm container tiêm phụ thuộc PSR-11. Thay vào đó, nó dùng Services locator. Services locator là một lớp được framework phát hiện, có các phương thức factory tĩnh. Mỗi phương thức trả về một instance dùng chung hoặc một instance mới. PSR-11 không khuyến khích mẫu service-locator — truyền container vào một đối tượng để đối tượng tự lấy các phụ thuộc của nó — trong PSR-11 §1.3 với động từ tình thái SHOULD NOT. Gói này tuân theo quy ước locator của CodeIgniter. Nó cũng giữ bề mặt locator tối giản và rõ ràng: mỗi service là một phương thức factory có tên với một tham số bool $getShared, và bên gọi nhận về các đối tượng cụ thể thay vì một handle container.

Thiết kế này giữ cho bản tích hợp CodeIgniter nhất quán với các bản tích hợp Laravel và Symfony. Mỗi bản tích hợp cung cấp cùng các service luận lý đó theo cách diễn đạt riêng của framework tương ứng.

Điểm vàoLoạiTrả vềVòng đời
Services::fontRegistry()serviceFontRegistryInterfacedùng chung (làm nóng trước, rồi khóa lại)
Services::imageRegistry()serviceImageRegistrydùng chung (bộ nhớ đệm least recently used (LRU) có giới hạn)
Services::documentFactory()serviceDocumentFactoryInterfacedùng chung (không lưu trạng thái)
Services::pdfDocument(false)serviceNextPDF\Core\Documentmới mỗi lần gọi
Services::pdf(false)serviceNextPDF\CodeIgniter\Libraries\Pdfmới mỗi lần gọi
Services::tsaClient()service?TsaClientdùng chung; null khi không có URL timestamp authority (TSA)
Services::pdfSigner(false)service?SignerInterfacemới; null khi việc ký bị tắt
pdf()helperPdfmới mỗi lần gọi
pdf_document()helperDocumentmới mỗi lần gọi
PdfResponse::inline() / download()tĩnhDownloadResponsemỗi lần gọi
GeneratePdfJobqueue jobmột cái cho mỗi lần dispatch

Một controller có thể trả về PDF chỉ trong ba dòng. Services::pdf() trả về một thư viện Pdf mới, bọc một tài liệu mới. Sau đó, download() tạo một DownloadResponse của CodeIgniter.

<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\DownloadResponse;
use NextPDF\CodeIgniter\Config\Services;
final class InvoiceController extends BaseController
{
public function download(int $id): DownloadResponse
{
$pdf = Services::pdf();
$pdf->document()->addPage();
$pdf->document()->cell(0, 10, "Invoice #{$id}");
return $pdf->download("invoice-{$id}.pdf");
}
}

Hướng dẫn từng bước có thể chạy đầy đủ nằm ở /integrations/codeigniter/quickstart/. Hướng dẫn này bao quát định tuyến, xem trực tiếp và các biến thể helper pdf()pdf_document().

Trong môi trường production, hãy yêu cầu một instance không dùng chung bằng Services::pdf(false). Hãy bắt một exception cơ sở duy nhất, NextPDF\Exception\NextPdfException; mọi lỗi của lõi và phần mở rộng đều kế thừa từ exception này. Hãy ghi log lỗi kèm ngữ cảnh thay vì bỏ qua lỗi.

try {
$pdf = Services::pdf(false);
$pdf->document()->addPage();
$pdf->document()->cell(0, 10, "Invoice #{$id}");
return $pdf->download("invoice-{$id}.pdf");
} 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]);
}

Controller production hoàn chỉnh nằm ở /integrations/codeigniter/production-usage/. Tài liệu này bổ sung phép đo thời gian để quan sát, vòng đời an toàn cho worker và cách tạo bất đồng bộ.

Trường hợp ngoại lệ và điểm cần lưu ý

Phần tiêu đề “Trường hợp ngoại lệ và điểm cần lưu ý”
  • Các registry phông chữ và hình ảnh là singleton tồn tại suốt vòng đời của tiến trình. Một tài liệu không bao giờ được dùng chung. pdfDocumentpdf trả về một instance mới ở mỗi lần gọi, nên một yêu cầu không thể rò rỉ nội dung sang yêu cầu khác. Services::pdf(false)pdf() đều trả về một thư viện mới, bọc một tài liệu mới.
  • Gói này yêu cầu các phần mở rộng PHP mbstringzlib. Registry phông chữ kiểm tra chúng một lần cho mỗi tiến trình. Nếu thiếu một trong hai phần mở rộng, registry phông chữ sẽ phát sinh một lỗi runtime nêu rõ phần mở rộng còn thiếu.
  • Hành vi của phần mở rộng tùy chọn phụ thuộc vào những gì được cài đặt trong cùng ứng dụng. Khi chỉ có nextpdf/core, các đường dẫn ký và PDF/A trả về null hoặc bị bỏ qua. Chúng không bao giờ báo lỗi gây nhiễu.

Bản tích hợp không thêm chi phí nào đo lường được ngoài bản thân engine. Registry phông chữ được phân tích một lần rồi khóa lại. Registry hình ảnh là bộ nhớ đệm LRU được giới hạn bởi thiết lập imageCacheMb (mặc định là 50 MB). Engine lõi và nội dung tài liệu quyết định chi phí dựng PDF, không phải adapter. Ngân sách mỗi trang cho bộ tài liệu này là 1500 ms thời gian thực / 128 MB đỉnh. Các recipe thực tế tự đặt ngân sách riêng trong front-matter.

PdfResponse đính kèm một bộ header phản hồi cố định vào mọi PDF mà nó phát ra: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Content-Security-Policy: default-src 'none', X-Robots-Tag: noindex, nofollowReferrer-Policy: no-referrer. Tên tệp được làm sạch, và các tên không phải ASCII được phát ra kèm một tham số mở rộng Request for Comments (RFC) 5987. Queue job giới hạn các builder callable trong namespace App\PdfBuilders và giới hạn đường dẫn đầu ra trong WRITEPATH/pdfs/. Xem /integrations/codeigniter/security-and-operations/ để biết mô hình mối đe dọa đầy đủ.

  • Việc phát hiện module dựa vào cơ chế autoload PSR-4 của Composer. Một tiền tố namespace ánh xạ tới một thư mục cơ sở, còn tên lớp đầy đủ ánh xạ tới một đường dẫn tệp (PSR-4 §x1.x3).
  • Thiết kế Services tuân theo hướng dẫn về locator được bàn đến trong PSR-11 §1.3.

Lõi NextPDF dùng giấy phép Apache-2.0. Chữ ký số, lưu trữ PDF/A và nhúng hóa đơn điện tử Factur-X do NextPDF Pro và NextPDF Enterprise cung cấp. Gói CodeIgniter cung cấp các phương thức service tương ứng. Các phương thức đó trả về null cho đến khi gói Premium tương ứng được cài đặt trong cùng ứng dụng.

  • /integrations/codeigniter/install/ — cài đặt và xác minh gói.
  • /integrations/codeigniter/quickstart/ — PDF đầu tiên trong một controller.
  • /integrations/codeigniter/configuration/ — mọi khóa cấu hình.
  • /integrations/codeigniter/boot-and-discovery/ — cách CodeIgniter tìm ra lớp Services.
  • /integrations/codeigniter/integration/ — tài liệu tham chiếu về kết nối và smoke test.