Test Failed
Branch master (4a3c5b)
by Greg
12:31
created

FamilyBookController::__construct()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 4
nop 0
dl 0
loc 22
rs 8.9197
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\Controller;
17
18
use Fisharebest\Webtrees\Filter;
19
use Fisharebest\Webtrees\Functions\FunctionsPrint;
20
use Fisharebest\Webtrees\I18N;
21
use Fisharebest\Webtrees\Individual;
22
use Fisharebest\Webtrees\Theme;
23
24
/**
25
 * Controller for the familybook chart
26
 */
27
class FamilyBookController extends ChartController {
28
	/** @var string Whether to show spouse details '0' or '1' */
29
	public $show_spouse;
30
31
	/** @var int Number of descendancy generations to show */
32
	public $descent;
33
34
	/** @var int Number of ascendancy generations to show */
35
	public $generations;
36
37
	/** @var int Number of descendancy generations that exist */
38
	private $dgenerations;
39
40
	/** @var int Half height of personbox */
41
	public $bhalfheight;
42
43
	/**
44
	 * Create a family-book controller
45
	 */
46
	public function __construct() {
47
		parent::__construct();
48
49
		// Extract the request parameters
50
		$this->show_spouse = Filter::get('show_spouse', '[01]', '0');
51
		$this->descent     = Filter::getInteger('descent', 0, 9, 5);
52
		$this->generations = Filter::getInteger('generations', 2, $this->tree()->getPreference('MAX_DESCENDANCY_GENERATIONS'), 2);
0 ignored issues
show
Bug introduced by
$this->tree()->getPrefer...SCENDANCY_GENERATIONS') of type string is incompatible with the type integer expected by parameter $max of Fisharebest\Webtrees\Filter::getInteger(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

52
		$this->generations = Filter::getInteger('generations', 2, /** @scrutinizer ignore-type */ $this->tree()->getPreference('MAX_DESCENDANCY_GENERATIONS'), 2);
Loading history...
53
54
		$this->bhalfheight = $this->getBoxDimensions()->height / 2;
55
		if ($this->root && $this->root->canShowName()) {
56
			$this->setPageTitle(
57
				/* I18N: %s is an individual’s name */
58
				I18N::translate('Family book of %s', $this->root->getFullName())
59
			);
60
		} else {
61
			$this->setPageTitle(I18N::translate('Family book'));
62
		}
63
		//Checks how many generations of descendency is for the person for formatting purposes
64
		$this->dgenerations = $this->maxDescendencyGenerations($this->root->getXref(), 0);
65
66
		if ($this->dgenerations < 1) {
67
			$this->dgenerations = 1;
68
		}
69
	}
70
71
	/**
72
	 * Prints descendency of passed in person
73
	 *
74
	 * @param Individual|null $person
75
	 * @param int             $generation
76
	 *
77
	 * @return int
78
	 */
79
	private function printDescendency(Individual $person = null, $generation) {
80
		if ($generation > $this->dgenerations) {
81
			return 0;
82
		}
83
84
		echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>';
85
		$numkids = 0;
86
87
		// Load children
88
		$children = [];
89
		if ($person) {
90
			// Count is position from center to left, dgenerations is number of generations
91
			if ($generation < $this->dgenerations) {
92
				// All children, from all partners
93
				foreach ($person->getSpouseFamilies() as $family) {
94
					foreach ($family->getChildren() as $child) {
95
						$children[] = $child;
96
					}
97
				}
98
			}
99
		}
100
		if ($generation < $this->dgenerations) {
101
			if (!empty($children)) {
102
				// real people
103
				echo '<table cellspacing="0" cellpadding="0" border="0" >';
104
				foreach ($children as $i => $child) {
105
					echo '<tr><td>';
106
					$kids = $this->printDescendency($child, $generation + 1);
107
					$numkids += $kids;
108
					echo '</td>';
109
					// Print the lines
110
					if (count($children) > 1) {
111
						if ($i === 0) {
112
							// Adjust for the first column on left
113
							$h = round(((($this->getBoxDimensions()->height) * $kids) + 8) / 2); // Assumes border = 1 and padding = 3
114
							//  Adjust for other vertical columns
115
							if ($kids > 1) {
116
								$h = ($kids - 1) * 4 + $h;
117
							}
118
							echo '<td class="align-bottom">',
119
							'<img id="vline_', $child->getXref(), '" src="', Theme::theme()->parameter('image-vline'), '" width="3" height="', $h - 4, '"></td>';
120
						} elseif ($i === count($children) - 1) {
121
							// Adjust for the first column on left
122
							$h = round(((($this->getBoxDimensions()->height) * $kids) + 8) / 2);
123
							// Adjust for other vertical columns
124
							if ($kids > 1) {
125
								$h = ($kids - 1) * 4 + $h;
126
							}
127
							echo '<td class="align-top">',
128
							'<img class="bvertline" width="3" id="vline_', $child->getXref(), '" src="', Theme::theme()->parameter('image-vline'), '" height="', $h - 2, '"></td>';
129
						} else {
130
							echo '<td class="align-bottomm"style="background: url(', Theme::theme()->parameter('image-vline'), ');">',
131
							'<img class="spacer"  width="3" src="', Theme::theme()->parameter('image-spacer'), '"></td>';
132
						}
133
					}
134
					echo '</tr>';
135
				}
136
				echo '</table>';
137
			} else {
138
				// Hidden/empty boxes - to preserve the layout
139
				echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>';
140
				$numkids += $this->printDescendency(null, $generation + 1);
141
				echo '</td></tr></table>';
142
			}
143
			echo '</td>';
144
			echo '<td>';
145
		}
146
147
		if ($numkids === 0) {
148
			$numkids = 1;
149
		}
150
		echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>';
151
		if ($person) {
152
			FunctionsPrint::printPedigreePerson($person);
153
			echo '</td><td>',
154
			'<img class="linef1" src="', Theme::theme()->parameter('image-hline'), '" width="8" height="3">';
155
		} else {
156
			echo '<div style="width:', $this->getBoxDimensions()->width + 19, 'px; height:', $this->getBoxDimensions()->height + 8, 'px;"></div>',
157
			'</td><td>';
158
		}
159
160
		// Print the spouse
161
		if ($generation === 1) {
162
			if ($this->show_spouse === '1') {
163
				foreach ($person->getSpouseFamilies() as $family) {
0 ignored issues
show
Bug introduced by
The method getSpouseFamilies() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

163
				foreach ($person->/** @scrutinizer ignore-call */ getSpouseFamilies() as $family) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
164
					$spouse = $family->getSpouse($person);
0 ignored issues
show
Bug introduced by
It seems like $person can also be of type null; however, parameter $person of Fisharebest\Webtrees\Family::getSpouse() does only seem to accept Fisharebest\Webtrees\Individual, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

164
					$spouse = $family->getSpouse(/** @scrutinizer ignore-type */ $person);
Loading history...
165
					echo '</td></tr><tr><td>';
166
					FunctionsPrint::printPedigreePerson($spouse);
167
					$numkids += 0.95;
168
					echo '</td><td>';
169
				}
170
			}
171
		}
172
		echo '</td></tr></table>';
173
		echo '</td></tr>';
174
		echo '</table>';
175
176
		return $numkids;
177
	}
178
179
	/**
180
	 * Prints pedigree of the person passed in
181
	 *
182
	 * @param Individual $person
183
	 * @param int        $count
184
	 */
185
	private function printPersonPedigree($person, $count) {
186
		if ($count >= $this->generations) {
187
			return;
188
		}
189
190
		$genoffset = $this->generations; // handle pedigree n generations lines
191
		//-- calculate how tall the lines should be
192
		$lh = ($this->bhalfheight) * pow(2, ($genoffset - $count - 1));
193
		//
194
		//Prints empty table columns for children w/o parents up to the max generation
195
		//This allows vertical line spacing to be consistent
196
		if (count($person->getChildFamilies()) == 0) {
197
			echo '<table cellspacing="0" cellpadding="0" border="0" >';
198
			$this->printEmptyBox();
199
200
			//-- recursively get the father’s family
201
			$this->printPersonPedigree($person, $count + 1);
202
			echo '</td><td></tr>';
203
			$this->printEmptyBox();
204
205
			//-- recursively get the mother’s family
206
			$this->printPersonPedigree($person, $count + 1);
207
			echo '</td><td></tr></table>';
208
		}
209
210
		// Empty box section done, now for regular pedigree
211
		foreach ($person->getChildFamilies() as $family) {
212
			echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-bottom">';
213
			// Determine line height for two or more spouces
214
			// And then adjust the vertical line for the root person only
215
			$famcount = 0;
216
			if ($this->show_spouse === '1') {
217
				// count number of spouses
218
				$famcount += count($person->getSpouseFamilies());
219
			}
220
			$savlh = $lh; // Save current line height
221
			if ($count == 1 && $genoffset <= $famcount) {
222
				$linefactor = 0;
223
				// genoffset of 2 needs no adjustment
224
				if ($genoffset > 2) {
225
					$tblheight = $this->getBoxDimensions()->height + 8;
226
					if ($genoffset == 3) {
227
						if ($famcount == 3) {
228
							$linefactor = $tblheight / 2;
229
						} elseif ($famcount > 3) {
230
							$linefactor = $tblheight;
231
						}
232
					}
233 View Code Duplication
					if ($genoffset == 4) {
234
						if ($famcount == 4) {
235
							$linefactor = $tblheight;
236
						} elseif ($famcount > 4) {
237
							$linefactor = ($famcount - $genoffset) * ($tblheight * 1.5);
238
						}
239
					}
240 View Code Duplication
					if ($genoffset == 5) {
241
						if ($famcount == 5) {
242
							$linefactor = 0;
243
						} elseif ($famcount > 5) {
244
							$linefactor = $tblheight * ($famcount - $genoffset);
245
						}
246
					}
247
				}
248
				$lh = (($famcount - 1) * ($this->getBoxDimensions()->height) - ($linefactor));
249
				if ($genoffset > 5) {
250
					$lh = $savlh;
251
				}
252
			}
253
			echo '<img class="line3 pvline"  src="', Theme::theme()->parameter('image-vline'), '" width="3" height="', $lh, '"></td>',
254
			'<td>',
255
			'<img class="linef2" src="', Theme::theme()->parameter('image-hline'), '" height="3"></td>',
256
			'<td>';
257
			$lh = $savlh; // restore original line height
258
			//-- print the father box
259
			FunctionsPrint::printPedigreePerson($family->getHusband());
260
			echo '</td>';
261
			if ($family->getHusband()) {
262
				echo '<td>';
263
				//-- recursively get the father’s family
264
				$this->printPersonPedigree($family->getHusband(), $count + 1);
265
				echo '</td>';
266
			} else {
267
				echo '<td>';
268
				if ($genoffset > $count) {
269
					echo '<table cellspacing="0" cellpadding="0" border="0" >';
270
					for ($i = 1; $i < (pow(2, ($genoffset) - $count) / 2); $i++) {
271
						$this->printEmptyBox();
272
						echo '</tr>';
273
					}
274
					echo '</table>';
275
				}
276
			}
277
			echo '</tr><tr>',
278
			'<td class="align-top"><img class="pvline" src="', Theme::theme()->parameter('image-vline'), '" width="3" height="', $lh, '"></td>',
279
			'<td><img class="linef3" src="', Theme::theme()->parameter('image-hline'), '" height="3"></td>',
280
			'<td>';
281
			//-- print the mother box
282
			FunctionsPrint::printPedigreePerson($family->getWife());
283
			echo '</td>';
284
			if ($family->getWife()) {
285
				echo '<td>';
286
				//-- recursively print the mother’s family
287
				$this->printPersonPedigree($family->getWife(), $count + 1);
288
				echo '</td>';
289 View Code Duplication
			} else {
290
				echo '<td>';
291
				if ($count < $genoffset - 1) {
292
					echo '<table cellspacing="0" cellpadding="0" border="0" >';
293
					for ($i = 1; $i < (pow(2, ($genoffset - 1) - $count) / 2) + 1; $i++) {
294
						$this->printEmptyBox();
295
						echo '</tr>';
296
						$this->printEmptyBox();
297
						echo '</tr>';
298
					}
299
					echo '</table>';
300
				}
301
			}
302
			echo '</tr>',
303
			'</table>';
304
			break;
305
		}
306
	}
307
308
	/**
309
	 * Calculates number of generations a person has
310
	 *
311
	 * @param string $pid
312
	 * @param int    $depth
313
	 *
314
	 * @return int
315
	 */
316
	private function maxDescendencyGenerations($pid, $depth) {
317
		if ($depth > $this->generations) {
318
			return $depth;
319
		}
320
		$person = Individual::getInstance($pid, $this->tree());
321
		if (is_null($person)) {
322
			return $depth;
323
		}
324
		$maxdc = $depth;
325
		foreach ($person->getSpouseFamilies() as $family) {
0 ignored issues
show
Bug introduced by
The method getSpouseFamilies() does not exist on Fisharebest\Webtrees\Media. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

325
		foreach ($person->/** @scrutinizer ignore-call */ getSpouseFamilies() as $family) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getSpouseFamilies() does not exist on Fisharebest\Webtrees\Source. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

325
		foreach ($person->/** @scrutinizer ignore-call */ getSpouseFamilies() as $family) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getSpouseFamilies() does not exist on Fisharebest\Webtrees\Repository. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

325
		foreach ($person->/** @scrutinizer ignore-call */ getSpouseFamilies() as $family) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getSpouseFamilies() does not exist on Fisharebest\Webtrees\GedcomRecord. It seems like you code against a sub-type of Fisharebest\Webtrees\GedcomRecord such as Fisharebest\Webtrees\Individual. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

325
		foreach ($person->/** @scrutinizer ignore-call */ getSpouseFamilies() as $family) {
Loading history...
Bug introduced by
The method getSpouseFamilies() does not exist on Fisharebest\Webtrees\Family. Did you maybe mean getSpouse()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

325
		foreach ($person->/** @scrutinizer ignore-call */ getSpouseFamilies() as $family) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getSpouseFamilies() does not exist on Fisharebest\Webtrees\Note. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

325
		foreach ($person->/** @scrutinizer ignore-call */ getSpouseFamilies() as $family) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
326 View Code Duplication
			foreach ($family->getChildren() as $child) {
327
				$dc = $this->maxDescendencyGenerations($child->getXref(), $depth + 1);
328
				if ($dc >= $this->generations) {
329
					return $dc;
330
				}
331
				if ($dc > $maxdc) {
332
					$maxdc = $dc;
333
				}
334
			}
335
		}
336
		$maxdc++;
337
		if ($maxdc == 1) {
338
			$maxdc++;
339
		}
340
341
		return $maxdc;
342
	}
343
344
	/**
345
	 * Print empty box
346
	 */
347
348
	private function printEmptyBox() {
349
		echo Theme::theme()->individualBoxEmpty();
350
	}
351
352
	/**
353
	 * Print a “Family Book” for an individual
354
	 *
355
	 * @param Individual $person
356
	 * @param int    $descent_steps
357
	 */
358
	public function printFamilyBook(Individual $person, $descent_steps) {
359
		if ($descent_steps == 0) {
360
			return;
361
		}
362
363
		$families = $person->getSpouseFamilies();
364
		if (1 || !empty($families)) {
365
			echo
366
			'<h3>',
367
			/* I18N: %s is an individual’s name */ I18N::translate('Family of %s', $person->getFullName()),
368
			'</h3>',
369
			'<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-middle">';
370
			$this->dgenerations = $this->generations;
371
			$this->printDescendency($person, 1);
372
			echo '</td><td class="align-middle">';
373
			$this->printPersonPedigree($person, 1);
374
			echo '</td></tr></table><br><br><hr class="family-break"><br><br>';
375
			foreach ($families as $family) {
376
				foreach ($family->getChildren() as $child) {
377
					$this->printFamilyBook($child, $descent_steps - 1);
378
				}
379
			}
380
		}
381
	}
382
}
383