GeoAnalysisResult   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 222
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 51
dl 0
loc 222
rs 10
c 0
b 0
f 0
wmc 22

16 Methods

Rating   Name   Duplication   Size   Complexity  
A copy() 0 7 1
A merge() 0 18 4
A description() 0 3 1
A knownPlaces() 0 6 2
A exclude() 0 6 2
A addUnknown() 0 3 1
A excludedPlaces() 0 3 1
A countExcluded() 0 5 1
A countUnknown() 0 3 1
A order() 0 3 1
A sortedKnownPlaces() 0 6 1
A maxCount() 0 3 1
A addPlace() 0 8 2
A countFound() 0 5 1
A __construct() 0 10 1
A countKnown() 0 3 1
1
<?php
2
3
/**
4
 * webtrees-lib: MyArtJaub library for webtrees
5
 *
6
 * @package MyArtJaub\Webtrees
7
 * @subpackage GeoDispersion
8
 * @author Jonathan Jaubart <[email protected]>
9
 * @copyright Copyright (c) 2021-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\Common\GeoDispersion\GeoAnalysis;
16
17
use Fisharebest\Webtrees\I18N;
18
use Illuminate\Support\Collection;
19
20
/**
21
 * Result of a geographical dispersion analysis for a category.
22
 * An order of the categories can be defined.
23
 *
24
 */
