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

ReportPdfTextBox   F

Complexity

Total Complexity 62

Size/Duplication

Total Lines 301
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 180
dl 0
loc 301
rs 3.44
c 0
b 0
f 0
wmc 62

1 Method

Rating   Name   Duplication   Size   Complexity  
F render() 0 292 62

How to fix   Complexity   

Complex Class

Complex classes like ReportPdfTextBox often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ReportPdfTextBox, and based on these observations, apply Extract Interface, too.

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