Passed
Branch master (380e00)
by Greg
20:17
created

ReportTcpdf::newPage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * webtrees: online genealogy
4
 * Copyright (C) 2017 webtrees development team
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
 * GNU General Public License for more details.
13
 * You should have received a copy of the GNU General Public License
14
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15
 */
16
namespace Fisharebest\Webtrees\Report;
17
18
use TCPDF;
19
20
/**
21
 * WT Report PDF Class
22
 *
23
 * This class inherits from the TCPDF class and is used to generate the PDF document
24
 */
25
class ReportTcpdf extends TCPDF {
26
	/** @var ReportBaseElement[] Array of elements in the header */
27
	public $headerElements = [];
28
29
	/** @var ReportBaseElement[] Array of elements in the page header */
30
	public $pageHeaderElements = [];
31
32
	/** @var ReportBaseElement[] Array of elements in the footer */
33
	public $footerElements = [];
34
35
	/** @var ReportBaseElement[] Array of elements in the body */
36
	public $bodyElements = [];
37
38
	/** @var ReportBaseFootnote[] Array of elements in the footer notes */
39
	public $printedfootnotes = [];
40
41
	/** @var string Currently used style name */
42
	public $currentStyle;
43
44
	/** @var int The last cell height */
45
	public $lastCellHeight = 0;
46
47
	/** @var int The largest font size within a TextBox to calculate the height */
48
	public $largestFontHeight = 0;
49
50
	/** @var int The last pictures page number */
51
	public $lastpicpage = 0;
52
53
	/** @var ReportBase The current report. */
54
	public $wt_report;
55
56
	/**
57
	 * PDF Header -PDF
58
	 */
59
	public function header() {
60
		foreach ($this->headerElements as $element) {
61
			if (is_object($element)) {
62
				$element->render($this);
63
			} elseif (is_string($element) && $element == 'footnotetexts') {
64
				$this->footnotes();
65
			} elseif (is_string($element) && $element == 'addpage') {
66
				$this->newPage();
67
			}
68
		}
69
		foreach ($this->pageHeaderElements as $element) {
70
			if (is_object($element)) {
71
				$element->render($this);
72
			} elseif (is_string($element) && $element == 'footnotetexts') {
73
				$this->footnotes();
74
			} elseif (is_string($element) && $element == 'addpage') {
75
				$this->newPage();
76
			}
77
		}
78
	}
79
80
	/**
81
	 * PDF Body -PDF
82
	 */
83
	public function body() {
84
		$this->AddPage();
85
		foreach ($this->bodyElements as $key => $element) {
86
			if (is_object($element)) {
87
				$element->render($this);
88
			} elseif (is_string($element) && $element == 'footnotetexts') {
89
				$this->footnotes();
90
			} elseif (is_string($element) && $element == 'addpage') {
91
				$this->newPage();
92
			}
93
			// Delete used elements in hope to reduce 'some' memory usage
94
			unset($this->bodyElements[$key]);
95
		}
96
	}
97
98
	/**
99
	 * PDF Footnotes -PDF
100
	 */
101
	public function footnotes() {
102
		foreach ($this->printedfootnotes as $element) {
103
			if (($this->GetY() + $element->getFootnoteHeight($this)) > $this->getPageHeight()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Fisharebest\Webtrees\Report\ReportBaseFootnote as the method getFootnoteHeight() does only exist in the following sub-classes of Fisharebest\Webtrees\Report\ReportBaseFootnote: Fisharebest\Webtrees\Report\ReportHtmlFootnote, Fisharebest\Webtrees\Report\ReportPdfFootnote. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
104
				$this->AddPage();
105
			}
106
			$element->renderFootnote($this);
107
			if ($this->GetY() > $this->getPageHeight()) {
108
				$this->AddPage();
109
			}
110
		}
111
	}
112
113
	/**
114
	 * PDF Footer -PDF
115
	 */
116 View Code Duplication
	public function footer() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
117
		foreach ($this->footerElements as $element) {
118
			if (is_object($element)) {
119
				$element->render($this);
120
			} elseif (is_string($element) && $element == 'footnotetexts') {
121
				$this->footnotes();
122
			} elseif (is_string($element) && $element == 'addpage') {
123
				$this->newPage();
124
			}
125
		}
126
	}