25
class GeoAnalysisResult
26
{
27
    private string $description;
28
    private int $order;
29
    private int $unknown_count;
30
    /**
31
     * @var Collection<GeoAnalysisResultItem>
32
     */
33
    private Collection $places;
34
35
    /**
36
     * Constructor for GeoAnalysisResult
37
     *
38
     * @param string $description
39
     * @param int $order
40
     * @param Collection<GeoAnalysisResultItem> $places
41
     * @param int $unknown
42
     */
43
    final public function __construct(
44
        string $description,
45
        int $order = 0,
46
        Collection $places = null,
47
        int $unknown = 0
48
    ) {
49
        $this->description = $description;
50
        $this->order = $order;
51
        $this->places = $places ?? new Collection();
52
        $this->unknown_count = $unknown;
53
    }
54
55
    /**
56
     * Get the category description
57
     *
58
     * @return string
59
     */
60
    public function description(): string
61
    {
62
        return $this->description;
63
    }
64
65
    /**
66
     * Get the category order
67
     *
68
     * @return int
69
     */
70
    public function order(): int
71
    {
72
        return $this->order;
73
    }
74
75
    /**
76
     * Add a place to the analysis result
77
     *
78
     * @param GeoAnalysisPlace $place
79
     */
80
    public function addPlace(GeoAnalysisPlace $place): void
81
    {
82
        if ($place->isKnown()) {
83
            /** @var GeoAnalysisResultItem $item */
84
            $item = $this->places->get($place->key(), new GeoAnalysisResultItem($place));
85
            $this->places->put($item->key(), $item->increment());
86
        } else {
87
            $this->addUnknown();
88
        }
89
    }
90
91
    /**
92
     * Exclude a place from the analysis result
93
     *
94
     * @param GeoAnalysisPlace $place
95
     */
96
    public function exclude(GeoAnalysisPlace $place): void
97
    {
98
        /** @var GeoAnalysisResultItem|null $item */
99
        $item = $this->places->get($place->key());
100
        if ($item !== null) {
101
            $item->place()->exclude();
102
        }
103
    }
104
105
    /**
106
     * Add an unknown place to the analysis result
107
     */
108
    public function addUnknown(): void
109
    {
110
        $this->unknown_count++;
111
    }
112
113
    /**
114
     * Take a copy of the current analysis result
115
     *
116
     * @return static
117
     */
118
    public function copy(): self
119
    {
120
        return new static(
121
            $this->description(),
122
            $this->order(),
123
            $this->places->map(fn(GeoAnalysisResultItem $item): GeoAnalysisResultItem => clone $item),
124
            $this->countUnknown()
125
        );
126
    }
127
128
    /**
129
     * Merge the current analysis result with another.
130
     * The current object is modified, not the second one.
131
     *
132
     * @param GeoAnalysisResult $other
133
     * @return $this
134
     */
135
    public function merge(GeoAnalysisResult $other): self
136
    {
137
        $this->places->each(function (GeoAnalysisResultItem $item) use ($other): void {
138
            if ($other->places->has($item->key())) {
139
                $item->place()->exclude(
140
                    $item->place()->isExcluded()
141
                    && $other->places->get($item->key())->place()->isExcluded()
142
                );
143
            }
144
        });
145
146
        $other->places->each(function (GeoAnalysisResultItem $item): void {
147
            if (!$this->places->has($item->key())) {
148
                $this->addPlace($item->place());
149
            }
150
        });
151
152
        return $this;
153
    }
154
155
    /**
156
     * Get the count of Known places
157
     *
158
     * @return int
159
     */
160
    public function countKnown(): int
161
    {
162
        return $this->places->sum(fn(GeoAnalysisResultItem $item): int => $item->count()) ?? 0;
163
    }
164
165
    /**
166
     * Get the count of Found places
167
     *
168
     * @return int
169
     */
170
    public function countFound(): int
171
    {
172
        return $this->places
173
            ->reject(fn(GeoAnalysisResultItem $item): bool => $item->place()->isExcluded())
174
            ->sum(fn(GeoAnalysisResultItem $item): int => $item->count()) ?? 0;
175
    }
176
177
    /**
178
     * Get the count of Excluded places
179
     *
180
     * @return int
181
     */
182
    public function countExcluded(): int
183
    {
184
        return $this->places
185
            ->filter(fn(GeoAnalysisResultItem $item): bool => $item->place()->isExcluded())
186
            ->sum(fn(GeoAnalysisResultItem $item): int => $item->count()) ?? 0;
187
    }
188
189
    /**
190
     * Get the count of Unknown places
191
     *
192
     * @return int
193
     */
194
    public function countUnknown(): int
195
    {
196
        return $this->unknown_count;
197
    }
198
199
    /**
200
     * Get the count of the most represented Place in the analysis result
201
     *
202
     * @return int
203
     */
204
    public function maxCount(): int
205
    {
206
        return $this->places->max(fn(GeoAnalysisResultItem $item): int => $item->count()) ?? 0;
207
    }
208
209
    /**
210
     * Get the list of Known places with their associated count
211
     *
212
     * @param bool $exclude_other
213
     * @return Collection<GeoAnalysisResultItem>
214
     */
215
    public function knownPlaces(bool $exclude_other = false): Collection
216
    {
217
        if ($exclude_other) {
218
            return $this->places->reject(fn(GeoAnalysisResultItem $item): bool => $item->place()->isExcluded());
219
        }
220
        return $this->places;
221
    }
222
223
    /**
224
     * Get the list of Known places with their associated count.
225
     * The list is sorted first by descending count, then by ascending Place name
226
     *
227
     * @param bool $exclude_other
228
     * @return Collection<GeoAnalysisResultItem>
229
     */
230
    public function sortedKnownPlaces(bool $exclude_other = false): Collection
231
    {
232
        return $this->knownPlaces($exclude_other)->sortBy([
233
            fn (GeoAnalysisResultItem $a, GeoAnalysisResultItem $b): int => $b->count() <=> $a->count(),
234
            fn (GeoAnalysisResultItem $a, GeoAnalysisResultItem $b): int =>
235
                I18N::comparator()($a->place()->place()->gedcomName(), $b->place()->place()->gedcomName())
236
        ]);
237
    }
238
239
    /**
240
     * Get the list of Excluded places
241
     *
242
     * @return Collection<GeoAnalysisResultItem>
243
     */
244
    public function excludedPlaces(): Collection
245
    {
246
        return $this->places->filter(fn(GeoAnalysisResultItem $item): bool => $item->place()->isExcluded());
247
    }
248
}
249