Przejdź do głównej zawartości

Kontrakty / Document

Domena dokumentu obejmuje kontrakty używane do budowania danych wyjściowych w formacie Portable Document Format (PDF): PdfDocumentInterface dla treści, DocumentFactoryInterface dla bezpiecznego tworzenia w środowisku workerów, kontrakty rejestrów czcionek i obrazów oraz trzy wyliczenia dotyczące dostarczania i układu. Wszystkie mają status stable od wersji 1.0.0 lub 1.7.0.

Okno terminala
composer require nextpdf/core:^3

PdfDocumentInterface to główna powierzchnia API. Definiuje zarządzanie stronami, wybór czcionek, układ tekstu w komórkach jedno- i wielowierszowych, renderowanie Hypertext Markup Language (HTML), osadzanie obrazów oraz końcowe dane wyjściowe. Każda metoda zwraca static, co pozwala łączyć wywołania w łańcuch. Document::createStandalone() zwraca konkretną instancję, która spełnia ten interfejs. W usługach deklaruj ten interfejs jako typ, aby wnętrze silnika pozostało wymienne.

Dokument można tworzyć dwiema ścieżkami. W klasycznym żądaniu PHP FastCGI Process Manager (PHP-FPM) metoda createStandalone() buduje samodzielny dokument z prywatnymi rejestrami. Długo działające workery, w tym RoadRunner, Swoole i Laravel Octane, korzystają z drugiej ścieżki. W tym modelu DocumentFactoryInterface::create() zwraca świeży, jednorazowy obiekt Document. Dokument odczytuje dane z rejestrów o cyklu życia procesu, ale nigdy ich nie modyfikuje. Fabryka przechowuje singletony FontRegistryInterface i ImageRegistryInterface. Każdy dokument otrzymuje własny kontekst renderowania oraz własny writer. Dzięki temu awarie pozostają izolowane: jeden dokument nie może uszkodzić współdzielonego stanu, na którym polega inny dokument.

Kontrakty rejestrów zapewniają wydajność workerów. FontRegistryInterface analizuje plik czcionki tylko raz i buforuje przetworzone metadane na czas życia procesu. Po rozgrzaniu możesz go zablokować, aby żądania produkcyjne nie mogły go modyfikować. ImageRegistryInterface buforuje zdekodowane dane binarne obrazu zgodnie z ograniczoną strategią LRU. Metadane obrazu pozostają w pamięci nawet po usunięciu danych binarnych. Oba rejestry udostępniają metodę memoryUsage() na potrzeby planowania pojemności. ImageRegistryInterface rozszerza ResettableService, który usuwa buforowane dane bez niszczenia metadanych strukturalnych. Worker może usuwać bufory obrazów pod presją pamięci i nadal obsługiwać żądania.

Trzy wyliczenia dopełniają tę domenę. OutputDestination wybiera wyświetlanie w treści, wymuszone pobieranie, zapis do systemu plików lub zwrócenie surowego ciągu znaków. Orientation wybiera orientację pionową albo poziomą. Alignment wybiera wyrównanie tekstu do lewej, do środka, do prawej albo justowanie. Każde wyliczenie używa starszego kodu TCPDF jako wartości wyliczenia, dzięki czemu most compat-tcpdf mapuje je bezbłędnie. Gwarancja zgodności wstecznej dla tych wyliczeń jest addytywna. Żaden przypadek nie jest usuwany. Nowe przypadki mogą pojawić się w wydaniu pomniejszym.

TypRodzajKluczowe składoweStabilnośćOd wersji
PdfDocumentInterfaceinterfejsaddPage(), setMargins(), setFont(), cell(), multiCell(), writeHtml(), image(), output(), save()stable1.0.0
DocumentFactoryInterfaceinterfejscreate(?Config): Documentstable1.7.0
ResettableServiceinterfejsreset(): voidstable1.7.0
FontRegistryInterfaceinterfejsregister(), get(), warmup(), lock(), isLocked(), registerFromBinary(), memoryUsage()stable1.7.0
ImageRegistryInterfaceinterfejsload(), loadFromString(), getMetadata(), memoryUsage() (rozszerza ResettableService)stable2.0.0
OutputDestinationenum (string)Inline, Download, File, Stringstable1.0.0
Orientationenum (string)Portrait, Landscapestable1.0.0
Alignmentenum (string)Left, Center, Right, Justifystable1.0.0

Strona poświęcona typografii w pełni dokumentuje FontRegistryInterface i ImageRegistryInterface. Ta strona omawia ich rolę w cyklu życia tworzenia dokumentu.

