ReportPdfTextBox::render()   F
last analyzed

Complexity

Conditions 60
Paths > 20000

Size

Total Lines 285
Code Lines 176

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 60
eloc 176
c 0
b 0
f 0
nc 815915008
nop 1
dl 0
loc 285
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2023 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 <https://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Report;
21
22
use function count;
23
use function hexdec;
24
use function is_array;
25
use function is_object;
26
use function ksort;
27
use function preg_match;
28
use function str_replace;
29
use function trim;
30
31
/**
32
 * Class ReportPdfTextBox
33
 */
34
class ReportPdfTextBox extends ReportBaseTextbox
35
{
36
    /**
37
     * PDF Text Box renderer
38
     *
39
     * @param PdfRenderer $renderer
40
     *
41
     * @return void
42
     */
43
    public function render($renderer): void
44
    {
45
        $newelements      = [];
46
        $lastelement      = '';
47
        $footnote_element = [];
48
        // Element counter
49
        $cE = count($this->elements);
50
        //-- collapse duplicate elements
51
        for ($i = 0; $i < $cE; $i++) {
52
            $element = $this->elements[$i];
53
            if ($element instanceof ReportBaseElement) {
54
                if ($element instanceof ReportBaseText) {
55
                    ksort($footnote_element);
56
                    foreach ($footnote_element as $links) {
57
                        $newelements[] = $links;
58
                    }
59
                    $footnote_element = [];
60
                    if (empty($lastelement)) {
61
                        $lastelement = $element;
62
                    } elseif ($element->getStyleName() === $lastelement->getStyleName()) {
63
                        // Checking if the Text has the same style
64
                        $lastelement->addText(str_replace("\n", '<br>', $element->getValue()));
65
                    } else {
66
                        $newelements[] = $lastelement;
67
                        $lastelement   = $element;
68
                    }
69
                } elseif ($element instanceof ReportPdfFootnote) {
70
                    // Check if the Footnote has been set with it’s link number
71
                    $renderer->checkFootnote($element);
72
                    // Save first the last element if any
73
                    if (!empty($lastelement)) {
74
                        $newelements[] = $lastelement;
75
                        $lastelement   = [];
76
                    }
77
                    // Save the Footnote with it’s link number as key for sorting later
78
                    $footnote_element[$element->num] = $element;
79
                } elseif (!$element instanceof ReportPdfFootnote || trim($element->getValue()) !== '') {
80
                    // Do not keep empty footnotes
81
                    if (!empty($footnote_element)) {
82
                        ksort($footnote_element);
83
                        foreach ($footnote_element as $links) {
84
                            $newelements[] = $links;
85
                        }
86
                        $footnote_element = [];
87
                    }
88
                    if (!empty($lastelement)) {
89
                        $newelements[] = $lastelement;
90
                        $lastelement   = [];
91
                    }
92
                    $newelements[] = $element;
93
                }
94
            } else {
95
                if (!empty($lastelement)) {
96
                    $newelements[] = $lastelement;
97
                    $lastelement   = [];
98
                }
99
                if (!empty($footnote_element)) {
100
                    ksort($footnote_element);
101
                    foreach ($footnote_element as $links) {
102
                        $newelements[] = $links;
103
                    }
104
                    $footnote_element = [];
105
                }
106
                $newelements[] = $element;
107
            }
108
        }
109
        if (!empty($lastelement)) {
110
            $newelements[] = $lastelement;
111
        }
112
        if (!empty($footnote_element)) {
113
            ksort($footnote_element);
114
            foreach ($footnote_element as $links) {
115
                $newelements[] = $links;
116
            }
117
        }
118
        $this->elements = $newelements;
119
        unset($footnote_element, $lastelement, $links, $newelements);
120
121
        // Used with line breaks and cell height calculation within this box
122
        $renderer->largestFontHeight = 0;
123
124
        // If current position (left)
125
        if ($this->left === ReportBaseElement::CURRENT_POSITION) {
126
            $cX = $renderer->tcpdf->GetX();
127
        } else {
128
            // For static position add margin (returns and updates X)
129
            $cX = $renderer->addMarginX($this->left);
130
        }
131
132
        // If current position (top)
133
        if ($this->top === ReportBaseElement::CURRENT_POSITION) {
134
            $cY = $renderer->tcpdf->GetY();
135
        } else {
136
            $cY = $this->top;
137
            $renderer->tcpdf->setY($cY);
138
        }
139
140
        // Check the width if set to page wide OR set by xml to larger then page width (margin)
141
        if ($this->width === 0.0 || $this->width > $renderer->getRemainingWidthPDF()) {
142
            $cW = $renderer->getRemainingWidthPDF();
143
        } else {
144
            $cW = $this->width;
145
        }
146
147
        // Save the original margins
148
        $cM = $renderer->tcpdf->getMargins();
149
        // Use cell padding to wrap the width
150
        // Temp Width with cell padding
151
        if (is_array($cM['cell'])) {
152
            $cWT = $cW - ($cM['padding_left'] + $cM['padding_right']);
153
        } else {
154
            $cWT = $cW - $cM['cell'] * 2;
155
        }
156
        // Element height (except text)
157
        $eH = 0.0;
158
        $w  = 0;
159
        // Temp Height
160
        $cHT = 0;
161
        //-- $lw is an array
162
        // 0 => last line width
163
        // 1 => 1 if text was wrapped, 0 if text did not wrap
164
        // 2 => number of LF
165
        $lw = [];
166
        // Element counter
167
        $cE = count($this->elements);
168
        //-- calculate the text box height + width
169
        for ($i = 0; $i < $cE; $i++) {
170
            if (is_object($this->elements[$i])) {
171
                $ew = $this->elements[$i]->setWrapWidth($cWT - $w, $cWT);
172
                if ($ew === $cWT) {
173
                    $w = 0;
174
                }
175
                $lw = $this->elements[$i]->getWidth($renderer);
176
                // Text is already gets the # LF
177
                $cHT += $lw[2];
178
                if ($lw[1] === 1) {
179
                    $w = $lw[0];
180
                } elseif ($lw[1] === 2) {
181
                    $w = 0;
182
                } else {
183
                    $w += $lw[0];
184
                }
185
                if ($w > $cWT) {
186
                    $w = $lw[0];
187
                }
188
                // Footnote is at the bottom of the page. No need to calculate it’s height or wrap the text!
189
                // We are changing the margins anyway!
190
                // For anything else but text (images), get the height
191
                $eH += $this->elements[$i]->getHeight($renderer);
192
            }
193
        }
194
195
        // Add up what’s the final height
196
        $cH = $this->height;
197
        // If any element exist
198
        if ($cE > 0) {
199
            // Check if this is text or some other element, like images
200
            if ($eH === 0.0) {
201
                // This is text elements. Number of LF but at least one line
202
                $cHT = ($cHT + 1) * $renderer->tcpdf->getCellHeightRatio();
203
                // Calculate the cell height with the largest font size used within this Box
204
                $cHT *= $renderer->largestFontHeight;
205
                // Add cell padding
206
                if ($this->padding) {
207
                    if (is_array($cM['cell'])) {
208
                        $cHT += $cM['padding_bottom'] + $cM['padding_top'];
209
                    } else {
210
                        $cHT += $cM['cell'] * 2;
211
                    }
212
                }
213
                if ($cH < $cHT) {
214
                    $cH = $cHT;
215
                }
216
            } elseif ($cH < $eH) {
217
                // This is any other element
218
                $cH = $eH;
219
            }
220
        }
221
        // Finally, check the last cells height
222
        if ($cH < $renderer->lastCellHeight) {
223
            $cH = $renderer->lastCellHeight;
224
        }
225
        // Add a new page if needed
226
        if ($this->pagecheck) {
227
            // Reset last cell height or Header/Footer will inherit it, in case of pagebreak
228
            $renderer->lastCellHeight = 0;
229
            if ($renderer->checkPageBreakPDF($cH)) {
230
                $cY = $renderer->tcpdf->GetY();
231
            }
232
        }
233
234
        // Setup the border and background color
235
        $cS = ''; // Class Style
236
        if ($this->border) {
237
            $cS = 'D';
238
        } // D or empty string: Draw (default)
239
        $match = [];
240
        // Fill the background
241
        if ($this->fill) {
242
            if (preg_match('/#?(..)(..)(..)/', $this->bgcolor, $match)) {
243
                $cS .= 'F'; // F: Fill the background
244
                $r  = hexdec($match[1]);
245
                $g  = hexdec($match[2]);
246
                $b  = hexdec($match[3]);
247
                $renderer->tcpdf->setFillColor($r, $g, $b);
248
            }
249
        }
250
        // Clean up a bit
251
        unset($lw, $w, $match, $cE, $eH);
252
        // Draw the border
253
        if (!empty($cS)) {
254
            if (!$renderer->tcpdf->getRTL()) {
255
                $cXM = $cX;
256
            } else {
257
                $cXM = $renderer->tcpdf->getPageWidth() - $cX - $cW;
258
            }
259
            $renderer->tcpdf->Rect($cXM, $cY, $cW, $cH, $cS);
260
        }
261
        // Add cell padding if set and if any text (element) exist
262
        if ($this->padding) {
263
            if ($cHT > 0) {
264
                if (is_array($cM['cell'])) {
265
                    $renderer->tcpdf->setY($cY + $cM['padding_top']);
266
                } else {
267
                    $renderer->tcpdf->setY($cY + $cM['cell']);
268
                }
269
            }
270
        }
271
        // Change the margins X, Width
272
        if (!$renderer->tcpdf->getRTL()) {
273
            if ($this->padding) {
274
                if (is_array($cM['cell'])) {
275
                    $renderer->tcpdf->setLeftMargin($cX + $cM['padding_left']);
276
                } else {
277
                    $renderer->tcpdf->setLeftMargin($cX + $cM['cell']);
278
                }
279
            } else {
280
                $renderer->tcpdf->setLeftMargin($cX);
281
            }
282
            $renderer->tcpdf->setRightMargin($renderer->getRemainingWidthPDF() - $cW + $cM['right']);
283
        } elseif ($this->padding) {
284
            if (is_array($cM['cell'])) {
285
                $renderer->tcpdf->setRightMargin($cX + $cM['padding_right']);
286
            } else {
287
                $renderer->tcpdf->setRightMargin($cX + $cM['cell']);
288
            }
289
            $renderer->tcpdf->setLeftMargin($renderer->getRemainingWidthPDF() - $cW + $cM['left']);
290
        } else {
291
            $renderer->tcpdf->setRightMargin($cX);
292
            $renderer->tcpdf->setLeftMargin($renderer->getRemainingWidthPDF() - $cW + $cM['left']);
293
        }
294
        // Save the current page number
295
        $cPN = $renderer->tcpdf->getPage();
296
297
        // Render the elements (write text, print picture...)
298
        foreach ($this->elements as $element) {
299
            if ($element instanceof ReportBaseElement) {
300
                $element->render($renderer);
301
            } elseif ($element === 'footnotetexts') {
302
                $renderer->footnotes();
303
            } elseif ($element === 'addpage') {
304
                $renderer->newPage();
305
            }
306
        }
307
        // Restore the margins
308
        $renderer->tcpdf->setLeftMargin($cM['left']);
309
        $renderer->tcpdf->setRightMargin($cM['right']);
310
311
        // This will be mostly used to trick the multiple images last height
312
        if ($this->reseth) {
313
            $cH = 0;
314
            // This can only happen with multiple images and with pagebreak
315
            if ($cPN !== $renderer->tcpdf->getPage()) {
316
                $renderer->tcpdf->setPage($cPN);
317
            }
318
        }
319
        // New line and some clean up
320
        if (!$this->newline) {
321
            $renderer->tcpdf->setXY($cX + $cW, $cY);
322
            $renderer->lastCellHeight = $cH;
323
        } else {
324
            // addMarginX() also updates X
325
            $renderer->addMarginX(0);
326
            $renderer->tcpdf->setY($cY + $cH);
327
            $renderer->lastCellHeight = 0;
328
        }
329
    }
330
}
331