Przejdź do głównej zawartości
getnextpdf.com

Jeden silnik, każdy framework

Spec: PSR-11 Container, §1.1.2Spec: PSR-4 Autoloader, §3

Większość rosnących środowisk PHP kończy z więcej niż jednym frameworkiem. NextPDF to jeden silnik PDF, który spotyka się z każdym z nich na jego własnych warunkach: idiomatyczne mostki dla Laravela, Symfony i CodeIgnitera oraz ścieżka samodzielna dla kodu, który nie działa w żadnym z nich. Model dokumentu jest współdzielony. Zmienia się tylko sposób, w jaki go wywołujesz.

Inna biblioteka PDF dla każdego stosu to cichy podatek. Każda ma swoje osobliwości, swoją obsługę czcionek, swoje wyobrażenie o tym, co znaczy prawidłowy. Faktura, która renderuje się poprawnie z usługi Laravela, może renderować się subtelnie inaczej z procesu roboczego Symfony, bo narysowała ją inna biblioteka. Teraz twój cel archiwalny, rozmieszczenie podpisu i znaczniki dostępności zależą od tego, który zespół wysłał dokument. Zgłoszenie błędu mówi „PDF jest zły”, a odpowiedź zależy od tego, który z trzech silników go wytworzył.

Standaryzacja na jednym silniku zwija tę powierzchnię. Istnieje jedno miejsce, w którym ustala się profil PDF/A, jeden potok czcionek do certyfikacji, jeden walidator, któremu się ufa. Framework, w którym akurat jesteś, przestaje być zmienną w tym, czy dokument jest poprawny.

  • Silnik rdzeniowy jest niezależny od frameworka. nextpdf/core nie wie nic o HTTP, routingu ani podłączaniu kontenera. To silnik PDF 2.0 i nic więcej.
  • Każdy mostek adaptuje, nie reimplementuje. Pakiety Laravela, Symfony i CodeIgnitera dają ci fasadę lub fabrykę, pomocnika odpowiedzi HTTP oraz ścieżkę generowania w kolejce lub asynchronicznego — nad tym samym silnikiem.
  • Mostek podąża za twoim frameworkiem, nie za twoim dokumentem. Zmienia sposób, w jaki wywołujesz silnik, nigdy zaś to, co silnik potrafi wytworzyć.
  • Tryb samodzielny jest zawsze dostępny. Narzędzie CLI, demon lub biblioteka nie ma frameworka, z którego można by mostkować; konstruuje dokument bezpośrednio.
  • Jeden model dokumentu przemieszcza się po wszystkich czterech. Te same obiekty wartości, typy wyliczeniowe i kontrakt wyjścia pojawiają się wszędzie, więc dokument przenosi się między miejscami wywołania bez zmian.

Architektura to celowy podział. Silnik to zasób; mostek to cienki adapter, który mówi idiomami jednego frameworka. Mostek rejestruje małą przestrzeń nazw nad współdzielonym rdzeniem poprzez standardowy autoloading (Spec: PSR-4 Autoloader, §3) i zwraca dokument poprzez kontrakt kontenera (Spec: PSR-11 Container, §1.1.2). Ten kontrakt jest tutaj cichym bohaterem: pozwala dwóm rozwiązaniom tego samego identyfikatora zwrócić różne instancje, i właśnie tak mostek daje ci świeży, jednorazowy dokument na żądanie, jednocześnie utrzymując sparsowany rejestr czcionek oraz pamięć podręczną obrazów jako singletony obejmujące cały proces. Długo żyjące procesy robocze — Octane, RoadRunner, Swoole, Messenger — otrzymują zamortyzowane parsowanie czcionek bez wycieku stanu między żądaniami, z samej konstrukcji.

Te cztery idiomy różnią się tylko na powierzchni:

  1. Core enginenextpdf/core — the framework-agnostic PDF 2.0 engine; the single shared document model, value objects, and output contract.
  2. Laravel bridgenextpdf/laravel — auto-discovered provider, a Pdf facade, a PdfResponse helper, and a queued GeneratePdfJob.
  3. Symfony bridgenextpdf/symfony — an auto-registered bundle, an injectable PdfFactory, a PdfResponse, and an optional Messenger handler.
  4. CodeIgniter bridgenextpdf/codeigniter — a service and pdf() helper, a Pdf library over a disposable Document, and a PdfResponse.
  5. StandaloneNo framework to bridge from — construct a Document directly in a CLI tool, daemon, or library.
One framework-agnostic core engine reached through four idiomatic surfaces: a Laravel facade, an injected Symfony factory, a CodeIgniter service, or a directly constructed standalone document — each handing back the same disposable Document model.

Przeczytaj diagram od lewej do prawej, a lekcją jest symetria. Każda powierzchnia rozwiązuje się do tego samego Document. Fasada Laravela, fabryka Symfony, usługa CodeIgnitera oraz samodzielny konstruktor to czworo drzwi do jednego pokoju.

Te same trzy wiersze intencji, wyrażone w każdym idiomie. Ciało, które buduje dokument — strony, czcionki, komórki, podpisywanie, zgodność — jest identyczne we wszystkich czterech, bo to ten sam silnik.

