DescendancyController::printChildDescendancy()   F
last analyzed

Complexity

Conditions 11
Paths 432

Size

Total Lines 57
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 39
nc 432
nop 2
dl 0
loc 57
rs 3.9388
c 0
b 0
f 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
 * webtrees: online genealogy
4
 * Copyright (C) 2019 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\Family;
19
use Fisharebest\Webtrees\Filter;
20
use Fisharebest\Webtrees\Functions\FunctionsCharts;
21
use Fisharebest\Webtrees\Functions\FunctionsPrint;
22
use Fisharebest\Webtrees\GedcomTag;
23
use Fisharebest\Webtrees\I18N;
24
use Fisharebest\Webtrees\Individual;
25
use Fisharebest\Webtrees\Theme;
26
use Rhumsaa\Uuid\Uuid;
27
28
/**
29
 * Controller for the descendancy chart
30
 */
31
class DescendancyController extends ChartController
32
{
33
    /** @var int Show boxes for cousins */
34
    public $show_cousins;
35
36
    /** @var int Determines style of chart */
37
    public $chart_style;
38
39
    /** @var int Number of generations to display */
40
    public $generations;
41
42
    /** @var array d'Aboville numbering system <http://www.saintclair.org/numbers/numdob.html> */
43
    public $dabo_num = array();
44
45
    /** @var array d'Aboville numbering system <http://www.saintclair.org/numbers/numdob.html> */
46
    public $dabo_sex = array();
47
48
    /**
49
     * Create the descendancy controller
50
     */
51
    public function __construct()
52
    {
53
        global $WT_TREE;
54
55
        parent::__construct();
56
57
        // Extract parameters from form
58
        $this->chart_style = Filter::getInteger('chart_style', 0, 3, 0);
59
        $this->generations = Filter::getInteger('generations', 2, $WT_TREE->getPreference('MAX_DESCENDANCY_GENERATIONS'), $WT_TREE->getPreference('DEFAULT_PEDIGREE_GENERATIONS'));
60
61
        if ($this->root && $this->root->canShowName()) {
62
            $this->setPageTitle(
63
                /* I18N: %s is an individual’s name */
64
                I18N::translate('Descendants of %s', $this->root->getFullName())
65
            );
66
        } else {
67
            $this->setPageTitle(I18N::translate('Descendants'));
68
        }
69
    }
70
71
    /**
72
     * Print a child family
73
     *
74
     * @param Individual $person
75
     * @param int        $depth the descendancy depth to show
76
     * @param string     $label
77
     * @param string     $gpid
78
     */
79
    public function printChildFamily(Individual $person, $depth, $label = '1.', $gpid = '')
80
    {
81
        if ($depth < 2) {
82
            return;
83
        }
84
        foreach ($person->getSpouseFamilies() as $family) {
85
            FunctionsCharts::printSosaFamily($family->getXref(), '', -1, $label, $person->getXref(), $gpid, 0, $this->showFull());
0 ignored issues
show
Bug introduced by
$this->showFull() of type boolean is incompatible with the type integer expected by parameter $show_full of Fisharebest\Webtrees\Fun...arts::printSosaFamily(). ( Ignorable by Annotation )

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

85
            FunctionsCharts::printSosaFamily($family->getXref(), '', -1, $label, $person->getXref(), $gpid, 0, /** @scrutinizer ignore-type */ $this->showFull());
Loading history...
86
            $i = 1;
87
            foreach ($family->getChildren() as $child) {
88
                $this->printChildFamily($child, $depth - 1, $label . ($i++) . '.', $person->getXref());
89
            }
90
        }
91
    }
92
93
    /**
94
     * print a child descendancy
95
     *
96
     * @param Individual $person
97
     * @param int        $depth the descendancy depth to show
98
     */
99
    public function printChildDescendancy(Individual $person, $depth)
100
    {
101
        echo "<li>";
102
        echo "<table><tr><td>";
103
        if ($depth == $this->generations) {
104
            echo '<img src="' . Theme::theme()->parameter('image-spacer') . '" height="3" width="', Theme::theme()->parameter('chart-descendancy-indent'), "\" alt=\"\"></td><td>";
105
        } else {
106
            echo '<img src="' . Theme::theme()->parameter('image-spacer') . '" height="3" width="3">';
107
            echo '<img src="' . Theme::theme()->parameter('image-hline') . '" height="3" width="', Theme::theme()->parameter('chart-descendancy-indent') - 3, '"></td><td>';
108
        }
109
        FunctionsPrint::printPedigreePerson($person, $this->showFull());
0 ignored issues
show
Bug introduced by
$this->showFull() of type boolean is incompatible with the type integer expected by parameter $show_full of Fisharebest\Webtrees\Fun...::printPedigreePerson(). ( Ignorable by Annotation )

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

109
        FunctionsPrint::printPedigreePerson($person, /** @scrutinizer ignore-type */ $this->showFull());
Loading history...
110
        echo '</td>';
111
112
        // check if child has parents and add an arrow
113
        echo '<td></td>';
114
        echo '<td>';
115
        foreach ($person->getChildFamilies() as $cfamily) {
116
            foreach ($cfamily->getSpouses() as $parent) {
117
                FunctionsCharts::printUrlArrow('?rootid=' . $parent->getXref() . '&amp;generations=' . $this->generations . '&amp;chart_style=' . $this->chart_style . '&amp;show_full=' . $this->showFull() . '&amp;ged=' . $parent->getTree()->getNameUrl(), I18N::translate('Start at parents'), 2);
118
                // only show the arrow for one of the parents
119
                break;
120
            }
121
        }
122
123
        // d'Aboville child number
124
        $level = $this->generations - $depth;
125
        if ($this->showFull()) {
126
            echo '<br><br>&nbsp;';
127
        }
128
        echo '<span dir="ltr">'; //needed so that RTL languages will display this properly
129
        if (!isset($this->dabo_num[$level])) {
130
            $this->dabo_num[$level] = 0;
131
        }
132
        $this->dabo_num[$level]++;
133
        $this->dabo_num[$level + 1] = 0;
134
        $this->dabo_sex[$level]     = $person->getSex();
135
        for ($i = 0; $i <= $level; $i++) {
136
            $isf = $this->dabo_sex[$i];
137
            if ($isf === 'M') {
138
                $isf = '';
139
            }
140
            if ($isf === 'U') {
141
                $isf = 'NN';
142
            }
143
            echo "<span class=\"person_box" . $isf . "\">&nbsp;" . $this->dabo_num[$i] . "&nbsp;</span>";
144
            if ($i < $level) {
145
                echo '.';
146
            }
147
        }
148
        echo "</span>";
149
        echo "</td></tr>";
150
        echo "</table>";
151
        echo "</li>";
152
153
        // loop for each spouse
154
        foreach ($person->getSpouseFamilies() as $family) {
155
            $this->printFamilyDescendancy($person, $family, $depth);
156
        }
157
    }
158
159
    /**
160
     * print a family descendancy
161
     *
162
     * @param Individual $person
163
     * @param Family     $family
164
     * @param int        $depth the descendancy depth to show
165
     */
166
    private function printFamilyDescendancy(Individual $person, Family $family, $depth)
167
    {
168
        $uid = Uuid::uuid4(); // create a unique ID
169
        // print marriage info
170
        echo '<li>';
171
        echo '<img src="', Theme::theme()->parameter('image-spacer'), '" height="2" width="', Theme::theme()->parameter('chart-descendancy-indent') + 4, '">';
172
        echo '<span class="details1">';
173
        echo "<a href=\"#\" onclick=\"expand_layer('" . $uid . "'); return false;\" class=\"top\"><i id=\"" . $uid . "_img\" class=\"icon-minus\" title=\"" . I18N::translate('View this family') . "\"></i></a>";
174
        if ($family->canShow()) {
175
            foreach ($family->getFacts(WT_EVENTS_MARR) as $fact) {
176
                echo ' <a href="', $family->getHtmlUrl(), '" class="details1">', $fact->summary(), '</a>';
177
            }
178
        }
179
        echo '</span>';
180
181
        // print spouse
182
        $spouse = $family->getSpouse($person);
183
        echo '<ul id="' . $uid . '" class="generation">';
184
        echo '<li>';
185
        echo '<table><tr><td>';
186
        FunctionsPrint::printPedigreePerson($spouse, $this->showFull());
0 ignored issues
show
Bug introduced by
$this->showFull() of type boolean is incompatible with the type integer expected by parameter $show_full of Fisharebest\Webtrees\Fun...::printPedigreePerson(). ( Ignorable by Annotation )

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

186
        FunctionsPrint::printPedigreePerson($spouse, /** @scrutinizer ignore-type */ $this->showFull());
Loading history...
187
        echo '</td>';
188
189
        // check if spouse has parents and add an arrow
190
        echo '<td></td>';
191
        echo '<td>';
192
        if ($spouse) {
193
            foreach ($spouse->getChildFamilies() as $cfamily) {
194
                foreach ($cfamily->getSpouses() as $parent) {
195
                    FunctionsCharts::printUrlArrow('?rootid=' . $parent->getXref() . '&amp;generations=' . $this->generations . '&amp;chart_style=' . $this->chart_style . '&amp;show_full=' . $this->showFull() . '&amp;ged=' . $parent->getTree()->getNameUrl(), I18N::translate('Start at parents'), 2);
196
                    // only show the arrow for one of the parents
197
                    break;
198
                }
199
            }
200
        }
201
        if ($this->showFull()) {
202
            echo '<br><br>&nbsp;';
203
        }
204
        echo '</td></tr>';
205
206
        // children
207
        $children = $family->getChildren();
208
        echo '<tr><td colspan="3" class="details1" >&nbsp;&nbsp;';
209
        if ($children) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $children of type Fisharebest\Webtrees\Individual[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
210
            echo GedcomTag::getLabel('NCHI') . ': ' . count($children);
211
        } else {
212
            // Distinguish between no children (NCHI 0) and no recorded
213
            // children (no CHIL records)
214
            if (strpos($family->getGedcom(), '\n1 NCHI 0')) {
215
                echo GedcomTag::getLabel('NCHI') . ': ' . count($children);
216
            } else {
217
                echo I18N::translate('No children');
218
            }
219
        }
220
        echo '</td></tr></table>';
221
        echo '</li>';
222
        if ($depth > 1) {
223
            foreach ($children as $child) {
224
                $this->printChildDescendancy($child, $depth - 1);
225
            }
226
        }
227
        echo '</ul>';
228
        echo '</li>';
229
    }
230
231
    /**
232
     * Find all the individuals that are descended from an individual.
233
     *
234
     * @param Individual   $person
235
     * @param int          $n
236
     * @param Individual[] $array
237
     *
238
     * @return Individual[]
239
     */
240
    public function individualDescendancy(Individual $person, $n, $array)
241
    {
242
        if ($n < 1) {
243
            return $array;
244
        }
245
        $array[$person->getXref()] = $person;
246
        foreach ($person->getSpouseFamilies() as $family) {
247
            $spouse = $family->getSpouse($person);
248
            if ($spouse) {
249
                $array[$spouse->getXref()] = $spouse;
250
            }
251
            foreach ($family->getChildren() as $child) {
252
                $array = $this->individualDescendancy($child, $n - 1, $array);
253
            }
254
        }
255
256
        return $array;
257
    }
258
259
    /**
260
     * Find all the families that are descended from an individual.
261
     *
262
     * @param Individual $person
263
     * @param int        $n
264
     * @param Family[]   $array
265
     *
266
     * @return Family[]
267
     */
268
    public function familyDescendancy($person, $n, $array)
269
    {
270
        if ($n < 1) {
271
            return $array;
272
        }
273
        foreach ($person->getSpouseFamilies() as $family) {
274
            $array[$family->getXref()] = $family;
275
            foreach ($family->getChildren() as $child) {
276
                $array = $this->familyDescendancy($child, $n - 1, $array);
277
            }
278
        }
279
280
        return $array;
281
    }
282
}
283