Przejdź do głównej zawartości

NextPDF — przegląd integracji z Laravelem

Pakiet nextpdf/laravel łączy silnik PDF NextPDF z aplikacją Laravel 12 i sam rejestruje powiązania kontenera. Udostępnia fasadę Pdf, pomocnik HTTP PdfResponse oraz kolejkowane zadanie GeneratePdfJob. Laravel wykrywa pakiet automatycznie, więc nie trzeba rejestrować go ręcznie.

Okno terminala
composer require nextpdf/laravel

Ograniczenie wersji w Composerze to nextpdf/core: ^3.0 || ^5.2. Pakiet wymaga również laravel/framework: ^12.0 oraz php: >=8.4 <9.0. Pełną procedurę, w tym publikowanie konfiguracji i opcjonalne rozszerzenia, opisano w /integrations/laravel/install/.

Pakiet działa między kontenerem usług Laravela a niezależnym od frameworka rdzeniem NextPDF. Nie implementuje ponownie generowania PDF. Zamiast tego dostosowuje rdzeniowy model NextPDF\Core\Document do cyklu życia Laravela, konfiguracji, kolejek i warstwy HTTP.

Poniższy diagram pokazuje drogę żądania od kodu aplikacji, przez pakiet, aż do współdzielonych rejestrów rdzenia.

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

Mapa autoloadingu zawiera jeden wpis PSR-4. PSR-4 to standard PHP (PHP Standard Recommendation) dotyczący autoloadingu, a jego prefiks NextPDF\Laravel\ jest mapowany na src/Laravel/. Zgodnie z PSR-4 prefiks przestrzeni nazw odpowiada katalogowi bazowemu, a pozostała część nazwy klasy jest odwzorowywana na ścieżkę pliku w tym katalogu (PSR-4 §3). Pod tym prefiksem znajdują się cztery klasy produkcyjne:

  • NextPDF\Laravel\NextPdfServiceProvider — rejestruje powiązania i publikuje konfigurację.
  • NextPDF\Laravel\Facades\Pdf — statyczny pośrednik, który rozwiązuje z kontenera nowy dokument.
  • NextPDF\Laravel\Http\PdfResponse — tworzy odpowiedzi PDF typu inline, odpowiedzi do pobrania oraz odpowiedzi strumieniowane ze stałym zestawem nagłówków bezpieczeństwa.
  • NextPDF\Laravel\Jobs\GeneratePdfJob — kolejkowalne zadanie, które buduje i zapisuje PDF w procesie roboczym.

Dostawca usług implementuje DeferrableProvider, więc rejestruje swoje powiązania dopiero po rozwiązaniu jednego z ogłoszonych wpisów. Dzięki temu ścieżka startowa frameworka pozostaje lekka. Metoda provides() dostawcy zawiera wpisy odroczone, a kontener odczytuje tę listę, aby zmapować każdy klucz z powrotem na dostawcę.

Mechanizm rozwiązywania działa zgodnie z kontraktem kontenera: gdy istnieje powiązanie, rozwiązanie identyfikatora zwraca zarejestrowany wpis. PSR-11 to standard PHP (PHP Standard Recommendation) dotyczący interoperacyjności kontenerów i określa, że dwa kolejne wywołania get() z tym samym identyfikatorem mogą zwrócić różne wartości, zależnie od strategii powiązania (PSR-11 §1.1.2). NextPDF celowo polega na tym zachowaniu. Rejestry są singletonami, więc każde rozwiązanie zwraca tę samą instancję. Dokumenty używają powiązania factory, więc każde rozwiązanie zwraca nową instancję. Pełną tabelę cykli życia powiązań zawiera /integrations/laravel/boot-and-discovery/.

Architektura jest zaprojektowana dla długo działających procesów roboczych, takich jak Octane, RoadRunner i Swoole. Rejestr czcionek jest singletonem o cyklu życia procesu: pakiet rozgrzewa go raz, a następnie blokuje, więc żadne żądanie nie może zmienić współdzielonego stanu czcionek. Rejestr obrazów jest singletonem o cyklu życia procesu z ograniczoną pamięcią podręczną typu least-recently-used (LRU). Ponieważ pakiet zawsze tworzy każdy dokument przez DocumentFactory, zmienny stan z poziomu żądania nigdy nie wycieka między żądaniami.

KlasaPubliczny punkt wejściaZwracaCel
NextPdfServiceProviderregister(), boot(), provides()void / arrayPowiązania kontenera, publikacja konfiguracji, lista wpisów odroczonych
Facades\Pdfstatyczny pośrednik (addPage(), cell(), save(), …)static / mixedRozwiązuje PdfDocumentInterface przy każdym wywołaniu
Http\PdfResponseinline(), download(), streamInline(), streamDownload()Response / StreamedResponseOdpowiedzi HTTP z nagłówkami Open Worldwide Application Security Project (OWASP)
Jobs\GeneratePdfJobdispatch(), handle(), then(), catch(), failed()PendingDispatch / void / selfKolejkowane generowanie PDF

Klucze kontenera powiązane przez dostawcę:

KluczCykl życiaRozwiązuje się do
NextPDF\Contracts\FontRegistryInterface (alias FontRegistry)singleton, zablokowanyNextPDF\Typography\FontRegistry
NextPDF\Graphics\ImageRegistrysingleton, ograniczony przez LRUImageRegistry
NextPDF\Contracts\DocumentFactoryInterface (alias DocumentFactory)singletonNextPDF\Core\DocumentFactory
Psr\Http\Client\ClientInterfacesingletonSecurityAwareHttpClient, który opakowuje CurlHttpClient
NextPDF\Security\Timestamp\TsaClientscopedTsaClient lub null, gdy brak adresu URL urzędu znacznika czasu (TSA)
NextPDF\Contracts\SignerInterfacefactoryDigitalSigner lub null, gdy podpisywanie jest wyłączone
NextPDF\Contracts\PdfDocumentInterface (alias nextpdf)factoryNextPDF\Core\Document
NextPDF\Contracts\EInvoice\{Embedder,Validator,Profile,SchematronRunner}Interfacefactoryrozwiązuje się tylko wtedy, gdy zainstalowany jest 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'));

Gotowy do uruchomienia przykład kontrolera znajduje się w /integrations/laravel/quickstart/.

W użyciu produkcyjnym kontrakt dokumentu rozwiązuje się z kontenera, a nie przez fasadę; dzięki temu miejsce wywołania pozostaje jawne i testowalne. Pełny kontroler, w tym wstrzykiwanie zależności (dependency injection, DI) i obsługę błędów, opisano w /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');
  • Dostawca jest odroczony, więc rozwiązanie niepowiązanego klucza kontenera nie uruchamia NextPDF. Powiązania pojawiają się dopiero po zażądaniu jednego z wpisów provides().
  • SignerInterface i TsaClient z założenia rozwiązują się do null, gdy nie skonfigurowano podpisywania ani urzędu znacznika czasu. Kod musi sprawdzać wynik pod kątem wartości null; nie zakładaj, że instancja istnieje.
  • Powiązania kontraktów e-faktury są zawsze rejestrowane, ale rozwiązują się do konkretnych implementacji Premium, które istnieją tylko wtedy, gdy zainstalowany jest nextpdf/premium. Próba rozwiązania ich bez Premium kończy się błędem nieznalezienia klasy; błąd pojawia się przy pierwszym rozwiązaniu, nie podczas startu.
  • Fasada zwraca nowy dokument przy każdym rozwiązaniu. Weź pod uwagę dwa statyczne wywołania Pdf:: w tym samym żądaniu, rozdzielone przez Pdf::clearResolvedInstances(): wywołania operują na różnych dokumentach.

Rejestracja dostawcy działa w czasie O(1). Dostawca rejestruje domknięcia i nie konstruuje ciężkich obiektów, więc koszt konstrukcji jest odroczony do pierwszego rozwiązania. Rozgrzewanie rejestru czcionek działa w czasie O(f), gdzie f to liczba wstępnie wczytanych plików czcionek, i wykonuje się raz w każdym procesie roboczym. Dzięki temu opóźnienie pierwszego żądania amortyzuje się w długo działających procesach roboczych. Budżet pamięci na stronę dla tego przeglądu jest zapisany w polu front-matter performance_budget.

PdfResponse stosuje stały zestaw nagłówków Open Worldwide Application Security Project (OWASP). Zestaw obejmuje X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Content-Security-Policy: default-src 'none', X-Robots-Tag oraz Referrer-Policy: no-referrer. GeneratePdfJob weryfikuje swoją ścieżkę wyjściową po stronie procesu roboczego, co łagodzi ryzyko spreparowanych zserializowanych ładunków. Pełny model zagrożeń i konfigurację wdrożenia opisano w /integrations/laravel/security-and-operations/.

TwierdzenieŹródłoKlauzulareference_id
Semantyka rozwiązywania / cyklu życia konteneraPSR-11 Container§1.1.2
Mapowanie prefiksu autoloadingu PSR-4PSR-4 Autoloader§3

Gdy zainstalowany jest nextpdf/premium, ten sam dostawca udostępnia więcej możliwości: podpis cyfrowy (PAdES B-B), archiwizację PDF/A oraz powiązania kontraktów e-faktury. Udostępnia je przez te same klucze kontenera, więc opisany tutaj pakiet Core może je przyjąć bez zmiany kodu. Szczegóły znajdują się pod adresem https://nextpdf.dev/get-license/?intent=laravel-signing.

  • /integrations/laravel/install/ — procedura instalacji i opcjonalne rozszerzenia
  • /integrations/laravel/quickstart/ — gotowy do uruchomienia przykład kontrolera
  • /integrations/laravel/configuration/ — każdy klucz konfiguracji, zweryfikowany względem config/nextpdf.php
  • /integrations/laravel/production-usage/ — kontroler z wstrzykiwaniem zależności (DI), obsługa błędów, kolejkowanie
  • /integrations/laravel/boot-and-discovery/ — automatyczne wykrywanie i cykle życia powiązań
  • /integrations/laravel/security-and-operations/ — model zagrożeń i konfiguracja wdrożenia