Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
98.92% |
92 / 93 |
|
95.65% |
22 / 23 |
CRAP | |
0.00% |
0 / 1 |
Document | |
98.92% |
92 / 93 |
|
95.65% |
22 / 23 |
53 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
5 | |||
addPage | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
addPages | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
createPage | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
copyPage | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
orderPages | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
5 | |||
deletePage | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
4 | |||
addFont | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
addFonts | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
embedFont | |
88.89% |
8 / 9 |
|
0.00% |
0 / 1 |
5.03 | |||
embedFonts | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
createStyle | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
addStyle | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
addStyles | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
setCurrentPage | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
setCurrentFont | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
importObjects | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
importFonts | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
hasImportedObjects | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasImportedFonts | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getImportObjects | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getImportedFonts | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__toString | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Pdf; |
15 | |
16 | use Pop\Pdf\Document\AbstractDocument; |
17 | use Pop\Pdf\Document\Page; |
18 | use Pop\Pdf\Document\Font; |
19 | use Pop\Pdf\Document\Metadata; |
20 | use Pop\Pdf\Document\Exception; |
21 | use Pop\Pdf\Document\Style; |
22 | |
23 | /** |
24 | * Pdf document class |
25 | * |
26 | * @category Pop |
27 | * @package Pop\Pdf |
28 | * @author Nick Sagona, III <dev@nolainteractive.com> |
29 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
30 | * @license http://www.popphp.org/license New BSD License |
31 | * @version 5.0.0 |
32 | */ |
33 | class Document extends AbstractDocument |
34 | { |
35 | |
36 | /** |
37 | * Imported objects |
38 | * @var array |
39 | */ |
40 | protected array $importedObjects = []; |
41 | |
42 | /** |
43 | * Imported fonts |
44 | * @var array |
45 | */ |
46 | protected array $importedFonts = []; |
47 | |
48 | /** |
49 | * Constructor |
50 | * |
51 | * Instantiate a PDF document |
52 | * |
53 | * @param ?Page $page |
54 | * @param ?Metadata $metadata |
55 | * @param Style|array|null $style |
56 | */ |
57 | public function __construct(?Page $page = null, ?Metadata $metadata = null, Style|array|null $style = null) |
58 | { |
59 | if ($page !== null) { |
60 | $this->addPage($page); |
61 | } |
62 | |
63 | $this->setMetadata((($metadata !== null) ? $metadata : new Metadata())); |
64 | |
65 | if ($style !== null) { |
66 | if (is_array($style)) { |
67 | $this->addStyles($style); |
68 | } else { |
69 | $this->addStyle($style); |
70 | } |
71 | } |
72 | } |
73 | |
74 | /** |
75 | * Add a page to the PDF document |
76 | * |
77 | * @param Page $page |
78 | * @return Document |
79 | */ |
80 | public function addPage(Page $page): Document |
81 | { |
82 | $this->pages[] = $page; |
83 | $this->currentPage = count($this->pages); |
84 | return $this; |
85 | } |
86 | |
87 | /** |
88 | * Add pages to the PDF document |
89 | * |
90 | * @param array $pages |
91 | * @return Document |
92 | */ |
93 | public function addPages(array $pages): Document |
94 | { |
95 | foreach ($pages as $page) { |
96 | $this->addPage($page); |
97 | } |
98 | return $this; |
99 | } |
100 | |
101 | /** |
102 | * Create and return a new page object, adding it to the PDF document |
103 | * |
104 | * @param mixed $size |
105 | * @param ?int $height |
106 | * @throws Exception |
107 | * @return Page |
108 | */ |
109 | public function createPage(mixed $size, ?int $height = null): Page |
110 | { |
111 | $page = new Page($size, $height); |
112 | $this->addPage($page); |
113 | return $page; |
114 | } |
115 | |
116 | /** |
117 | * Copy and return a page of the PDF, adding it to the PDF document |
118 | * |
119 | * @param int $p |
120 | * @param bool $preserveContent |
121 | * @throws Exception |
122 | * @return Page |
123 | */ |
124 | public function copyPage(int $p, bool $preserveContent = true): Page |
125 | { |
126 | if (!isset($this->pages[$p - 1])) { |
127 | throw new Exception("Error: That page (" . $p . ") does not exist."); |
128 | } |
129 | |
130 | $page = clone $this->pages[$p - 1]; |
131 | |
132 | if (!$preserveContent) { |
133 | $page->clearContent(); |
134 | } |
135 | |
136 | $this->addPage($page); |
137 | return $page; |
138 | } |
139 | |
140 | /** |
141 | * Order the pages |
142 | * |
143 | * @param array $pages |
144 | * @throws Exception |
145 | * @return Document |
146 | */ |
147 | public function orderPages(array $pages): Document |
148 | { |
149 | $newOrder = []; |
150 | |
151 | // Check if the numbers of pages passed equals the number of pages in the PDF. |
152 | if (count($pages) != count($this->pages)) { |
153 | throw new Exception('Error: The pages array passed does not contain the same number of pages as the PDF.'); |
154 | } |
155 | |
156 | // Make sure each page passed is within the PDF and not out of range. |
157 | foreach ($pages as $value) { |
158 | if (!array_key_exists(($value - 1), $this->pages)) { |
159 | throw new Exception('Error: The pages array passed contains a page that does not exist.'); |
160 | } |
161 | } |
162 | |
163 | // Set the new order of the page objects. |
164 | foreach ($pages as $value) { |
165 | $newOrder[] = $this->pages[$value - 1]; |
166 | } |
167 | |
168 | // Set the pages arrays to the new order. |
169 | $this->pages = $newOrder; |
170 | return $this; |
171 | } |
172 | |
173 | /** |
174 | * Delete a page from the PDF document |
175 | * |
176 | * @param int $p |
177 | * @throws Exception |
178 | * @return Document |
179 | */ |
180 | public function deletePage(int $p): Document |
181 | { |
182 | if (!isset($this->pages[$p - 1])) { |
183 | throw new Exception("Error: That page (" . $p . ") does not exist."); |
184 | } |
185 | |
186 | unset($this->pages[$p - 1]); |
187 | |
188 | // Reset current page if current page was the one deleted |
189 | if ($this->currentPage == $p) { |
190 | $this->currentPage = (count($this->pages) > 0) ? (count($this->pages) - 1) : null; |
191 | } |
192 | |
193 | return $this; |
194 | } |
195 | |
196 | /** |
197 | * Add a font |
198 | * |
199 | * @param Font|string $font |
200 | * @param bool $embedOverride |
201 | * @throws Exception |
202 | * @return Document |
203 | */ |
204 | public function addFont(Font|string $font, bool $embedOverride = false): Document |
205 | { |
206 | if (is_string($font)) { |
207 | $font = new Font($font); |
208 | } |
209 | if (!$font->isStandard()) { |
210 | $this->embedFont($font, $embedOverride); |
211 | } else { |
212 | if (!array_key_exists($font->getName(), $this->fonts)) { |
213 | $this->fonts[$font->getName()] = $font; |
214 | $this->currentFont = $font->getName(); |
215 | } |
216 | } |
217 | |
218 | return $this; |
219 | } |
220 | |
221 | /** |
222 | * Add fonts |
223 | * |
224 | * @param array $fonts |
225 | * @param bool $embedOverride |
226 | * @throws Exception |
227 | * @return Document |
228 | */ |
229 | public function addFonts(array $fonts, bool $embedOverride = false): Document |
230 | { |
231 | foreach ($fonts as $font) { |
232 | $this->addFont($font, $embedOverride); |
233 | } |
234 | |
235 | return $this; |
236 | } |
237 | |
238 | /** |
239 | * Add a font |
240 | * |
241 | * @param Font $font |
242 | * @param bool $embedOverride |
243 | * @throws Exception |
244 | * @return Document |
245 | */ |
246 | public function embedFont(Font $font, bool $embedOverride = false): Document |
247 | { |
248 | if (!$font->isEmbedded()) { |
249 | $this->addFont($font); |
250 | } else { |
251 | if (!$font->parser()->isEmbeddable() && !$embedOverride) { |
252 | throw new Exception('Error: The font license does not allow for it to be embedded.'); |
253 | } |
254 | |
255 | if (!array_key_exists($font->parser()->getFontName(), $this->fonts)) { |
256 | $font->parser()->setCompression($this->compression); |
257 | $this->fonts[$font->parser()->getFontName()] = $font; |
258 | $this->currentFont = $font->parser()->getFontName(); |
259 | } |
260 | } |
261 | |
262 | return $this; |
263 | } |
264 | |
265 | /** |
266 | * Embed fonts |
267 | * |
268 | * @param array $fonts |
269 | * @param bool $embedOverride |
270 | * @throws Exception |
271 | * @return Document |
272 | */ |
273 | public function embedFonts(array $fonts, bool $embedOverride = false): Document |
274 | { |
275 | foreach ($fonts as $font) { |
276 | $this->embedFont($font, $embedOverride); |
277 | } |
278 | |
279 | return $this; |
280 | } |
281 | |
282 | /** |
283 | * Create style |
284 | * |
285 | * @param Style|string $style |
286 | * @return Document |
287 | */ |
288 | public function createStyle(Style|string $style, ?string $font = null, int|float|null $size = null): Document |
289 | { |
290 | return ($style instanceof Style) ? |
291 | $this->addStyle($style) : $this->addStyle(new Style($style, $font, $size)); |
292 | } |
293 | |
294 | /** |
295 | * Add a style |
296 | * |
297 | * @param Style|string $style |
298 | * @return Document |
299 | */ |
300 | public function addStyle(Style|string $style): Document |
301 | { |
302 | if (is_string($style)) { |
303 | $style = new Style($style); |
304 | } |
305 | |
306 | if (!array_key_exists($style->getName(), $this->styles)) { |
307 | $this->styles[$style->getName()] = $style; |
308 | } |
309 | |
310 | return $this; |
311 | } |
312 | |
313 | /** |
314 | * Add styles |
315 | * |
316 | * @param array $styles |
317 | * @return AbstractDocument |
318 | */ |
319 | public function addStyles(array $styles): Document |
320 | { |
321 | foreach ($styles as $style) { |
322 | $this->addStyle($style); |
323 | } |
324 | return $this; |
325 | } |
326 | |
327 | /** |
328 | * Set the current page of the PDF document |
329 | * |
330 | * @param int $p |
331 | * @throws Exception |
332 | * @return Document |
333 | */ |
334 | public function setCurrentPage(int $p): Document |
335 | { |
336 | // Check if the page exists. |
337 | if (!isset($this->pages[$p - 1])) { |
338 | throw new Exception("Error: That page (" . $p . ") does not exist."); |
339 | } |
340 | $this->currentPage = $p; |
341 | |
342 | return $this; |
343 | } |
344 | |
345 | /** |
346 | * Set the current font of the PDF document |
347 | * |
348 | * @param string $name |
349 | * @throws Exception |
350 | * @return Document |
351 | */ |
352 | public function setCurrentFont(string $name): Document |
353 | { |
354 | // Check if the font exists. |
355 | if (!isset($this->fonts[$name])) { |
356 | throw new Exception("Error: The font '" . $name . "' has not been added to the PDF document."); |
357 | } |
358 | $this->currentFont = $name; |
359 | |
360 | return $this; |
361 | } |
362 | |
363 | /** |
364 | * Import objects into document |
365 | * |
366 | * @param array $objects |
367 | * @return Document |
368 | */ |
369 | public function importObjects(array $objects): Document |
370 | { |
371 | $this->importedObjects = $objects; |
372 | return $this; |
373 | } |
374 | |
375 | /** |
376 | * Import fonts into document |
377 | * |
378 | * @param array $fonts |
379 | * @return Document |
380 | */ |
381 | public function importFonts(array $fonts): Document |
382 | { |
383 | foreach ($fonts as $font) { |
384 | $this->fonts[$font['name']] = $font; |
385 | } |
386 | $this->importedFonts = $fonts; |
387 | return $this; |
388 | } |
389 | |
390 | /** |
391 | * Determine if the document has imported objects |
392 | * |
393 | * @return bool |
394 | */ |
395 | public function hasImportedObjects(): bool |
396 | { |
397 | return (count($this->importedObjects) > 0); |
398 | } |
399 | |
400 | /** |
401 | * Determine if the document has imported fonts |
402 | * |
403 | * @return bool |
404 | */ |
405 | public function hasImportedFonts(): bool |
406 | { |
407 | return (count($this->importedFonts) > 0); |
408 | } |
409 | |
410 | /** |
411 | * Get the imported objects |
412 | * |
413 | * @return array |
414 | */ |
415 | public function getImportObjects(): array |
416 | { |
417 | return $this->importedObjects; |
418 | } |
419 | |
420 | /** |
421 | * Get the import fonts |
422 | * |
423 | * @return array |
424 | */ |
425 | public function getImportedFonts(): array |
426 | { |
427 | return $this->importedFonts; |
428 | } |
429 | |
430 | /** |
431 | * Output the PDF document to string |
432 | * |
433 | * @return string |
434 | */ |
435 | public function __toString(): string |
436 | { |
437 | $compiler = new Build\Compiler(); |
438 | $compiler->finalize($this); |
439 | return $compiler->getOutput(); |
440 | } |
441 | |
442 | } |