<?php
declare(strict_types=1);
// Laravel — resolve a fresh document from the container.
use NextPDF\Contracts\PdfDocumentInterface;
$document = app(PdfDocumentInterface::class);
// Symfony — inject the factory, then ask it for a document.
use NextPDF\Symfony\Service\PdfFactory;
$document = $factory->create(); // PdfFactory injected into your service
// CodeIgniter — pull it from the Services layer.
use NextPDF\CodeIgniter\Config\Services;
$document = Services::pdfDocument();
// Standalone — no framework; construct it directly.
use NextPDF\Core\Document;
$document = Document::createStandalone();
// From here, the code is identical regardless of how $document arrived.
$document->addPage();
$document->cell(0, 10, 'One engine, every framework', newLine: true);
$bytes = $document->getPdfData();

Pierwsze wiersze to jedyna różnica. Wszystko po nich jest przenośne: przenieś usługę budującą dokument z Symfony do samodzielnego procesu roboczego, a kod renderujący się nie zmieni, bo kontrakt, od którego zależy, się nie zmienił.

Częste założenie jest takie, że mostek frameworka odblokowuje możliwości — że walidacja długoterminowa podpisu lub ustrukturyzowane e-fakturowanie pojawia się, bo zainstalowałeś nextpdf/laravel, zamiast wywoływać silnik bezpośrednio. Tak nie jest. Mostek zmienia miejsce wywołania, nigdy zasięg silnika. Możliwości rdzeniowe, takie jak wyjście PDF/A oraz podpisywanie bazowe PAdES, są otwartoźródłowe i sięgają każdej powierzchni; zaawansowane możliwości są odblokowywane przez edycję i wówczas są dostępne poprzez dowolny mostek lub ścieżkę samodzielną na równi. Wybór integracji frameworka to nie wybór zestawu funkcji.

Lustrzanym nieporozumieniem jest to, że „jeden silnik” musi oznaczać jedną ścieżkę renderowania dla każdego dokumentu. Nie musi. Silnik wewnątrzprocesowy renderuje PDF bezpośrednio; gdy dokument naprawdę potrzebuje silnika układu klasy przeglądarkowej, obsługuje to pakiet renderera. Renderowanie i wywoływanie to osobne osie — przewodnik decyzji o integracji jest miejscem, które je mapuje.

Mostek nie rozszerza tego, co silnik potrafi wyrenderować. To uczciwe ograniczenie i o to chodzi: możliwość żyje w rdzeniu i warstwie, a nie w adapterze, przez który do niej sięgasz.

Framework bridges over one engine — edition availability
EditionAvailability
Core

Every bridge (Laravel, Symfony, CodeIgniter) and the standalone path are Apache-2.0 and work against Core. They adapt or expose the engine; they do not gate features and do not change what it can produce.

Pro

Advanced capabilities such as long-term signature validation (PAdES B-LT and B-LTA) are unlocked by an edition, then reached identically through any bridge or standalone — never by switching framework. PDF/A archival output and PAdES baseline signing (B-B and B-T) are already in Core, available the same way through every surface.

Enterprise

Structured e-invoicing (EN 16931) and deeper compliance tooling are edition capabilities too, likewise the same whichever surface calls the engine, while conformance validation itself ships in Core.

Dwie kolejne granice warto wyłożyć wprost. Po pierwsze, każdy mostek śledzi bieżącą wersję główną swojego frameworka — Laravel, Symfony i CodeIgniter każdy przypina wspierany zakres, więc „każdy framework” oznacza wspieraną wersję każdego z nich, a nie każde historyczne wydanie; traktuj dokumentację każdego pakietu jako miarodajną dla jego API. Po drugie, mostki to adaptery frameworków, a nie zaplecza renderujące. Jeśli dokument potrzebuje pełnego silnika układu przeglądarkowego, to jest to wybór renderera niezależny od tego, który framework wywołał silnik.

  • Przewodnik decyzji o integracji — mapa przypadek-użycia-do-pakietu, w tym renderery oraz powierzchnia usługi Connect, gdy musisz zdecydować, zamiast standaryzować.
  • Otwarty rdzeń, brak uzależnienia od dostawcy — dlaczego silnik to zasób, a mostki są cienkie, więc standaryzacja cię nie uwięzi.
  • Potok HTML — co obejmuje silnik wewnątrzprocesowy, byś wiedział, kiedy renderer przeglądarkowy jest osobnym pytaniem.
  • Fundamenty PHP 8.4 — minimalny próg środowiska uruchomieniowego, który dzieli każdy mostek i ścieżka samodzielna.
  • Silnik rdzeniowynextpdf/core, niezależny od frameworka silnik PDF 2.0, na którym budują każdy mostek i ścieżka samodzielna.
  • Mostek frameworka — pakiet integracyjny (Laravel, Symfony, CodeIgniter), który adaptuje silnik do idiomów frameworka — fasada, fabryka, odpowiedź, zadanie w kolejce — bez zmiany jego możliwości.
  • Ścieżka samodzielna — używanie silnika rdzeniowego bezpośrednio, bez frameworka, przez samodzielne skonstruowanie Document; trasa dla narzędzi CLI, demonów i bibliotek.
  • Dokument jednorazowy — kontrakt Document do jednorazowego użycia: zbuduj, wyemituj, odrzuć. Każde rozwiązanie kontenera zwraca świeży, więc żaden stan nie wycieka między żądaniami w długo żyjącym procesie roboczym.
  • PAdES — PDF Advanced Electronic Signatures, rodzina profili ETSI do podpisywania PDF. Podpisywanie bazowe (B-B i B-T) jest w Core; walidacja długoterminowa (B-LT i B-LTA) to możliwość zaawansowanej edycji. Do każdego sięga się przez dowolną powierzchnię, co dokładnie omawiają strony o podpisywaniu.