Document: DParts, pemisahan / penggabungan, dan ekstensi vendor
Sekilas pandang
Bagian berjudul “Sekilas pandang”Modul Document menangani berkas Portable Document Format (PDF) secara utuh, bukan konten halaman. Modul ini membangun hierarki Document Part yang digunakan oleh alur kerja teregulasi untuk melampirkan metadata. Modul ini memisahkan PDF menjadi segmen rentang halaman, menggabungkan beberapa PDF menjadi satu, dan mendaftarkan ekstensi pengembang di katalog dokumen.
Instalasi
Bagian berjudul “Instalasi”composer require nextpdf/core:^3Ikhtisar konseptual
Bagian berjudul “Ikhtisar konseptual”Modul ini beroperasi di atas lapisan konten halaman. Jika Graphics dan Content menghasilkan operator, Document bekerja pada tingkat struktural: page tree, katalog dokumen, dan Document Part tree.
Sebuah Document Part (DPart) adalah partisi logis dalam sebuah PDF. ISO 32000-2 mendefinisikan hierarki DPart dengan node yang membawa Document Part Metadata (DPM). Alur kerja teregulasi, seperti farmasi, hukum, atau pengarsipan, dapat mengaitkan metadata dengan sub-rentang halaman, bukan dengan seluruh berkas — §14.12. DPart adalah node readonly yang tidak dapat diubah: node daun mereferensikan rentang indeks halaman yang bersambung, dan node perantara mengelompokkan node anak DPart menjadi sebuah tree. DPartRoot adalah akar tree yang diserialisasi oleh Writer. Entri /Start dan /End pada node daun merupakan referensi tidak langsung ke objek halaman, bukan bilangan bulat indeks halaman — §14.12. DPart::resolveWithPageObjects() menyelesaikan entri tersebut terhadap peta indeks-halaman→nomor-objek yang disediakan writer dan mengembalikan bentuk referensi /Start (dan /End opsional). Bentuk bilangan bulat hanya digunakan sebagai cadangan pada jalur pengujian ketika peta tersebut tidak tersedia.
PdfMerger dan PdfSplitter adalah antarmuka komposisi dokumen. PdfMerger menggabungkan objek halaman dari beberapa PDF masukan, menomori ulang objek untuk menghindari tabrakan, dan membangun ulang satu page tree serta satu tabel referensi-silang. Page tree yang dihasilkan adalah node Pages yang seimbang dengan Kids dan Count, ditambah model atribut yang dapat diwariskan yang didefinisikan PDF untuk node page-tree — §7.7.3. PdfSplitter melakukan kebalikannya: ia mengekstrak rentang halaman menjadi objek SplitDocument mandiri. PageRange adalah value object yang dikonsumsi oleh kedua kelas tersebut. Objek ini berbasis-1, memvalidasi batasnya, dan menjawab contains(), count(), dan toArray().
VendorExtensionRegistry, ExtensionsDictionary, dan DeveloperExtensionEntry memodelkan dictionary developer-extensions di katalog dokumen. Engine menggunakan dictionary tersebut untuk mendeklarasikan tingkat ekstensi vendor di luar spesifikasi dasar. Registry menolak pendaftaran ulang prefiks vendor yang sama ketika menimbulkan konflik, dengan VendorExtensionRegistryConflictException. CollectionDictionary dan CollectionSort memodelkan entri katalog collection PDF (portable collection atau portfolio).
Antarmuka API
Bagian berjudul “Antarmuka API”| Kelas | Metode utama | Peran |
|---|---|---|
DPart | isLeaf(), hasMetadata(), resolveWithPageObjects(), write() | Node Document Part yang immutable (@since 1.12.0) |
DPartRoot | isEmpty(), write() | Akar DPart tree yang diserialisasi oleh Writer (@since 1.12.0) |
PdfMerger | merge(array $pdfFiles, int $maxFiles = 100, int $maxTotalBytes = 200_000_000), append() | Penggabungan multi-PDF dengan penomoran ulang objek (@since 1.9.0) |
PdfSplitter | split(), splitEvery(), extractPages() | Pemisahan rentang halaman menjadi SplitDocument (@since 1.9.0) |
PageRange | contains(int $page), count(), toArray() | Value object rentang halaman berbasis-1 |
MergeResult / SplitResult | isValid(), count(), document(), totalOutputSize() | Objek hasil komposisi |
VendorExtensionRegistry | pendaftaran ekstensi | Registry developer-extensions (@since 2.2.0) |
ExtensionsDictionary | withEntry(), entries(), isEmpty(), toPdfDictionary() | Builder extensions-dictionary yang tidak dapat diubah (@since 2.0.0) |
CollectionDictionary | toPdfDictionary() | Entri katalog portable-collection (@since 2.0.0) |
Jalankan composer docs:generate-api-php -- --module=Document untuk menghasilkan tabel PHPDoc lengkap.
Contoh kode — Mulai cepat
Bagian berjudul “Contoh kode — Mulai cepat”Pisahkan sebuah PDF menjadi dokumen satu halaman, lalu periksa hasilnya.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Document\PageRange;use NextPDF\Document\PdfSplitter;
$splitter = new PdfSplitter();$result = $splitter->splitEvery(file_get_contents('/srv/in/report.pdf'), 1);
foreach (range(0, $result->count() - 1) as $index) { $segment = $result->document($index); file_put_contents("/srv/out/page-{$index}.pdf", $segment->pdfData);}
$singlePage = $splitter->extractPages( file_get_contents('/srv/in/report.pdf'), new PageRange(2, 4),);Contoh kode — Produksi
Bagian berjudul “Contoh kode — Produksi”Gabungkan beberapa PDF dengan anggaran masukan yang eksplisit, lalu validasi hasilnya sebelum menulis keluaran gabungan.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Document\PdfMerger;use NextPDF\Exception\PageLayoutException;
/** @var list<string> $sources Raw PDF byte strings to combine. */$sources = array_map( static fn (string $path): string => file_get_contents($path), glob('/srv/batch/*.pdf') ?: [],);
$merger = new PdfMerger();
try { // Bound the merge: at most 50 files, 100 MB total. $merged = $merger->merge($sources, maxFiles: 50, maxTotalBytes: 100_000_000);} catch (PageLayoutException $e) { throw new \RuntimeException('Merge rejected: empty or invalid input set.', previous: $e);}
if (!$merged->isValid()) { throw new \RuntimeException('Merged document failed structural validation.');}
file_put_contents('/srv/out/combined.pdf', $merged->pdfData);Kasus tepi & jebakan
Bagian berjudul “Kasus tepi & jebakan”PdfMerger::merge()danPdfSplitter::split()memberlakukan batasan masukan melaluiResourceGuard. Jika masukan berisi terlalu banyak berkas atau terlalu banyak byte, metode ini memunculkan exception alih-alih memangkasnya secara diam-diam. TetapkanmaxFiles/maxTotalBytesdengan sengaja sesuai beban kerja Anda.- Daftar berkas kosong atau daftar rentang kosong memunculkan
PageLayoutException. Perlakukan ini sebagai kesalahan konfigurasi, bukan hasil kosong. PageRangeberbasis-1 dan inklusif. SebuahDPartdaun memiliki daftarpagesberupa indeks halaman berbasis-0. Kedua abstraksi tersebut menggunakan basis indeks yang berbeda. Konversikan secara eksplisit ketika Anda berpindah di antara keduanya.DPartbersifatreadonly. Untuk membangun tree yang berbeda, buat node baru alih-alih mengubah node yang sudah ada.resolveWithPageObjects()mengembalikan bentuk cadangan indeks bilangan bulat hanya ketika peta page-object kosong. Jangan mengandalkan jalur tersebut pada keluaran produksi.VendorExtensionRegistrymemunculkanVendorExtensionRegistryConflictExceptionuntuk prefiks vendor yang duplikat. Daftarkan setiap prefiks satu kali saja.
Performa
Bagian berjudul “Performa”Pemisahan dan penggabungan berskala linear terhadap jumlah halaman dan didominasi oleh penguraian serta penomoran ulang objek, bukan oleh pencatatan internal modul itu sendiri. Beban kerja referensi standar masuk dalam anggaran 1500 ms wall / 64 MB puncak. Penggabungan berukuran besar terutama dibatasi oleh total byte masukan. Guard maxTotalBytes menjaga memori puncak tetap terbatas. Profil reproduktivitasnya adalah structural: PDF yang digabung atau dipisah membawa trailer dan /ID yang baru, sehingga dua kali eksekusi setara secara struktural tetapi tidak identik secara byte.
Catatan keamanan
Bagian berjudul “Catatan keamanan”PdfMerger::merge() dan PdfSplitter::split() mengonsumsi byte PDF yang tidak tepercaya. Sebelum penguraian, keduanya melewatkan masukan melalui ResourceGuard::assertSize() / assertCount(), yang membatasi denial of service akibat amplifikasi dekompresi atau jumlah objek. Tetapkan argumen maxFiles, maxTotalBytes, dan maxBytes secara ketat untuk deployment, alih-alih mengandalkan nilai standar. Perlakukan setiap PDF masukan sebagai berbahaya. Ketika sumber berasal dari pengguna, jalankan komposisi batch di worker yang terbatas. Lihat model ancaman engine di /modules/core/security/ untuk batas kepercayaan.
Kesesuaian
Bagian berjudul “Kesesuaian”DPart tree yang dibangun modul ini mengikuti model Document Part dalam ISO 32000-2 §14.12, dengan entri /Start dan /End daun yang dipancarkan sebagai referensi tidak langsung ke objek halaman di bawah klausa yang sama. Keluaran gabungan menggunakan struktur node page-tree yang didefinisikan dalam §7.7.3. Hal ini merupakan fakta implementasi yang dihasilkan oleh src/Document/ dan diuji oleh tests/Unit/Document/ (DPartTest, DPartRootTest, DPartPageRefTest, DocumentPdfMergerDeepTest, DocumentPageRangeParseDeepTest). Ini bukan pernyataan kesesuaian PDF 2.0 secara menyeluruh. Kesesuaian dokumen secara penuh divalidasi oleh oracle dan golden suite yang dijelaskan dalam /modules/core/conformance/.
Lihat juga
Bagian berjudul “Lihat juga”- Modul Core
- Modul Writer — menyerialisasi DPart tree dan page tree.
- Modul Metadata — Extensible Metadata Platform (XMP) yang berpasangan dengan DPM.
- Modul Navigation
- Ikhtisar kesesuaian
- Model keamanan engine