127
128
	/**
129
	 * Add an element to the Header -PDF
130
	 *
131
	 * @param object|string $element
132
	 *
133
	 * @return int The number of the Header elements
134
	 */
135
	public function addHeader($element) {
136
		$this->headerElements[] = $element;
137
138
		return count($this->headerElements) - 1;
139
	}
140
141
	/**
142
	 * Add an element to the Page Header -PDF
143
	 *
144
	 * @param object|string $element
145
	 *
146
	 * @return int The number of the Page Header elements
147
	 */
148
	public function addPageHeader($element) {
149
		$this->pageHeaderElements[] = $element;
150
151
		return count($this->pageHeaderElements) - 1;
152
	}
153
154
	/**
155
	 * Add an element to the Body -PDF
156
	 *
157
	 * @param object|string $element
158
	 *
159
	 * @return int The number of the Body elements
160
	 */
161
	public function addBody($element) {
162
		$this->bodyElements[] = $element;
163
164
		return count($this->bodyElements) - 1;
165
	}
166
167
	/**
168
	 * Add an element to the Footer -PDF
169
	 *
170
	 * @param object|string $element
171
	 *
172
	 * @return int The number of the Footer elements
173
	 */
174
	public function addFooter($element) {
175
		$this->footerElements[] = $element;
176
177
		return count($this->footerElements) - 1;
178
	}
179
180
	/**
181
	 * Remove the header.
182
	 *
183
	 * @param $index
184
	 */
185
	public function removeHeader($index) {
186
		unset($this->headerElements[$index]);
187
	}
188
189
	/**
190
	 * Remove the page header.
191
	 *
192
	 * @param $index
193
	 */
194
	public function removePageHeader($index) {
195
		unset($this->pageHeaderElements[$index]);
196
	}
197
198
	/**
199
	 * Remove the body.
200
	 *
201
	 * @param $index
202
	 */
203
	public function removeBody($index) {
204
		unset($this->bodyElements[$index]);
205
	}
206
207
	/**
208
	 * Remove the footer.
209
	 *
210
	 * @param $index
211
	 */
212
	public function removeFooter($index) {
213
		unset($this->footerElements[$index]);
214
	}
215
216
	/**
217
	 * Clear the Header -PDF
218
	 */
219
	public function clearHeader() {
220
		unset($this->headerElements);
221
		$this->headerElements = [];
222
	}
223
224
	/**
225
	 * Clear the Page Header -PDF
226
	 */
227
	public function clearPageHeader() {
228
		unset($this->pageHeaderElements);
229
		$this->pageHeaderElements = [];
230
	}
231
232
	/**
233
	 * Set the report.
234
	 *
235
	 * @param $r
236
	 */
237
	public function setReport($r) {
238
		$this->wt_report = $r;
239
	}
240
241
	/**
242
	 * Get the currently used style name -PDF
243
	 *
244
	 * @return string
245
	 */
246
	public function getCurrentStyle() {
247
		return $this->currentStyle;
248
	}
249
250
	/**
251
	 * Setup a style for usage -PDF
252
	 *
253
	 * @param string $s Style name
254
	 */
255
	public function setCurrentStyle($s) {
256
		$this->currentStyle = $s;
257
		$style              = $this->wt_report->getStyle($s);
258
		$this->SetFont($style['font'], $style['style'], $style['size']);
259
	}
260
261
	/**
262
	 * Get the style -PDF
263
	 *
264
	 * @param string $s Style name
265
	 *
266
	 * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be string[]|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
267
	 */
