Passed
Push — master ( d12d76...a43d60 )
by Greg
05:47
created

PdfRenderer::createCell()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 14
dl 0
loc 3
rs 10
c 1
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2019 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Report;
21
22
use Fisharebest\Webtrees\MediaFile;
23
use Fisharebest\Webtrees\Webtrees;
24
use League\Flysystem\FilesystemInterface;
25
26
use function count;
27
28
/**
29
 * Class PdfRenderer
30
 */
31
class PdfRenderer extends AbstractRenderer
32
{
33
    /**
34
     * PDF compression - Zlib extension is required
35
     *
36
     * @var bool const
37
     */
38
    private const COMPRESSION = true;
39
40
    /**
41
     * If true reduce the RAM memory usage by caching temporary data on filesystem (slower).
42
     *
43
     * @var bool const
44
     */
45
    private const DISK_CACHE = false;
46
47
    /**
48
     * true means that the input text is unicode (PDF)
49
     *
50
     * @var bool const
51
     */
52
    private const UNICODE = true;
53
54
    /**
55
     * false means that the full font is embedded, true means only the used chars
56
     * in TCPDF v5.9 font subsetting is a very slow process, this leads to larger files
57
     *
58
     * @var bool const
59
     */
60
    private const SUBSETTING = false;
61
62
    /**
63
     * @var TcpdfWrapper
64
     */
65
    public $tcpdf;
66
67
    /** @var ReportBaseElement[] Array of elements in the header */
68
    public $headerElements = [];
69
70
    /** @var ReportBaseElement[] Array of elements in the page header */
71
    public $pageHeaderElements = [];
72
73
    /** @var ReportBaseElement[] Array of elements in the footer */
74
    public $footerElements = [];
75
76
    /** @var ReportBaseElement[] Array of elements in the body */
77
    public $bodyElements = [];
78
79
    /** @var ReportPdfFootnote[] Array of elements in the footer notes */
80
    public $printedfootnotes = [];
81
82
    /** @var string Currently used style name */
83
    public $currentStyle = '';
84
85
    /** @var float The last cell height */
86
    public $lastCellHeight = 0;
87
88
    /** @var float The largest font size within a TextBox to calculate the height */
89
    public $largestFontHeight = 0;
90
91
    /** @var int The last pictures page number */
92
    public $lastpicpage = 0;
93
94
    /** @var PdfRenderer The current report. */
95
    public $wt_report;
96
97
    /**
98
     * PDF Header -PDF
99
     *
100
     * @return void
101
     */
102
    public function header(): void
103
    {
104
        foreach ($this->headerElements as $element) {
105
            if ($element instanceof ReportBaseElement) {
106
                $element->render($this);
107
            } elseif ($element === 'footnotetexts') {
108
                $this->footnotes();
109
            } elseif ($element === 'addpage') {
110
                $this->newPage();
111
            }
112
        }
113
114
        foreach ($this->pageHeaderElements as $element) {
115
            if ($element instanceof ReportBaseElement) {
116
                $element->render($this);
117
            } elseif ($element === 'footnotetexts') {
118
                $this->footnotes();
119
            } elseif ($element === 'addpage') {
120
                $this->newPage();
121
            }
122
        }
123
    }
124
125
    /**
126
     * PDF Body -PDF
127
     *
128
     * @return void
129
     */
130
    public function body(): void
131
    {
132
        $this->tcpdf->AddPage();
133
134
        foreach ($this->bodyElements as $key => $element) {
135
            if ($element instanceof ReportBaseElement) {
136
                $element->render($this);
137
            } elseif ($element === 'footnotetexts') {
138
                $this->footnotes();
139
            } elseif ($element === 'addpage') {
140
                $this->newPage();
141
            }
142
        }
143
    }
144
145
    /**
146
     * PDF Footnotes -PDF
147
     *
148
     * @return void
149
     */
150
    public function footnotes(): void
151
    {
152
        foreach ($this->printedfootnotes as $element) {
153
            if (($this->tcpdf->GetY() + $element->getFootnoteHeight($this)) > $this->tcpdf->getPageHeight()) {
154
                $this->tcpdf->AddPage();
155
            }
156
157
            $element->renderFootnote($this);
158
159
            if ($this->tcpdf->GetY() > $this->tcpdf->getPageHeight()) {
160
                $this->tcpdf->AddPage();
161
            }
162
        }
163
    }
164
165
    /**
166
     * PDF Footer -PDF
167
     *
168
     * @return void
169
     */
170
    public function footer(): void
171
    {
172
        foreach ($this->footerElements as $element) {
173
            if ($element instanceof ReportBaseElement) {
174
                $element->render($this);
175
            } elseif ($element === 'footnotetexts') {
176
                $this->footnotes();
177
            } elseif ($element === 'addpage') {
178
                $this->newPage();
179
            }
180
        }
181
    }
182
183
    /**
184
     * Add an element to the Header -PDF
185
     *
186
     * @param ReportBaseElement|string $element
187
     *
188
     * @return void
189
     */
190
    public function addHeader($element): void
191
    {
192
        $this->headerElements[] = $element;
193
    }
194
195
    /**
196
     * Add an element to the Page Header -PDF
197
     *
198
     * @param ReportBaseElement|string $element
199
     *
200
     * @return void
201
     */
202
    public function addPageHeader($element): void
203
    {
204
        $this->pageHeaderElements[] = $element;
205
    }
206
207
    /**
208
     * Add an element to the Body -PDF
209
     *
210
     * @param ReportBaseElement|string $element
211
     *
212
     * @return void
213
     */
214
    public function addBody($element): void
215
    {
216
        $this->bodyElements[] = $element;
217
    }
218
219
    /**
220
     * Add an element to the Footer -PDF
221
     *
222
     * @param ReportBaseElement|string $element
223
     *
224
     * @return void
225
     */
226
    public function addFooter($element): void
227
    {
228
        $this->footerElements[] = $element;
229
    }
230
231
    /**
232
     * Remove the header.
233
     *
234
     * @param int $index
235
     *
236
     * @return void
237
     */
238
    public function removeHeader(int $index): void
239
    {
240
        unset($this->headerElements[$index]);
241
    }
242
243
    /**
244
     * Remove the page header.
245
     *
246
     * @param int $index
247
     *
248
     * @return void
249
     */
250
    public function removePageHeader(int $index): void
251
    {
252
        unset($this->pageHeaderElements[$index]);
253
    }
254
255
    /**
256
     * Remove the body.
257
     *
258
     * @param int $index
259
     *
260
     * @return void
261
     */
262
    public function removeBody(int $index): void
263
    {
264
        unset($this->bodyElements[$index]);
265
    }
266
267
    /**
268
     * Remove the footer.
269
     *
270
     * @param int $index
271
     *
272
     * @return void
273
     */
274
    public function removeFooter(int $index): void
275
    {
276
        unset($this->footerElements[$index]);
277
    }
278
279
    /**
280
     * Clear the Header -PDF
281
     *
282
     * @return void
283
     */
284
    public function clearHeader(): void
285
    {
286
        unset($this->headerElements);
287
        $this->headerElements = [];
288
    }
289
290
    /**
291
     * Clear the Page Header -PDF
292
     *
293
     * @return void
294
     */
295
    public function clearPageHeader(): void
296
    {
297
        unset($this->pageHeaderElements);
298
        $this->pageHeaderElements = [];
299
    }
300
301
    /**
302
     * Set the report.
303
     *
304
     * @param PdfRenderer $report
305
     *
306
     * @return void
307
     */
308
    public function setReport(PdfRenderer $report): void
309
    {
310
        $this->wt_report = $report;
311
    }
312
313
    /**
314
     * Get the currently used style name -PDF
315
     *
316
     * @return string
317
     */
318
    public function getCurrentStyle(): string
319
    {
320
        return $this->currentStyle;
321
    }
322
323
    /**
324
     * Setup a style for usage -PDF
325
     *
326
     * @param string $s Style name
327
     *
328
     * @return void
329
     */
330
    public function setCurrentStyle(string $s): void
331
    {
332
        $this->currentStyle = $s;
333
        $style              = $this->wt_report->getStyle($s);
334
        $this->tcpdf->SetFont($style['font'], $style['style'], $style['size']);
335
    }
336
337
    /**
338
     * Get the style -PDF
339
     *
340
     * @param string $s Style name
341
     *
342
     * @return array
343
     */
344
    public function getStyle(string $s): array
345
    {
346
        if (!isset($this->wt_report->styles[$s])) {
347
            $s                           = $this->getCurrentStyle();
348
            $this->wt_report->styles[$s] = $s;
349
        }
350
351
        return $this->wt_report->styles[$s];
352
    }
353
354
    /**
355
     * Add margin when static horizontal position is used -PDF
356
     * RTL supported
357
     *
358
     * @param float $x Static position
359
     *
360
     * @return float
361
     */
362
    public function addMarginX(float $x): float
363
    {
364
        $m = $this->tcpdf->getMargins();
365
        if ($this->tcpdf->getRTL()) {
366
            $x += $m['right'];
367
        } else {
368
            $x += $m['left'];
369
        }
370
        $this->tcpdf->SetX($x);
371
372
        return $x;
373
    }
374
375
    /**
376
     * Get the maximum line width to draw from the curren position -PDF
377
     * RTL supported
378
     *
379
     * @return float
380
     */
381
    public function getMaxLineWidth(): float
382
    {
383
        $m = $this->tcpdf->getMargins();
384
        if ($this->tcpdf->getRTL()) {
385
            return ($this->tcpdf->getRemainingWidth() + $m['right']);
386
        }
387
388
        return ($this->tcpdf->getRemainingWidth() + $m['left']);
389
    }
390
391
    /**
392
     * Get the height of the footnote.
393
     *
394
     * @return float
395
     */
396
    public function getFootnotesHeight(): float
397
    {
398
        $h = 0;
399
        foreach ($this->printedfootnotes as $element) {
400
            $h += $element->getHeight($this);
401
        }
402
403
        return $h;
404
    }
405
406
    /**
407
     * Returns the the current font size height -PDF
408
     *
409
     * @return float
410
     */
411
    public function getCurrentStyleHeight(): float
412
    {
413
        if ($this->currentStyle === '') {
414
            return $this->wt_report->default_font_size;
415
        }
416
        $style = $this->wt_report->getStyle($this->currentStyle);
417
418
        return (float) $style['size'];
419
    }
420
421
    /**
422
     * Checks the Footnote and numbers them
423
     *
424
     * @param ReportPdfFootnote $footnote
425
     *
426
     * @return ReportPdfFootnote|bool object if already numbered, false otherwise
427
     */
428
    public function checkFootnote(ReportPdfFootnote $footnote)
429
    {
430
        $ct  = count($this->printedfootnotes);
431
        $val = $footnote->getValue();
432
        $i   = 0;
433
        while ($i < $ct) {
434
            if ($this->printedfootnotes[$i]->getValue() == $val) {
435
                // If this footnote already exist then set up the numbers for this object
436
                $footnote->setNum($i + 1);
437
                $footnote->setAddlink((string) ($i + 1));
438
439
                return $this->printedfootnotes[$i];
440
            }
441
            $i++;
442
        }
443
        // If this Footnote has not been set up yet
444
        $footnote->setNum($ct + 1);
445
        $footnote->setAddlink((string) $this->tcpdf->AddLink());
446
        $this->printedfootnotes[] = $footnote;
447
448
        return false;
449
    }
450
451
    /**
452
     * Used this function instead of AddPage()
453
     * This function will make sure that images will not be overwritten
454
     *
455
     * @return void
456
     */
457
    public function newPage(): void
458
    {
459
        if ($this->lastpicpage > $this->tcpdf->getPage()) {
460
            $this->tcpdf->setPage($this->lastpicpage);
461
        }
462
        $this->tcpdf->AddPage();
463
    }
464
465
    /**
466
     * Add a page if needed -PDF
467
     *
468
     * @param float $height Cell height
469
     *
470
     * @return bool true in case of page break, false otherwise
471
     */
472
    public function checkPageBreakPDF(float $height): bool
473
    {
474
        return $this->tcpdf->checkPageBreak($height);
475
    }
476
477
    /**
478
     * Returns the remaining width between the current position and margins -PDF
479
     *
480
     * @return float Remaining width
481
     */
482
    public function getRemainingWidthPDF(): float
483
    {
484
        return $this->tcpdf->getRemainingWidth();
485
    }
486
    /**
487
     * PDF Setup - ReportPdf
488
     *
489
     * @return void
490
     */
491
    public function setup(): void
492
    {
493
        parent::setup();
494
495
        // Setup the PDF class with custom size pages because WT supports more page sizes. If WT sends an unknown size name then the default would be A4
496
        $this->tcpdf = new TcpdfWrapper($this->orientation, parent::UNITS, [
497
            $this->page_width,
498
            $this->page_height,
499
        ], self::UNICODE, 'UTF-8', self::DISK_CACHE);
500
501
        // Setup the PDF margins
502
        $this->tcpdf->SetMargins($this->left_margin, $this->top_margin, $this->right_margin);
503
        $this->tcpdf->setHeaderMargin($this->header_margin);
504
        $this->tcpdf->setFooterMargin($this->footer_margin);
505
        //Set auto page breaks
506
        $this->tcpdf->SetAutoPageBreak(true, $this->bottom_margin);
507
        // Set font subsetting
508
        $this->tcpdf->setFontSubsetting(self::SUBSETTING);
509
        // Setup PDF compression
510
        $this->tcpdf->SetCompression(self::COMPRESSION);
511
        // Setup RTL support
512
        $this->tcpdf->setRTL($this->rtl);
513
        // Set the document information
514
        $this->tcpdf->SetCreator(Webtrees::NAME . ' ' . Webtrees::VERSION);
515
        $this->tcpdf->SetAuthor($this->rauthor);
516
        $this->tcpdf->SetTitle($this->title);
517
        $this->tcpdf->SetSubject($this->rsubject);
518
        $this->tcpdf->SetKeywords($this->rkeywords);
519
520
        $this->setReport($this);
521
522
        if ($this->show_generated_by) {
523
            // The default style name for Generated by.... is 'genby'
524
            $element = new ReportPdfCell(0, 10, 0, 'C', '', 'genby', 1, ReportBaseElement::CURRENT_POSITION, ReportBaseElement::CURRENT_POSITION, 0, 0, '', '', true);
525
            $element->addText($this->generated_by);
526
            $element->setUrl(Webtrees::URL);
527
            $this->addFooter($element);
528
        }
529
    }
530
531
    /**
532
     * Add an element.
533
     *
534
     * @param ReportBaseElement|string $element
535
     *
536
     * @return void
537
     */
538
    public function addElement($element): void
539
    {
540
        if ($this->processing === 'B') {
541
            $this->addBody($element);
542
543
            return;
544
        }
545
546
        if ($this->processing === 'H') {
547
            $this->addHeader($element);
548
549
            return;
550
        }
551
552
        if ($this->processing === 'F') {
553
            $this->addFooter($element);
554
555
            return;
556
        }
557
    }
558
559
    /**
560
     * Run the report.
561
     *
562
     * @return void
563
     */
564
    public function run(): void
565
    {
566
        $this->body();
567
        echo $this->tcpdf->Output('doc.pdf', 'S');
568
    }
569
570
    /**
571
     * Create a new Cell object.
572
     *
573
     * @param int    $width   cell width (expressed in points)
574
     * @param int    $height  cell height (expressed in points)
575
     * @param mixed  $border  Border style
576
     * @param string $align   Text alignement
577
     * @param string $bgcolor Background color code
578
     * @param string $style   The name of the text style
579
     * @param int    $ln      Indicates where the current position should go after the call
580
     * @param mixed  $top     Y-position
581
     * @param mixed  $left    X-position
582
     * @param int    $fill    Indicates if the cell background must be painted (1) or transparent (0). Default value: 1
583
     * @param int    $stretch Stretch carachter mode
584
     * @param string $bocolor Border color
585
     * @param string $tcolor  Text color
586
     * @param bool   $reseth
587
     *
588
     * @return ReportBaseCell
589
     */
590
    public function createCell($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth): ReportBaseCell
591
    {
592
        return new ReportPdfCell($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth);
593
    }
594
595
    /**
596
     * Create a new TextBox object.
597
     *
598
     * @param float  $width   Text box width
599
     * @param float  $height  Text box height
600
     * @param bool   $border
601
     * @param string $bgcolor Background color code in HTML
602
     * @param bool   $newline
603
     * @param float  $left
604
     * @param float  $top
605
     * @param bool   $pagecheck
606
     * @param string $style
607
     * @param bool   $fill
608
     * @param bool   $padding
609
     * @param bool   $reseth
610
     *
611
     * @return ReportBaseTextbox
612
     */
613
    public function createTextBox(
614
        float $width,
615
        float $height,
616
        bool $border,
617
        string $bgcolor,
618
        bool $newline,
619
        float $left,
620
        float $top,
621
        bool $pagecheck,
622
        string $style,
623
        bool $fill,
624
        bool $padding,
625
        bool $reseth
626
    ): ReportBaseTextbox {
627
        return new ReportPdfTextBox($width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth);
628
    }
629
630
    /**
631
     * Create a text element.
632
     *
633
     * @param string $style
634
     * @param string $color
635
     *
636
     * @return ReportBaseText
637
     */
638
    public function createText(string $style, string $color): ReportBaseText
639
    {
640
        return new ReportPdfText($style, $color);
641
    }
642
643
    /**
644
     * Create a new Footnote object.
645
     *
646
     * @param string $style Style name
647
     *
648
     * @return ReportBaseFootnote
649
     */
650
    public function createFootnote($style): ReportBaseFootnote
651
    {
652
        return new ReportPdfFootnote($style);
653
    }
654
655
    /**
656
     * Create a new Page Header object
657
     *
658
     * @return ReportBasePageHeader
659
     */
660
    public function createPageHeader(): ReportBasePageHeader
661
    {
662
        return new ReportPdfPageHeader();
663
    }
664
665
    /**
666
     * Create a new image object.
667
     *
668
     * @param string $file  Filename
669
     * @param float  $x
670
     * @param float  $y
671
     * @param float  $w     Image width
672
     * @param float  $h     Image height
673
     * @param string $align L:left, C:center, R:right or empty to use x/y
674
     * @param string $ln    T:same line, N:next line
675
     *
676
     * @return ReportBaseImage
677
     */
678
    public function createImage(string $file, float $x, float $y, float $w, float $h, string $align, string $ln): ReportBaseImage
679
    {
680
        return new ReportPdfImage($file, $x, $y, $w, $h, $align, $ln);
681
    }
682
683
    /**
684
     * Create a new image object from Media Object.
685
     *
686
     * @param MediaFile           $media_file
687
     * @param float               $x
688
     * @param float               $y
689
     * @param float               $w     Image width
690
     * @param float               $h     Image height
691
     * @param string              $align L:left, C:center, R:right or empty to use x/y
692
     * @param string              $ln    T:same line, N:next line
693
     * @param FilesystemInterface $data_filesystem
694
     *
695
     * @return ReportBaseImage
696
     */
697
    public function createImageFromObject(
698
        MediaFile $media_file,
699
        float $x,
700
        float $y,
701
        float $w,
702
        float $h,
703
        string $align,
704
        string $ln,
705
        FilesystemInterface $data_filesystem
706
    ): ReportBaseImage {
707
        return new ReportPdfImage('@' . $media_file->fileContents($data_filesystem), $x, $y, $w, $h, $align, $ln);
708
    }
709
710
    /**
711
     * Create a line.
712
     *
713
     * @param float $x1
714
     * @param float $y1
715
     * @param float $x2
716
     * @param float $y2
717
     *
718
     * @return ReportBaseLine
719
     */
720
    public function createLine(float $x1, float $y1, float $x2, float $y2): ReportBaseLine
721
    {
722
        return new ReportPdfLine($x1, $y1, $x2, $y2);
723
    }
724
725
    /**
726
     * Create an HTML element.
727
     *
728
     * @param string   $tag
729
     * @param string[] $attrs
730
     *
731
     * @return ReportBaseHtml
732
     */
733
    public function createHTML(string $tag, array $attrs): ReportBaseHtml
734
    {
735
        return new ReportPdfHtml($tag, $attrs);
736
    }
737
}
738