Passed
Branch feature/2.1-geodispersion-dev (1d61a8)
by Jonathan
61:21
created

GeoAnalysisResult   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 222
Duplicated Lines 0 %

Importance

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