SosaCalculatorService::addNode()   D
last analyzed

Complexity

Conditions 11
Paths 320

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 19
nc 320
nop 2
dl 0
loc 29
rs 4.9833
c 0
b 0
f 0

How to fix   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-lib: MyArtJaub library for webtrees
5
 *
6
 * @package MyArtJaub\Webtrees
7
 * @subpackage Sosa
8
 * @author Jonathan Jaubart <[email protected]>
9
 * @copyright Copyright (c) 2009-2022, Jonathan Jaubart
10
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3
11
 */
12
13
declare(strict_types=1);
14
15
namespace MyArtJaub\Webtrees\Module\Sosa\Services;
16
17
use Fisharebest\Webtrees\Individual;
18
use Fisharebest\Webtrees\Registry;
19
use Fisharebest\Webtrees\Tree;
20
use Fisharebest\Webtrees\Contracts\UserInterface;
21
22
/**
23
 * Service for Sosa ancestors calculations
24
 */
25
class SosaCalculatorService
26
{
27
    /**
28
     * Maximium size for the temporary Sosa table
29
     * @var int TMP_SOSA_TABLE_LIMIT
30
     */
31
    private const TMP_SOSA_TABLE_LIMIT = 1000;
32
33
    /**
34
     * @var SosaRecordsService $sosa_records_service
35
     */
36
    private $sosa_records_service;
37
38
    /**
39
     * Reference user
40
     * @var UserInterface $user
41
     */
42
    private $user;
43
44
    /**
45
     * Reference tree
46
     * @var Tree $tree
47
     */
48
    private $tree;
49
50
    /**
51
     * Temporary Sosa table, used during construction
52
     * @var array<array<string,mixed>> $tmp_sosa_table
53
     */
54
    private $tmp_sosa_table;
55
56
    /**
57
     * Maximum number of generations to calculate
58
     * @var int $max_generations
59
     */
60
    private $max_generations;
61
62
    /**
63
     * Constructor for the Sosa Calculator
64
     *
65
     * @param SosaRecordsService $sosa_records_service
66
     * @param Tree $tree
67
     * @param UserInterface $user
68
     */
69
    public function __construct(SosaRecordsService $sosa_records_service, Tree $tree, UserInterface $user)
70
    {
71
        $this->sosa_records_service = $sosa_records_service;
72
        $this->tree = $tree;
73
        $this->user = $user;
74
        $this->tmp_sosa_table = array();
75
        $max_gen_setting = $tree->getUserPreference($user, 'MAJ_SOSA_MAX_GEN');
76
        $this->max_generations = is_numeric($max_gen_setting) ?
77
            (int) $max_gen_setting :
78
            $this->sosa_records_service->maxSystemGenerations();
79
    }
80
81
    /**
82
     * Compute all Sosa ancestors from the user's root individual.
83
     *
84
     * @return bool Result of the computation
85
     */
86
    public function computeAll(): bool
87
    {
88
        $root_id = $this->tree->getUserPreference($this->user, 'MAJ_SOSA_ROOT_ID');
89
        if (($indi = Registry::individualFactory()->make($root_id, $this->tree)) !== null) {
90
            $this->sosa_records_service->deleteAll($this->tree, $this->user);
91
            $this->addNode($indi, 1);
92
            $this->flushTmpSosaTable(true);
93
            return true;
94
        }
95
        return false;
96
    }
97
98
    /**
99
     * Compute all Sosa Ancestors from a specified Individual
100
     *
101
     * @param Individual $indi
102
     * @return bool
103
     */
104
    public function computeFromIndividual(Individual $indi): bool
105
    {
106
        $current_sosas = $this->sosa_records_service->sosaNumbers($this->tree, $this->user, $indi);
107
        foreach ($current_sosas->keys() as $sosa) {
108
            $this->sosa_records_service->deleteAncestorsFrom($this->tree, $this->user, $sosa);
109
            $this->addNode($indi, $sosa);
110
        }
111
        $this->flushTmpSosaTable(true);
112
        return true;
113
    }
114
115
    /**
116
     * Recursive method to add individual to the Sosa table, and flush it regularly
117
     *
118
     * @param Individual $indi Individual to add
119
     * @param int $sosa Individual's sosa
120
     */
121
    private function addNode(Individual $indi, int $sosa): void
122
    {
123
        $birth_year = $indi->getBirthDate()->gregorianYear();
124
        $birth_year_est = $birth_year === 0 ? $indi->getEstimatedBirthDate()->gregorianYear() : $birth_year;
125
126
        $death_year = $indi->getDeathDate()->gregorianYear();
127
        $death_year_est = $death_year === 0 ? $indi->getEstimatedDeathDate()->gregorianYear() : $death_year;
128
129
        $this->tmp_sosa_table[] = [
130
            'indi' => $indi->xref(),
131
            'sosa' => $sosa,
132
            'birth_year' => $birth_year === 0 ? null : $birth_year,
133
            'birth_year_est' => $birth_year_est === 0 ? null : $birth_year_est,
134
            'death_year' => $death_year === 0 ? null : $death_year,
135
            'death_year_est' => $death_year_est === 0 ? null : $death_year_est
136
        ];
137
138
        $this->flushTmpSosaTable();
139
140
        if (
141
            ($fam = $indi->childFamilies()->first()) !== null
142
            && $this->sosa_records_service->generation($sosa) < $this->max_generations
143
        ) {
144
            /** @var \Fisharebest\Webtrees\Family $fam */
145
            if (($husb = $fam->husband()) !== null) {
146
                $this->addNode($husb, 2 * $sosa);
147
            }
148
            if (($wife = $fam->wife()) !== null) {
149
                $this->addNode($wife, 2 * $sosa + 1);
150
            }
151
        }
152
    }
153
154
    /**
155
     * Write sosas in the table, if the number of items is superior to the limit, or if forced.
156
     *
157
     * @param bool $force Should the flush be forced
158
     */
159
    private function flushTmpSosaTable($force = false): void
160
    {
161
        if ($force || count($this->tmp_sosa_table) >= self::TMP_SOSA_TABLE_LIMIT) {
162
            $this->sosa_records_service->insertOrUpdate($this->tree, $this->user, $this->tmp_sosa_table);
163
            $this->tmp_sosa_table = array();
164
        }
165
    }
166
}
167