268
	public function getStyle($s) {
269
		if (!isset($this->wt_report->Styles[$s])) {
270
			$s                           = $this->getCurrentStyle();
271
			$this->wt_report->Styles[$s] = $s;
272
		}
273
274
		return $this->wt_report->Styles[$s];
275
	}
276
277
	/**
278
	 * Add margin when static horizontal position is used -PDF
279
	 * RTL supported
280
	 *
281
	 * @param float $x Static position
282
	 *
283
	 * @return float
284
	 */
285
	public function addMarginX($x) {
286
		$m = $this->getMargins();
287
		if ($this->getRTL()) {
288
			$x += $m['right'];
289
		} else {
290
			$x += $m['left'];
291
		}
292
		$this->SetX($x);
293
294
		return $x;
295
	}
296
297
	/**
298
	 * Get the maximum line width to draw from the curren position -PDF
299
	 * RTL supported
300
	 *
301
	 * @return float
302
	 */
303
	public function getMaxLineWidth() {
304
		$m = $this->getMargins();
305
		if ($this->getRTL()) {
306
			return ($this->getRemainingWidth() + $m['right']);
307
		} else {
308
			return ($this->getRemainingWidth() + $m['left']);
309
		}
310
	}
311
312
	/**
313
	 * Get the height of the footnote.
314
	 *
315
	 * @return int
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
316
	 */
317
	public function getFootnotesHeight() {
318
		$h = 0;
319
		foreach ($this->printedfootnotes as $element) {
320
			$h += $element->getHeight($this);
321
		}
322
323
		return $h;
324
	}
325
326
	/**
327
	 * Returns the the current font size height -PDF
328
	 *
329
	 * @return int
330
	 */
331 View Code Duplication
	public function getCurrentStyleHeight() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
332
		if (empty($this->currentStyle)) {
333
			return $this->wt_report->defaultFontSize;
334
		}
335
		$style = $this->wt_report->getStyle($this->currentStyle);
336
337
		return $style['size'];
338
	}
339
340
	/**
341
	 * Checks the Footnote and numbers them
342
	 *
343
	 * @param object $footnote
344
	 *
345
	 * @return bool false if not numbered befor | object if already numbered
0 ignored issues
show
Documentation introduced by
Should the return type not be ReportBaseFootnote|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
346
	 */
347 View Code Duplication
	public function checkFootnote($footnote) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
348
		$ct  = count($this->printedfootnotes);
349
		$val = $footnote->getValue();
350
		$i   = 0;
351
		while ($i < $ct) {
352
			if ($this->printedfootnotes[$i]->getValue() == $val) {
353
				// If this footnote already exist then set up the numbers for this object
354
				$footnote->setNum($i + 1);
355
				$footnote->setAddlink($i + 1);
356
357
				return $this->printedfootnotes[$i];
358
			}
359
			$i++;
360
		}
361
		// If this Footnote has not been set up yet
362
		$footnote->setNum($ct + 1);
363
		$footnote->setAddlink($this->AddLink());
364
		$this->printedfootnotes[] = $footnote;
365
366
		return false;
367
	}
368
369
	/**
370
	 * Used this function instead of AddPage()
371
	 * This function will make sure that images will not be overwritten
372
	 */
373
	public function newPage() {
374
		if ($this->lastpicpage > $this->getPage()) {
375
			$this->setPage($this->lastpicpage);
376
		}
377
		$this->AddPage();
378
	}
379
380
	/**
381
	 * Add a page if needed -PDF
382
	 *
383
	 * @param int $height Cell height
384
	 *
385
	 * @return bool true in case of page break, false otherwise
386
	 */
387
	public function checkPageBreakPDF($height) {
388
		return $this->checkPageBreak($height);
389
	}
390
391
	/**
392
	 * Returns the remaining width between the current position and margins -PDF
393
	 *
394
	 * @return float Remaining width
395
	 */
396
	public function getRemainingWidthPDF() {
397
		return $this->getRemainingWidth();
398
	}
399
}
400