examples/01-hello-world.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Hello World');
$doc->addPage();
$doc->setFont('helvetica', '', 24);
$doc->cell(0, 15, 'Hello, NextPDF!', newLine: true);
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'This is a minimal PDF generated with NextPDF.', newLine: true);
$doc->save(__DIR__ . '/output/01-hello-world.pdf');
examples/02-pdf-factory.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\PdfFactory;
use NextPDF\ValueObjects\{Margin, PageSize};
$factory = PdfFactory::new()
->withPageSize(PageSize::A4())
->withMargins(new Margin(15.0, 15.0, 15.0, 15.0))
->withCompress(true)
->withLang('en');
// The same configured factory creates independent documents.
$doc = $factory->create();
$doc->setTitle('PdfFactory Example');
$doc->setAuthor('NextPDF');
$doc->addPage();
$doc->setFont('helvetica', '', 16);
$doc->cell(0, 12, 'Created via PdfFactory', newLine: true);
$doc2 = $factory->create();
$doc2->addPage();
$doc2->setFont('helvetica', '', 12);
$doc2->cell(0, 10, 'Second document from the same factory.');
$doc->save(__DIR__ . '/output/02-pdf-factory.pdf');

PdfFactory to niemutowalny builder. Każde wywołanie with*() zwraca nową instancję. Wewnętrznie komponuje DocumentFactoryInterface, więc model rejestrów workerów opisany w przeglądzie obowiązuje bez dodatkowej konfiguracji.

  • createStandalone() buduje prywatne rejestry. W pętli workera oznacza to ponowną analizę każdej czcionki przy każdym żądaniu. Zamiast tego użyj DocumentFactoryInterface ze współdzielonymi rejestrami.
  • Obiekt Document jest z założenia jednorazowy. Ponowne użycie tej samej instancji dla wielu logicznych dokumentów powoduje wyciek stanu. Wywołuj create() dla każdego dokumentu i pozwól, by zwolnił go mechanizm odzyskiwania pamięci.
  • FontRegistryInterface::lock() sprawia, że register(), addFontDirectory() i warmup() zgłaszają LogicException. Blokuj po rozgrzaniu rejestru, nigdy podczas obsługi żądania.
  • OutputDestination::File zapisuje do systemu plików serwera i zwraca surowe bajty. save() przyjmuje jawną ścieżkę pliku. Nie mieszaj tych dwóch ścieżek dla tego samego dokumentu.
  • cell() przyjmuje bool|string dla argumentu obramowania w celu zachowania zgodności z TCPDF. Pusty ciąg znaków nie jest tym samym co false. Przekaż wartość o typie, który rzeczywiście masz na myśli.

Rejestry czcionek i obrazów sprawiają, że domena dokumentu jest ograniczana przede wszystkim przez pamięć, a nie przez pracę wykonywaną przy każdym żądaniu. Największy koszt przypada na analizę czcionek przy pierwszym żądaniu. performance_budget wynosi 1500 ms czasu zegarowego i 64 MB szczytowego zużycia pamięci dla trzech dokumentów w przykładzie z workerem. Niemal cały budżet pochłania pierwsza analiza czcionki. Po rozgrzaniu koszt przypadający na kontrakt dokumentu ma złożoność O(1): wyszukanie w rejestrze i alokacja kontekstu. memoryUsage() wywołane na dowolnym rejestrze zwraca MemoryReport na potrzeby bieżącego planowania pojemności. ResettableService::reset() ogranicza szczytowe zużycie pamięci przy trwałym obciążeniu.

Kontrakty dokumentu nie eksponują żadnej powierzchni kryptograficznej, ale wiążą się z nimi dwa ryzyka operacyjne. Po pierwsze, image() przyjmuje ścieżkę lub Uniform Resource Locator (URL). W scenariuszach z niezaufanymi danymi wejściowymi ogranicz zdalne pobieranie za pomocą ExternalResourcePolicyInterface (zobacz stronę poświęconą zasadom bezpieczeństwa), zamiast przekazywać bezpośrednio adresy URL kontrolowane przez użytkownika. Po drugie, writeHtml() jest punktem wejścia do potoku HTML. Niezaufany kod znaczników musi przejść przez HtmlSecurityPolicyInterface przed renderowaniem. Sama warstwa dokumentu nie wykonuje sanityzacji. To zadanie domeny zasad bezpieczeństwa; ponieważ chodzi o kontrakt, możesz dostarczyć bardziej restrykcyjną zasadę bez forkowania.

Kontrakty dokumentu implementują strukturę dokumentu PDF 2.0 zdefiniowaną w normie ISO 32000-2. Obsługa danych wyjściowych, stron i czcionek tworzy obiekty pośrednie oraz strumień odsyłaczy zgodnie z ISO 32000-2 §7. Warstwa writera emituje treść zgodnie z kontraktem warstwy silnika oraz rekordem decyzji architektonicznej (ADR-010). Ta strona nie formułuje twierdzeń na poziomie klauzul poza zgodnością strukturalną. Strony poświęcone ekstrakcji i dostępności dokumentują zgodność z PDF/A i PDF/UA oraz zawierają tabele normatywne.