跳转到内容

NextPDF Laravel 集成概览

nextpdf/laravel 包将 NextPDF PDF 引擎接入 Laravel 12 应用,并为你注册容器绑定。它提供一个 Pdf facade、一个 PdfResponse HTTP 辅助类,以及一个可排入队列的 GeneratePdfJob。Laravel 会自动发现该包,因此你无需手动注册。

Terminal window
composer require nextpdf/laravel

Composer 版本约束为 nextpdf/core: ^3.0 || ^5.2。此包还需要 laravel/framework: ^12.0php: >=8.4 <9.0。完整步骤,包括配置发布与可选扩展,请参见 /integrations/laravel/install/.

此包位于 Laravel 服务容器与框架无关的 NextPDF core 之间,承担一层很薄的适配职责。它不会重新实现 PDF 生成功能,而是将 core 的 NextPDF\Core\Document 模型适配到 Laravel 的生命周期、配置、队列与 HTTP 层。

下图展示了一个请求如何从你的应用代码出发,经由此包,最终进入共享的 core 注册表。

NextPDF Laravel request and render flowA request resolves a fresh document from the container, which the package adapts onto the shared font and image registries before HTTP or queue output.

Your Laravel app

Pdf facade

Laravel service container

NextPdfServiceProvider (deferred)

DocumentFactory (singleton)

Document (fresh per resolve)

FontRegistry (singleton, locked)

ImageRegistry (singleton, LRU)

PdfResponse (HTTP)

GeneratePdfJob (queue worker)

NextPDF Laravel request and render flow

自动加载映射只包含一条 PSR-4 条目。PSR-4 是 PHP 自动加载的标准建议,其中前缀 NextPDF\Laravel\ 映射到 src/Laravel/。在 PSR-4 中,命名空间前缀对应一个基准目录,剩余类名再映射到该目录下的文件路径(PSR-4 §3)。此前缀下有四个正式提供的类:

  • NextPDF\Laravel\NextPdfServiceProvider — 注册绑定并发布配置。
  • NextPDF\Laravel\Facades\Pdf — 一个静态 proxy(代理),会从容器 resolve(解析)出一个全新的 document。
  • NextPDF\Laravel\Http\PdfResponse — 一个工厂,用于生成 inline、下载与流式 PDF 响应,并附带一组固定的安全标头。
  • NextPDF\Laravel\Jobs\GeneratePdfJob — 一个可排入队列的 job,会在 worker 上创建并存储 PDF。

此服务提供者实现了 DeferrableProvider,因此只有当你解析其中一个已声明的条目时,它才会注册绑定。这种延迟机制让框架启动路径保持轻量。该提供者的 provides() 方法列出延迟加载的条目,容器会读取这份清单,并将每个键映射回该提供者。

解析遵循容器契约:只要绑定存在,解析该标识符就会返回已注册的条目。PSR-11 是 PHP 容器互操作性的标准建议,它指出,对同一个标识符连续调用两次 get(),可能会因绑定策略不同而返回不同的值(PSR-11 §1.1.2)。NextPDF 有意依赖这项行为。注册表是单例,因此每次解析都返回同一个实例;document 则采用工厂绑定,因此每次解析都返回一个全新的实例。完整的绑定生命周期表,请参见 /integrations/laravel/boot-and-discovery/.

此架构面向长生命周期 worker,例如 Octane、RoadRunner 与 Swoole。font registry 是进程生命周期内的单例:包只会预热一次并将其锁定,因此任何请求都无法修改共享的字体状态。image registry 也是进程生命周期内的单例,配有一个有界的最近最少使用(LRU)缓存。由于包始终通过 DocumentFactory 全新创建 document,因此每个请求的可变状态绝不会泄漏到其他请求。

公开入口点返回用途
NextPdfServiceProviderregister()boot()provides()void / array容器绑定、配置发布、延迟条目清单
Facades\Pdf静态 proxy(addPage()cell()save() 等)static / mixed每次调用都会解析出一个 PdfDocumentInterface 实例
Http\PdfResponseinline()download()streamInline()streamDownload()Response / StreamedResponse带有 OWASP 标头的 HTTP 响应
Jobs\GeneratePdfJobdispatch()handle()then()catch()failed()PendingDispatch / void / self排入队列的 PDF 生成

提供者绑定的容器键如下:

生命周期解析为
NextPDF\Contracts\FontRegistryInterface(别名 FontRegistry单例,已锁定NextPDF\Typography\FontRegistry
NextPDF\Graphics\ImageRegistry单例,有界 LRUImageRegistry
NextPDF\Contracts\DocumentFactoryInterface(别名 DocumentFactory单例NextPDF\Core\DocumentFactory
Psr\Http\Client\ClientInterface单例SecurityAwareHttpClient,包裹 CurlHttpClient
NextPDF\Security\Timestamp\TsaClient作用域TsaClient,或在未配置 TSA URL 时为 null(即没有 TSA 客户端)
NextPDF\Contracts\SignerInterface工厂DigitalSigner,或在停用签署时为 null(即未启用签署)
NextPDF\Contracts\PdfDocumentInterface(别名 nextpdf工厂NextPDF\Core\Document
NextPDF\Contracts\EInvoice\{Embedder,Validator,Profile,SchematronRunner}Interface工厂仅在安装了 nextpdf/premium 时才会解析
resource: README.md Quick Start (verified against src/Laravel/Facades/Pdf.php)
<?php
declare(strict_types=1);
use NextPDF\Laravel\Facades\Pdf;
Pdf::addPage();
Pdf::cell(0, 10, 'Hello from Laravel', newLine: true);
Pdf::save(storage_path('app/hello.pdf'));

以 controller 为上下文、可直接运行的示例,请参见 /integrations/laravel/quickstart/.

生产环境的写法是从容器解析 document 契约,而非通过 facade;这样调用点更明确,也更易于测试。完整的 controller 示例(包含依赖注入(DI)与错误处理)请参见 /integrations/laravel/production-usage/.

resource: src/Laravel/Http/PdfResponse.php (download factory)
<?php
declare(strict_types=1);
use NextPDF\Contracts\PdfDocumentInterface;
use NextPDF\Laravel\Http\PdfResponse;
$document = app(PdfDocumentInterface::class);
$document->addPage();
$document->cell(0, 10, 'Invoice', newLine: true);
return PdfResponse::download($document, 'invoice.pdf');
  • 此提供者采用延迟加载,因此解析一个不相关的容器键并不会启动 NextPDF。只有当你请求其中一个 provides() 条目时,这些绑定才会出现。
  • SignerInterfaceTsaClient 在你尚未配置签署或时间戳机构时,按设计会解析为 null。你的代码必须对结果进行 null 检查,不要假设实例一定存在。
  • e-invoice 契约绑定一律会注册,但它们只会解析到 Premium 的具体实现,而这些实现只有在安装了 nextpdf/premium 时才存在。在没有 Premium 的情况下解析它们会引发 class-not-found 错误,且错误出现在首次解析时,而非启动时。
  • 此 facade 每次解析都会返回一个全新的 document。假设同一个请求中有两次 Pdf:: 静态调用,并且两次调用之间执行了 Pdf::clearResolvedInstances():这两次调用会操作不同的 document。

提供者注册以 O(1) 时间完成。此提供者只绑定闭包,不构造重量级对象,因此构造成本会延迟到首次解析时才发生。font registry 预热以 O(f) 时间完成,其中 f 是预加载的字体文件数量,并且每个 worker 进程只执行一次。这样的时机安排能在长生命周期 worker 中摊销首次请求延迟。本概览的单页内存预算记录在 front-matter 字段 performance_budget 中。

PdfResponse 会应用一组来自开放全球应用安全项目(OWASP)的固定安全标头。这些标头包括 X-Content-Type-Options: nosniffX-Frame-Options: DENYContent-Security-Policy: default-src 'none'X-Robots-Tag,以及 Referrer-Policy: no-referrerGeneratePdfJob 会在 worker 端验证输出路径,这项检查可缓解序列化负载被篡改的风险。完整的威胁模型与部署配置,请参见 /integrations/laravel/security-and-operations/.

主张来源条款参考 ID
容器解析/生命周期语义PSR-11 容器§1.1.2
PSR-4 自动加载前缀映射PSR-4 自动加载器§3

安装 nextpdf/premium 后,同一个提供者会公开更多功能:数字签名(PAdES B-B)、PDF/A 归档,以及 e-invoice 契约绑定。此提供者通过完全相同的容器键公开这些功能,因此本页说明的 Core 包无需任何代码变更即可使用这些功能。详情请参见 https://nextpdf.dev/get-license/?intent=laravel-signing

  • /integrations/laravel/install/ — 安装步骤与可选扩展
  • /integrations/laravel/quickstart/ — 可直接运行的 controller 示例
  • /integrations/laravel/configuration/ — 每个 config 键均对照验证 config/nextpdf.php
  • /integrations/laravel/production-usage/ — 以 DI 组装的 controller、错误处理、队列
  • /integrations/laravel/boot-and-discovery/ — 自动发现与绑定生命周期
  • /integrations/laravel/security-and-operations/ — 威胁模型与部署配置