1 | <?php |
||||
2 | |||||
3 | /** |
||||
4 | * webtrees: online genealogy |
||||
5 | * Copyright (C) 2025 webtrees development team |
||||
6 | * This program is free software: you can redistribute it and/or modify |
||||
7 | * it under the terms of the GNU General Public License as published by |
||||
8 | * the Free Software Foundation, either version 3 of the License, or |
||||
9 | * (at your option) any later version. |
||||
10 | * This program is distributed in the hope that it will be useful, |
||||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
13 | * GNU General Public License for more details. |
||||
14 | * You should have received a copy of the GNU General Public License |
||||
15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
16 | */ |
||||
17 | |||||
18 | declare(strict_types=1); |
||||
19 | |||||
20 | namespace Fisharebest\Webtrees; |
||||
21 | |||||
22 | use Fisharebest\Webtrees\Contracts\UserInterface; |
||||
0 ignored issues
–
show
|
|||||
23 | use Fisharebest\Webtrees\Elements\UnknownElement; |
||||
24 | use Fisharebest\Webtrees\Http\RequestHandlers\MessagePage; |
||||
25 | use Fisharebest\Webtrees\Module\IndividualListModule; |
||||
26 | use Fisharebest\Webtrees\Module\ModuleInterface; |
||||
27 | use Fisharebest\Webtrees\Module\ModuleListInterface; |
||||
28 | use Fisharebest\Webtrees\Services\MessageService; |
||||
0 ignored issues
–
show
The type
Fisharebest\Webtrees\Services\MessageService was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
29 | use Fisharebest\Webtrees\Services\ModuleService; |
||||
0 ignored issues
–
show
The type
Fisharebest\Webtrees\Services\ModuleService was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
30 | use Fisharebest\Webtrees\Services\UserService; |
||||
31 | use Illuminate\Database\Query\Builder; |
||||
32 | use Illuminate\Database\Query\Expression; |
||||
33 | use Illuminate\Database\Query\JoinClause; |
||||
34 | use Illuminate\Support\Collection; |
||||
35 | |||||
36 | use function abs; |
||||
37 | use function array_keys; |
||||
38 | use function array_reverse; |
||||
39 | use function array_search; |
||||
40 | use function array_shift; |
||||
41 | use function array_slice; |
||||
42 | use function arsort; |
||||
43 | use function asort; |
||||
44 | use function count; |
||||
45 | use function e; |
||||
46 | use function explode; |
||||
47 | use function floor; |
||||
48 | use function implode; |
||||
49 | use function in_array; |
||||
50 | use function preg_match; |
||||
51 | use function preg_quote; |
||||
52 | use function route; |
||||
53 | use function str_replace; |
||||
54 | use function strip_tags; |
||||
55 | use function uksort; |
||||
56 | use function view; |
||||
57 | |||||
58 | readonly class StatisticsData |
||||
59 | { |
||||
60 | public function __construct( |
||||
61 | private Tree $tree, |
||||
62 | private UserService $user_service, |
||||
63 | ) { |
||||
64 | } |
||||
65 | |||||
66 | public function averageChildrenPerFamily(): float |
||||
67 | { |
||||
68 | return (float) DB::table('families') |
||||
0 ignored issues
–
show
|
|||||
69 | ->where('f_file', '=', $this->tree->id()) |
||||
70 | ->avg('f_numchil'); |
||||
71 | } |
||||
72 | |||||
73 | public function averageLifespanDays(string $sex): int |
||||
74 | { |
||||
75 | return (int) $this->birthAndDeathQuery($sex) |
||||
76 | ->select([new Expression('AVG(' . DB::prefix('death.d_julianday2') . ' - ' . DB::prefix('birth.d_julianday1') . ') AS days')]) |
||||
0 ignored issues
–
show
'AVG(' . Fisharebest\Web...ianday1') . ') AS days' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
77 | ->value('days'); |
||||
78 | } |
||||
79 | |||||
80 | /** |
||||
81 | * @return Collection<string,int> |
||||
82 | */ |
||||
83 | public function commonGivenNames(string $sex, int $threshold, int $limit): Collection |
||||
84 | { |
||||
85 | $query = DB::table('name') |
||||
86 | ->where('n_file', '=', $this->tree->id()) |
||||
87 | ->where('n_type', '<>', '_MARNM') |
||||
88 | ->where('n_givn', '<>', Individual::PRAENOMEN_NESCIO) |
||||
0 ignored issues
–
show
The type
Fisharebest\Webtrees\Individual was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
89 | ->where(new Expression('LENGTH(n_givn)'), '>', 1); |
||||
0 ignored issues
–
show
'LENGTH(n_givn)' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
90 | |||||
91 | if ($sex !== 'ALL') { |
||||
92 | $query |
||||
93 | ->join('individuals', static function (JoinClause $join): void { |
||||
94 | $join |
||||
95 | ->on('i_file', '=', 'n_file') |
||||
96 | ->on('i_id', '=', 'n_id'); |
||||
97 | }) |
||||
98 | ->where('i_sex', '=', $sex); |
||||
99 | } |
||||
100 | |||||
101 | $rows = $query |
||||
102 | ->groupBy(['n_givn']) |
||||
103 | ->pluck(new Expression('COUNT(DISTINCT n_id)'), 'n_givn') |
||||
104 | ->map(static fn (int|string $count): int => (int) $count); |
||||
105 | |||||
106 | |||||
107 | $given_names = []; |
||||
108 | |||||
109 | foreach ($rows as $n_givn => $count) { |
||||
110 | // Split “John Thomas” into “John” and “Thomas” and count against both totals |
||||
111 | foreach (explode(' ', (string) $n_givn) as $given) { |
||||
112 | // Exclude initials and particles. |
||||
113 | if (preg_match('/^([A-Z]|[a-z]{1,3})$/', $given) !== 1) { |
||||
114 | $given_names[$given] ??= 0; |
||||
115 | $given_names[$given] += (int) $count; |
||||
116 | } |
||||
117 | } |
||||
118 | } |
||||
119 | |||||
120 | return (new Collection($given_names)) |
||||
121 | ->sortDesc() |
||||
122 | ->slice(0, $limit) |
||||
123 | ->filter(static fn (int $count): bool => $count >= $threshold); |
||||
124 | } |
||||
125 | |||||
126 | /** |
||||
127 | * @return array<array<int>> |
||||
128 | */ |
||||
129 | public function commonSurnames(int $limit, int $threshold, string $sort): array |
||||
130 | { |
||||
131 | // Use the count of base surnames. |
||||
132 | $top_surnames = DB::table('name') |
||||
133 | ->where('n_file', '=', $this->tree->id()) |
||||
134 | ->where('n_type', '<>', '_MARNM') |
||||
135 | ->whereNotIn('n_surn', ['', Individual::NOMEN_NESCIO]) |
||||
136 | ->select(['n_surn']) |
||||
137 | ->groupBy(['n_surn']) |
||||
138 | ->orderByRaw('COUNT(n_surn) DESC') |
||||
139 | ->orderBy(new Expression('COUNT(n_surn)'), 'DESC') |
||||
0 ignored issues
–
show
'COUNT(n_surn)' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
140 | ->having(new Expression('COUNT(n_surn)'), '>=', $threshold) |
||||
141 | ->take($limit) |
||||
142 | ->pluck('n_surn') |
||||
143 | ->all(); |
||||
144 | |||||
145 | $surnames = []; |
||||
146 | |||||
147 | foreach ($top_surnames as $top_surname) { |
||||
148 | $surnames[$top_surname] = DB::table('name') |
||||
149 | ->where('n_file', '=', $this->tree->id()) |
||||
150 | ->where('n_type', '<>', '_MARNM') |
||||
151 | ->where('n_surn', '=', $top_surname) |
||||
152 | ->select(['n_surn', new Expression('COUNT(n_surn) AS count')]) |
||||
153 | ->groupBy(['n_surn']) |
||||
154 | ->orderBy('n_surn') |
||||
155 | ->pluck('count', 'n_surn') |
||||
156 | ->map(static fn (string $count): int => (int) $count) |
||||
157 | ->all(); |
||||
158 | } |
||||
159 | |||||
160 | switch ($sort) { |
||||
161 | default: |
||||
162 | case 'alpha': |
||||
163 | uksort($surnames, I18N::comparator()); |
||||
0 ignored issues
–
show
The type
Fisharebest\Webtrees\I18N was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
164 | break; |
||||
165 | case 'count': |
||||
166 | break; |
||||
167 | case 'rcount': |
||||
168 | $surnames = array_reverse($surnames, true); |
||||
169 | break; |
||||
170 | } |
||||
171 | |||||
172 | return $surnames; |
||||
173 | } |
||||
174 | |||||
175 | /** |
||||
176 | * @param array<string> $events |
||||
177 | */ |
||||
178 | public function countAllEvents(array $events): int |
||||
179 | { |
||||
180 | return DB::table('dates') |
||||
181 | ->where('d_file', '=', $this->tree->id()) |
||||
182 | ->whereIn('d_fact', $events) |
||||
183 | ->count(); |
||||
184 | } |
||||
185 | |||||
186 | public function countAllPlaces(): int |
||||
187 | { |
||||
188 | return DB::table('places') |
||||
189 | ->where('p_file', '=', $this->tree->id()) |
||||
190 | ->count(); |
||||
191 | } |
||||
192 | |||||
193 | public function countAllRecords(): int |
||||
194 | { |
||||
195 | return |
||||
196 | $this->countIndividuals() + |
||||
197 | $this->countFamilies() + |
||||
198 | $this->countMedia() + |
||||
199 | $this->countNotes() + |
||||
200 | $this->countRepositories() + |
||||
201 | $this->countSources(); |
||||
202 | } |
||||
203 | |||||
204 | public function countChildren(): int |
||||
205 | { |
||||
206 | return (int) DB::table('families') |
||||
207 | ->where('f_file', '=', $this->tree->id()) |
||||
208 | ->sum('f_numchil'); |
||||
209 | } |
||||
210 | |||||
211 | /** |
||||
212 | * @return array<array{place:Place,count:int}> |
||||
213 | */ |
||||
214 | public function countCountries(int $limit): array |
||||
215 | { |
||||
216 | return DB::table('places') |
||||
217 | ->join('placelinks', static function (JoinClause $join): void { |
||||
218 | $join |
||||
219 | ->on('pl_file', '=', 'p_file') |
||||
220 | ->on('pl_p_id', '=', 'p_id'); |
||||
221 | }) |
||||
222 | ->where('p_file', '=', $this->tree->id()) |
||||
223 | ->where('p_parent_id', '=', 0) |
||||
224 | ->groupBy(['p_place']) |
||||
225 | ->orderByDesc(new Expression('COUNT(*)')) |
||||
0 ignored issues
–
show
'COUNT(*)' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
226 | ->orderBy('p_place') |
||||
227 | ->take($limit) |
||||
228 | ->select([new Expression('COUNT(*) AS total'), 'p_place AS place']) |
||||
229 | ->get() |
||||
230 | ->map(fn (object $row): array => [ |
||||
231 | 'place' => new Place($row->place, $this->tree), |
||||
232 | 'count' => (int) $row->total, |
||||
233 | ]) |
||||
234 | ->all(); |
||||
235 | } |
||||
236 | |||||
237 | private function countEventQuery(string $event, int $year1 = 0, int $year2 = 0): Builder |
||||
238 | { |
||||
239 | $query = DB::table('dates') |
||||
240 | ->where('d_file', '=', $this->tree->id()) |
||||
241 | ->where('d_fact', '=', $event) |
||||
242 | ->whereIn('d_type', ['@#DGREGORIAN@', '@#DJULIAN@']); |
||||
243 | |||||
244 | if ($year1 !== 0 && $year2 !== 0) { |
||||
245 | $query->whereBetween('d_year', [$year1, $year2]); |
||||
246 | } else { |
||||
247 | $query->where('d_year', '<>', 0); |
||||
248 | } |
||||
249 | |||||
250 | return $query; |
||||
251 | } |
||||
252 | |||||
253 | /** |
||||
254 | * @return array<string,int> |
||||
255 | */ |
||||
256 | public function countEventsByMonth(string $event, int $year1, int $year2): array |
||||
257 | { |
||||
258 | return $this->countEventQuery($event, $year1, $year2) |
||||
259 | ->groupBy(['d_month']) |
||||
260 | ->pluck(new Expression('COUNT(*)'), 'd_month') |
||||
0 ignored issues
–
show
'COUNT(*)' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
261 | ->map(static fn (string $total): int => (int) $total) |
||||
262 | ->all(); |
||||
263 | } |
||||
264 | |||||
265 | /** |
||||
266 | * @return array<object{month:string,sex:string,total:int}> |
||||
0 ignored issues
–
show
|
|||||
267 | */ |
||||
268 | public function countEventsByMonthAndSex(string $event, int $year1, int $year2): array |
||||
269 | { |
||||
270 | return $this->countEventQuery($event, $year1, $year2) |
||||
271 | ->join('individuals', static function (JoinClause $join): void { |
||||
272 | $join |
||||
273 | ->on('i_id', '=', 'd_gid') |
||||
274 | ->on('i_file', '=', 'd_file'); |
||||
275 | }) |
||||
276 | ->groupBy(['i_sex', 'd_month']) |
||||
277 | ->select(['d_month', 'i_sex', new Expression('COUNT(*) AS total')]) |
||||
0 ignored issues
–
show
'COUNT(*) AS total' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
278 | ->get() |
||||
279 | ->map(static fn (object $row): object => (object) [ |
||||
280 | 'month' => $row->d_month, |
||||
281 | 'sex' => $row->i_sex, |
||||
282 | 'total' => (int) $row->total, |
||||
283 | ]) |
||||
284 | ->all(); |
||||
285 | } |
||||
286 | |||||
287 | /** |
||||
288 | * @return array<int,array{0:string,1:int}> |
||||
289 | */ |
||||
290 | public function countEventsByCentury(string $event): array |
||||
291 | { |
||||
292 | return $this->countEventQuery($event, 0, 0) |
||||
293 | ->select([new Expression('ROUND((d_year + 49) / 100, 0) AS century'), new Expression('COUNT(*) AS total')]) |
||||
0 ignored issues
–
show
'ROUND((d_year + 49) / 100, 0) AS century' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
294 | ->groupBy(['century']) |
||||
295 | ->orderBy('century') |
||||
0 ignored issues
–
show
'century' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderBy() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
296 | ->get() |
||||
297 | ->map(fn (object $row): array => [$this->centuryName((int) $row->century), (int) $row->total]) |
||||
298 | ->all(); |
||||
299 | } |
||||
300 | |||||
301 | public function countFamilies(): int |
||||
302 | { |
||||
303 | return DB::table('families') |
||||
304 | ->where('f_file', '=', $this->tree->id()) |
||||
305 | ->count(); |
||||
306 | } |
||||
307 | |||||
308 | /** |
||||
309 | * @param array<string> $events |
||||
310 | */ |
||||
311 | public function countFamiliesWithEvents(array $events): int |
||||
312 | { |
||||
313 | return DB::table('dates') |
||||
314 | ->join('families', static function (JoinClause $join): void { |
||||
315 | $join |
||||
316 | ->on('f_id', '=', 'd_gid') |
||||
317 | ->on('f_file', '=', 'd_file'); |
||||
318 | }) |
||||
319 | ->where('d_file', '=', $this->tree->id()) |
||||
320 | ->whereIn('d_fact', $events) |
||||
321 | ->count(); |
||||
322 | } |
||||
323 | |||||
324 | public function countFamiliesWithNoChildren(): int |
||||
325 | { |
||||
326 | return DB::table('families') |
||||
327 | ->where('f_file', '=', $this->tree->id()) |
||||
328 | ->where('f_numchil', '=', 0) |
||||
329 | ->count(); |
||||
330 | } |
||||
331 | |||||
332 | public function countFamiliesWithSources(): int |
||||
333 | { |
||||
334 | return DB::table('families') |
||||
335 | ->select(['f_id']) |
||||
336 | ->distinct() |
||||
337 | ->join('link', static function (JoinClause $join): void { |
||||
338 | $join->on('f_id', '=', 'l_from') |
||||
339 | ->on('f_file', '=', 'l_file'); |
||||
340 | }) |
||||
341 | ->where('l_file', '=', $this->tree->id()) |
||||
342 | ->where('l_type', '=', 'SOUR') |
||||
343 | ->count('f_id'); |
||||
344 | } |
||||
345 | |||||
346 | /** |
||||
347 | * @return array<string,int> |
||||
348 | */ |
||||
349 | public function countFirstChildrenByMonth(int $year1, int $year2): array |
||||
350 | { |
||||
351 | return $this->countFirstChildrenQuery($year1, $year2) |
||||
352 | ->groupBy(['d_month']) |
||||
353 | ->pluck(new Expression('COUNT(*)'), 'd_month') |
||||
0 ignored issues
–
show
'COUNT(*)' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
354 | ->map(static fn (string $total): int => (int) $total) |
||||
355 | ->all(); |
||||
356 | } |
||||
357 | |||||
358 | /** |
||||
359 | * @return array<object{month:string,sex:string,total:int}> |
||||
0 ignored issues
–
show
|
|||||
360 | */ |
||||
361 | public function countFirstChildrenByMonthAndSex(int $year1, int $year2): array |
||||
362 | { |
||||
363 | return $this->countFirstChildrenQuery($year1, $year2) |
||||
364 | ->join('individuals', static function (JoinClause $join): void { |
||||
365 | $join |
||||
366 | ->on('i_file', '=', 'l_file') |
||||
367 | ->on('i_id', '=', 'l_to'); |
||||
368 | }) |
||||
369 | ->groupBy(['d_month', 'i_sex']) |
||||
370 | ->select(['d_month', 'i_sex', new Expression('COUNT(*) AS total')]) |
||||
0 ignored issues
–
show
'COUNT(*) AS total' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
371 | ->get() |
||||
372 | ->map(static fn (object $row): object => (object) [ |
||||
373 | 'month' => $row->d_month, |
||||
374 | 'sex' => $row->i_sex, |
||||
375 | 'total' => (int) $row->total, |
||||
376 | ]) |
||||
377 | ->all(); |
||||
378 | } |
||||
379 | |||||
380 | private function countFirstChildrenQuery(int $year1, int $year2): Builder |
||||
381 | { |
||||
382 | $first_child_subquery = DB::table('link') |
||||
383 | ->join('dates', static function (JoinClause $join): void { |
||||
384 | $join |
||||
385 | ->on('d_gid', '=', 'l_to') |
||||
386 | ->on('d_file', '=', 'l_file') |
||||
387 | ->where('d_julianday1', '<>', 0) |
||||
388 | ->whereIn('d_month', ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']); |
||||
389 | }) |
||||
390 | ->where('l_file', '=', $this->tree->id()) |
||||
391 | ->where('l_type', '=', 'CHIL') |
||||
392 | ->select(['l_from AS family_id', new Expression('MIN(d_julianday1) AS min_birth_jd')]) |
||||
0 ignored issues
–
show
'MIN(d_julianday1) AS min_birth_jd' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
393 | ->groupBy(['family_id']); |
||||
394 | |||||
395 | $query = DB::table('link') |
||||
396 | ->join('dates', static function (JoinClause $join): void { |
||||
397 | $join |
||||
398 | ->on('d_gid', '=', 'l_to') |
||||
399 | ->on('d_file', '=', 'l_file'); |
||||
400 | }) |
||||
401 | ->joinSub($first_child_subquery, 'subquery', static function (JoinClause $join): void { |
||||
402 | $join |
||||
403 | ->on('family_id', '=', 'l_from') |
||||
404 | ->on('min_birth_jd', '=', 'd_julianday1'); |
||||
405 | }) |
||||
406 | ->where('link.l_file', '=', $this->tree->id()) |
||||
407 | ->where('link.l_type', '=', 'CHIL'); |
||||
408 | |||||
409 | if ($year1 !== 0 && $year2 !== 0) { |
||||
410 | $query->whereBetween('d_year', [$year1, $year2]); |
||||
411 | } |
||||
412 | |||||
413 | return $query; |
||||
414 | } |
||||
415 | |||||
416 | /** |
||||
417 | * @return array<string,int> |
||||
418 | */ |
||||
419 | public function countFirstMarriagesByMonth(Tree $tree, int $year1, int $year2): array |
||||
420 | { |
||||
421 | $query = DB::table('families') |
||||
422 | ->join('dates', static function (JoinClause $join): void { |
||||
423 | $join |
||||
424 | ->on('d_gid', '=', 'f_id') |
||||
425 | ->on('d_file', '=', 'f_file') |
||||
426 | ->where('d_fact', '=', 'MARR') |
||||
427 | ->whereIn('d_month', ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']) |
||||
428 | ->where('d_julianday2', '<>', 0); |
||||
429 | }) |
||||
430 | ->where('f_file', '=', $tree->id()); |
||||
431 | |||||
432 | if ($year1 !== 0 && $year2 !== 0) { |
||||
433 | $query->whereBetween('d_year', [$year1, $year2]); |
||||
434 | } |
||||
435 | |||||
436 | $rows = $query |
||||
437 | ->orderBy('d_julianday2') |
||||
438 | ->select(['f_husb AS husb', 'f_wife AS wife', 'd_month AS month']) |
||||
439 | ->get(); |
||||
440 | |||||
441 | $months = [ |
||||
442 | 'JAN' => 0, |
||||
443 | 'FEB' => 0, |
||||
444 | 'MAR' => 0, |
||||
445 | 'APR' => 0, |
||||
446 | 'MAY' => 0, |
||||
447 | 'JUN' => 0, |
||||
448 | 'JUL' => 0, |
||||
449 | 'AUG' => 0, |
||||
450 | 'SEP' => 0, |
||||
451 | 'OCT' => 0, |
||||
452 | 'NOV' => 0, |
||||
453 | 'DEC' => 0, |
||||
454 | ]; |
||||
455 | $seen = []; |
||||
456 | |||||
457 | foreach ($rows as $row) { |
||||
458 | if (!in_array($row->husb, $seen, true) && !in_array($row->wife, $seen, true)) { |
||||
459 | $months[$row->month]++; |
||||
460 | $seen[] = $row->husb; |
||||
461 | $seen[] = $row->wife; |
||||
462 | } |
||||
463 | } |
||||
464 | |||||
465 | return $months; |
||||
466 | } |
||||
467 | |||||
468 | /** |
||||
469 | * @param array<string> $names |
||||
470 | */ |
||||
471 | public function countGivenNames(array $names): int |
||||
472 | { |
||||
473 | if ($names === []) { |
||||
474 | // Count number of distinct given names. |
||||
475 | return DB::table('name') |
||||
476 | ->where('n_file', '=', $this->tree->id()) |
||||
477 | ->distinct() |
||||
478 | ->where('n_givn', '<>', Individual::PRAENOMEN_NESCIO) |
||||
479 | ->whereNotNull('n_givn') |
||||
480 | ->count('n_givn'); |
||||
481 | } |
||||
482 | |||||
483 | // Count number of occurrences of specific given names. |
||||
484 | return DB::table('name') |
||||
485 | ->where('n_file', '=', $this->tree->id()) |
||||
486 | ->whereIn('n_givn', $names) |
||||
487 | ->count('n_givn'); |
||||
488 | } |
||||
489 | |||||
490 | public function countHits(string $page_name, string $page_parameter): int |
||||
491 | { |
||||
492 | return (int) DB::table('hit_counter') |
||||
493 | ->where('gedcom_id', '=', $this->tree->id()) |
||||
494 | ->where('page_name', '=', $page_name) |
||||
495 | ->where('page_parameter', '=', $page_parameter) |
||||
496 | ->sum('page_count'); |
||||
497 | } |
||||
498 | |||||
499 | public function countIndividuals(): int |
||||
500 | { |
||||
501 | return DB::table('individuals') |
||||
502 | ->where('i_file', '=', $this->tree->id()) |
||||
503 | ->count(); |
||||
504 | } |
||||
505 | |||||
506 | public function countIndividualsBySex(string $sex): int |
||||
507 | { |
||||
508 | return DB::table('individuals') |
||||
509 | ->where('i_file', '=', $this->tree->id()) |
||||
510 | ->where('i_sex', '=', $sex) |
||||
511 | ->count(); |
||||
512 | } |
||||
513 | |||||
514 | public function countIndividualsDeceased(): int |
||||
515 | { |
||||
516 | return DB::table('individuals') |
||||
517 | ->where('i_file', '=', $this->tree->id()) |
||||
518 | ->where(static function (Builder $query): void { |
||||
519 | foreach (Gedcom::DEATH_EVENTS as $death_event) { |
||||
520 | $query->orWhere('i_gedcom', 'LIKE', "%\n1 " . $death_event . '%'); |
||||
521 | } |
||||
522 | }) |
||||
523 | ->count(); |
||||
524 | } |
||||
525 | |||||
526 | public function countIndividualsLiving(): int |
||||
527 | { |
||||
528 | $query = DB::table('individuals') |
||||
529 | ->where('i_file', '=', $this->tree->id()); |
||||
530 | |||||
531 | foreach (Gedcom::DEATH_EVENTS as $death_event) { |
||||
532 | $query->where('i_gedcom', 'NOT LIKE', "%\n1 " . $death_event . '%'); |
||||
533 | } |
||||
534 | |||||
535 | return $query->count(); |
||||
536 | } |
||||
537 | |||||
538 | /** |
||||
539 | * @param array<string> $events |
||||
540 | */ |
||||
541 | public function countIndividualsWithEvents(array $events): int |
||||
542 | { |
||||
543 | return DB::table('dates') |
||||
544 | ->join('individuals', static function (JoinClause $join): void { |
||||
545 | $join |
||||
546 | ->on('i_id', '=', 'd_gid') |
||||
547 | ->on('i_file', '=', 'd_file'); |
||||
548 | }) |
||||
549 | ->where('d_file', '=', $this->tree->id()) |
||||
550 | ->whereIn('d_fact', $events) |
||||
551 | ->count(); |
||||
552 | } |
||||
553 | |||||
554 | public function countIndividualsWithSources(): int |
||||
555 | { |
||||
556 | return DB::table('individuals') |
||||
557 | ->select(['i_id']) |
||||
558 | ->distinct() |
||||
559 | ->join('link', static function (JoinClause $join): void { |
||||
560 | $join->on('i_id', '=', 'l_from') |
||||
561 | ->on('i_file', '=', 'l_file'); |
||||
562 | }) |
||||
563 | ->where('l_file', '=', $this->tree->id()) |
||||
564 | ->where('l_type', '=', 'SOUR') |
||||
565 | ->count('i_id'); |
||||
566 | } |
||||
567 | |||||
568 | public function countMarriedFemales(): int |
||||
569 | { |
||||
570 | return DB::table('families') |
||||
571 | ->where('f_file', '=', $this->tree->id()) |
||||
572 | ->where('f_gedcom', 'LIKE', "%\n1 MARR%") |
||||
573 | ->distinct() |
||||
574 | ->count('f_wife'); |
||||
575 | } |
||||
576 | |||||
577 | public function countMarriedMales(): int |
||||
578 | { |
||||
579 | return DB::table('families') |
||||
580 | ->where('f_file', '=', $this->tree->id()) |
||||
581 | ->where('f_gedcom', 'LIKE', "%\n1 MARR%") |
||||
582 | ->distinct() |
||||
583 | ->count('f_husb'); |
||||
584 | } |
||||
585 | |||||
586 | public function countMedia(string $type = 'all'): int |
||||
587 | { |
||||
588 | $query = DB::table('media_file') |
||||
589 | ->where('m_file', '=', $this->tree->id()); |
||||
590 | |||||
591 | if ($type !== 'all') { |
||||
592 | $query->where('source_media_type', '=', $type); |
||||
593 | } |
||||
594 | |||||
595 | return $query->count(); |
||||
596 | } |
||||
597 | |||||
598 | /** |
||||
599 | * @return array<array{0:string,1:int}> |
||||
600 | */ |
||||
601 | public function countMediaByType(): array |
||||
602 | { |
||||
603 | $element = Registry::elementFactory()->make('OBJE:FILE:FORM:TYPE'); |
||||
604 | $values = $element->values(); |
||||
605 | |||||
606 | return DB::table('media_file') |
||||
607 | ->where('m_file', '=', $this->tree->id()) |
||||
608 | ->groupBy('source_media_type') |
||||
609 | ->select([new Expression('COUNT(*) AS total'), 'source_media_type']) |
||||
0 ignored issues
–
show
'COUNT(*) AS total' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
610 | ->get() |
||||
611 | ->map(static fn (object $row): array => [ |
||||
612 | $values[$element->canonical($row->source_media_type)] ?? I18N::translate('Other'), |
||||
613 | (int) $row->total, |
||||
614 | ]) |
||||
615 | ->all(); |
||||
616 | } |
||||
617 | |||||
618 | public function countNotes(): int |
||||
619 | { |
||||
620 | return DB::table('other') |
||||
621 | ->where('o_file', '=', $this->tree->id()) |
||||
622 | ->where('o_type', '=', 'NOTE') |
||||
623 | ->count(); |
||||
624 | } |
||||
625 | |||||
626 | /** |
||||
627 | * @param array<string> $events |
||||
628 | */ |
||||
629 | public function countOtherEvents(array $events): int |
||||
630 | { |
||||
631 | return DB::table('dates') |
||||
632 | ->where('d_file', '=', $this->tree->id()) |
||||
633 | ->whereNotIn('d_fact', $events) |
||||
634 | ->count(); |
||||
635 | } |
||||
636 | |||||
637 | /** |
||||
638 | * @param array<string> $rows |
||||
639 | * |
||||
640 | * @return array<array{place:Place,count:int}> |
||||
641 | */ |
||||
642 | private function countPlaces(array $rows, string $event, int $limit): array |
||||
643 | { |
||||
644 | $places = []; |
||||
645 | |||||
646 | foreach ($rows as $gedcom) { |
||||
647 | if (preg_match('/\n1 ' . $event . '(?:\n[2-9].*)*\n2 PLAC (.+)/', $gedcom, $match) === 1) { |
||||
648 | $places[$match[1]] ??= 0; |
||||
649 | $places[$match[1]]++; |
||||
650 | } |
||||
651 | } |
||||
652 | |||||
653 | arsort($places); |
||||
654 | |||||
655 | $records = []; |
||||
656 | |||||
657 | foreach (array_slice($places, 0, $limit) as $place => $count) { |
||||
658 | $records[] = [ |
||||
659 | 'place' => new Place((string) $place, $this->tree), |
||||
660 | 'count' => $count, |
||||
661 | ]; |
||||
662 | } |
||||
663 | |||||
664 | return $records; |
||||
665 | } |
||||
666 | |||||
667 | /** |
||||
668 | * @return array<array{place:Place,count:int}> |
||||
669 | */ |
||||
670 | public function countPlacesForFamilies(string $event, int $limit): array |
||||
671 | { |
||||
672 | $rows = DB::table('families') |
||||
673 | ->where('f_file', '=', $this->tree->id()) |
||||
674 | ->where('f_gedcom', 'LIKE', "%\n2 PLAC %") |
||||
675 | ->pluck('f_gedcom') |
||||
676 | ->all(); |
||||
677 | |||||
678 | return $this->countPlaces($rows, $event, $limit); |
||||
679 | } |
||||
680 | |||||
681 | /** |
||||
682 | * @return array<array{place:Place,count:int}> |
||||
683 | */ |
||||
684 | public function countPlacesForIndividuals(string $event, int $limit): array |
||||
685 | { |
||||
686 | $rows = DB::table('individuals') |
||||
687 | ->where('i_file', '=', $this->tree->id()) |
||||
688 | ->where('i_gedcom', 'LIKE', "%\n2 PLAC %") |
||||
689 | ->pluck('i_gedcom') |
||||
690 | ->all(); |
||||
691 | |||||
692 | return $this->countPlaces($rows, $event, $limit); |
||||
693 | } |
||||
694 | |||||
695 | public function countRepositories(): int |
||||
696 | { |
||||
697 | return DB::table('other') |
||||
698 | ->where('o_file', '=', $this->tree->id()) |
||||
699 | ->where('o_type', '=', 'REPO') |
||||
700 | ->count(); |
||||
701 | } |
||||
702 | |||||
703 | public function countSources(): int |
||||
704 | { |
||||
705 | return DB::table('sources') |
||||
706 | ->where('s_file', '=', $this->tree->id()) |
||||
707 | ->count(); |
||||
708 | } |
||||
709 | |||||
710 | /** |
||||
711 | * @param array<string> $names |
||||
712 | */ |
||||
713 | public function countSurnames(array $names): int |
||||
714 | { |
||||
715 | if ($names === []) { |
||||
716 | // Count number of distinct surnames |
||||
717 | return DB::table('name') |
||||
718 | ->where('n_file', '=', $this->tree->id())->distinct() |
||||
719 | ->whereNotNull('n_surn') |
||||
720 | ->count('n_surn'); |
||||
721 | } |
||||
722 | |||||
723 | // Count number of occurrences of specific surnames. |
||||
724 | return DB::table('name') |
||||
725 | ->where('n_file', '=', $this->tree->id()) |
||||
726 | ->whereIn('n_surn', $names) |
||||
727 | ->count('n_surn'); |
||||
728 | } |
||||
729 | |||||
730 | public function countTreeFavorites(): int |
||||
731 | { |
||||
732 | return DB::table('favorite') |
||||
733 | ->where('gedcom_id', '=', $this->tree->id()) |
||||
734 | ->count(); |
||||
735 | } |
||||
736 | |||||
737 | public function countTreeNews(): int |
||||
738 | { |
||||
739 | return DB::table('news') |
||||
740 | ->where('gedcom_id', '=', $this->tree->id()) |
||||
741 | ->count(); |
||||
742 | } |
||||
743 | |||||
744 | public function countUserfavorites(): int |
||||
745 | { |
||||
746 | return DB::table('favorite') |
||||
747 | ->where('user_id', '=', Auth::id()) |
||||
0 ignored issues
–
show
|
|||||
748 | ->count(); |
||||
749 | } |
||||
750 | |||||
751 | public function countUserJournal(): int |
||||
752 | { |
||||
753 | return DB::table('news') |
||||
754 | ->where('user_id', '=', Auth::id()) |
||||
755 | ->count(); |
||||
756 | } |
||||
757 | |||||
758 | public function countUserMessages(): int |
||||
759 | { |
||||
760 | return DB::table('message') |
||||
761 | ->where('user_id', '=', Auth::id()) |
||||
762 | ->count(); |
||||
763 | } |
||||
764 | |||||
765 | /** |
||||
766 | * @return array<int,object{family:Family,children:int}> |
||||
0 ignored issues
–
show
|
|||||
767 | */ |
||||
768 | public function familiesWithTheMostChildren(int $limit): array |
||||
769 | { |
||||
770 | return DB::table('families') |
||||
771 | ->where('f_file', '=', $this->tree->id()) |
||||
772 | ->orderByDesc('f_numchil') |
||||
773 | ->limit($limit) |
||||
774 | ->get() |
||||
775 | ->map(fn (object $row): object => (object) [ |
||||
776 | 'family' => Registry::familyFactory()->make($row->f_id, $this->tree, $row->f_gedcom), |
||||
777 | 'children' => (int) $row->f_numchil, |
||||
778 | ]) |
||||
779 | ->all(); |
||||
780 | } |
||||
781 | |||||
782 | /** |
||||
783 | * @param array<string> $events |
||||
784 | * |
||||
785 | * @return object{id:string,year:int,fact:string,type:string}|null |
||||
786 | */ |
||||
787 | private function firstEvent(array $events, bool $ascending): object|null |
||||
788 | { |
||||
789 | if ($events === []) { |
||||
790 | $events = [ |
||||
791 | ...Gedcom::BIRTH_EVENTS, |
||||
792 | ...Gedcom::DEATH_EVENTS, |
||||
793 | ...Gedcom::MARRIAGE_EVENTS, |
||||
794 | ...Gedcom::DIVORCE_EVENTS, |
||||
795 | ]; |
||||
796 | } |
||||
797 | |||||
798 | return DB::table('dates') |
||||
799 | ->select(['d_gid as id', 'd_year as year', 'd_fact AS fact', 'd_type AS type']) |
||||
800 | ->where('d_file', '=', $this->tree->id()) |
||||
801 | ->whereIn('d_fact', $events) |
||||
802 | ->where('d_julianday1', '<>', 0) |
||||
803 | ->orderBy('d_julianday1', $ascending ? 'ASC' : 'DESC') |
||||
804 | ->limit(1) |
||||
805 | ->get() |
||||
806 | ->map(static fn (object $row): object => (object) [ |
||||
807 | 'id' => $row->id, |
||||
808 | 'year' => (int) $row->year, |
||||
809 | 'fact' => $row->fact, |
||||
810 | 'type' => $row->type, |
||||
811 | ]) |
||||
812 | ->first(); |
||||
813 | } |
||||
814 | |||||
815 | /** |
||||
816 | * @param array<string> $events |
||||
817 | */ |
||||
818 | public function firstEventName(array $events, bool $ascending): string |
||||
819 | { |
||||
820 | $row = $this->firstEvent($events, $ascending); |
||||
821 | |||||
822 | if ($row !== null) { |
||||
823 | $record = Registry::gedcomRecordFactory()->make($row->id, $this->tree); |
||||
824 | |||||
825 | if ($record instanceof GedcomRecord) { |
||||
0 ignored issues
–
show
The type
Fisharebest\Webtrees\GedcomRecord was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
826 | return '<a href="' . e($record->url()) . '">' . $record->fullName() . '</a>'; |
||||
827 | } |
||||
828 | } |
||||
829 | |||||
830 | return ''; |
||||
831 | } |
||||
832 | |||||
833 | /** |
||||
834 | * @param array<string> $events |
||||
835 | */ |
||||
836 | public function firstEventPlace(array $events, bool $ascending): string |
||||
837 | { |
||||
838 | $row = $this->firstEvent($events, $ascending); |
||||
839 | |||||
840 | if ($row !== null) { |
||||
841 | $record = Registry::gedcomRecordFactory()->make($row->id, $this->tree); |
||||
842 | $fact = null; |
||||
843 | |||||
844 | if ($record instanceof GedcomRecord) { |
||||
845 | $fact = $record->facts([$row->fact])->first(); |
||||
846 | } |
||||
847 | |||||
848 | if ($fact instanceof Fact) { |
||||
849 | return $fact->place()->shortName(); |
||||
850 | } |
||||
851 | } |
||||
852 | |||||
853 | return I18N::translate('Private'); |
||||
854 | } |
||||
855 | |||||
856 | /** |
||||
857 | * @param array<string> $events |
||||
858 | */ |
||||
859 | public function firstEventRecord(array $events, bool $ascending): string |
||||
860 | { |
||||
861 | $row = $this->firstEvent($events, $ascending); |
||||
862 | $result = I18N::translate('This information is not available.'); |
||||
863 | |||||
864 | if ($row !== null) { |
||||
865 | $record = Registry::gedcomRecordFactory()->make($row->id, $this->tree); |
||||
866 | |||||
867 | if ($record instanceof GedcomRecord && $record->canShow()) { |
||||
868 | $result = $record->formatList(); |
||||
869 | } else { |
||||
870 | $result = I18N::translate('This information is private and cannot be shown.'); |
||||
871 | } |
||||
872 | } |
||||
873 | |||||
874 | return $result; |
||||
875 | } |
||||
876 | |||||
877 | /** |
||||
878 | * @param array<string> $events |
||||
879 | */ |
||||
880 | public function firstEventType(array $events, bool $ascending): string |
||||
881 | { |
||||
882 | $row = $this->firstEvent($events, $ascending); |
||||
883 | |||||
884 | if ($row === null) { |
||||
885 | return ''; |
||||
886 | } |
||||
887 | |||||
888 | foreach ([Individual::RECORD_TYPE, Family::RECORD_TYPE] as $record_type) { |
||||
0 ignored issues
–
show
The type
Fisharebest\Webtrees\Family was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
889 | $element = Registry::elementFactory()->make($record_type . ':' . $row->fact); |
||||
890 | |||||
891 | if (!$element instanceof UnknownElement) { |
||||
892 | return $element->label(); |
||||
893 | } |
||||
894 | } |
||||
895 | |||||
896 | return $row->fact; |
||||
897 | } |
||||
898 | |||||
899 | /** |
||||
900 | * @param array<string> $events |
||||
901 | */ |
||||
902 | public function firstEventYear(array $events, bool $ascending): string |
||||
903 | { |
||||
904 | $row = $this->firstEvent($events, $ascending); |
||||
905 | |||||
906 | if ($row === null) { |
||||
907 | return '-'; |
||||
908 | } |
||||
909 | |||||
910 | if ($row->year < 0) { |
||||
911 | $date = new Date($row->type . ' ' . abs($row->year) . ' B.C.'); |
||||
912 | } else { |
||||
913 | $date = new Date($row->type . ' ' . $row->year); |
||||
914 | } |
||||
915 | |||||
916 | return $date->display(); |
||||
917 | } |
||||
918 | |||||
919 | public function isUserLoggedIn(int|null $user_id): bool |
||||
920 | { |
||||
921 | return $user_id !== null && DB::table('session') |
||||
922 | ->where('user_id', '=', $user_id) |
||||
923 | ->exists(); |
||||
924 | } |
||||
925 | |||||
926 | public function latestUserId(): int|null |
||||
927 | { |
||||
928 | $user_id = DB::table('user') |
||||
929 | ->select(['user.user_id']) |
||||
930 | ->leftJoin('user_setting', 'user.user_id', '=', 'user_setting.user_id') |
||||
931 | ->where('setting_name', '=', UserInterface::PREF_TIMESTAMP_REGISTERED) |
||||
932 | ->orderByDesc('setting_value') |
||||
933 | ->value('user_id'); |
||||
934 | |||||
935 | if ($user_id === null) { |
||||
936 | return null; |
||||
937 | } |
||||
938 | |||||
939 | return (int) $user_id; |
||||
940 | } |
||||
941 | |||||
942 | /** |
||||
943 | * @return array<object{family:Family,child1:Individual,child2:Individual,age:string}> |
||||
0 ignored issues
–
show
|
|||||
944 | */ |
||||
945 | public function maximumAgeBetweenSiblings(int $limit): array |
||||
946 | { |
||||
947 | return DB::table('link AS link1') |
||||
948 | ->join('link AS link2', static function (JoinClause $join): void { |
||||
949 | $join |
||||
950 | ->on('link2.l_from', '=', 'link1.l_from') |
||||
951 | ->on('link2.l_type', '=', 'link1.l_type') |
||||
952 | ->on('link2.l_file', '=', 'link1.l_file'); |
||||
953 | }) |
||||
954 | ->join('dates AS child1', static function (JoinClause $join): void { |
||||
955 | $join |
||||
956 | ->on('child1.d_gid', '=', 'link1.l_to') |
||||
957 | ->on('child1.d_file', '=', 'link1.l_file') |
||||
958 | ->where('child1.d_fact', '=', 'BIRT') |
||||
959 | ->where('child1.d_julianday1', '<>', 0); |
||||
960 | }) |
||||
961 | ->join('dates AS child2', static function (JoinClause $join): void { |
||||
962 | $join |
||||
963 | ->on('child2.d_gid', '=', 'link2.l_to') |
||||
964 | ->on('child2.d_file', '=', 'link2.l_file') |
||||
965 | ->where('child2.d_fact', '=', 'BIRT') |
||||
966 | ->whereColumn('child2.d_julianday2', '>', 'child1.d_julianday1'); |
||||
967 | }) |
||||
968 | ->where('link1.l_type', '=', 'CHIL') |
||||
969 | ->where('link1.l_file', '=', $this->tree->id()) |
||||
970 | ->distinct() |
||||
971 | ->select(['link1.l_from AS family', 'link1.l_to AS child1', 'link2.l_to AS child2', new Expression(DB::prefix('child2.d_julianday2') . ' - ' . DB::prefix('child1.d_julianday1') . ' AS age')]) |
||||
0 ignored issues
–
show
Fisharebest\Webtrees\DB:...ulianday1') . ' AS age' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
972 | ->orderBy('age', 'DESC') |
||||
973 | ->take($limit) |
||||
974 | ->get() |
||||
975 | ->map(fn (object $row): object => (object) [ |
||||
976 | 'family' => Registry::familyFactory()->make($row->family, $this->tree), |
||||
977 | 'child1' => Registry::individualFactory()->make($row->child1, $this->tree), |
||||
978 | 'child2' => Registry::individualFactory()->make($row->child2, $this->tree), |
||||
979 | 'age' => $this->calculateAge((int) $row->age), |
||||
980 | ]) |
||||
981 | ->filter(static fn (object $row): bool => $row->family !== null) |
||||
982 | ->filter(static fn (object $row): bool => $row->child1 !== null) |
||||
983 | ->filter(static fn (object $row): bool => $row->child2 !== null) |
||||
984 | ->all(); |
||||
985 | } |
||||
986 | |||||
987 | /** |
||||
988 | * @return Collection<int,Individual> |
||||
989 | */ |
||||
990 | public function topTenOldestAliveQuery(string $sex, int $limit): Collection |
||||
991 | { |
||||
992 | $query = DB::table('dates') |
||||
993 | ->join('individuals', static function (JoinClause $join): void { |
||||
994 | $join |
||||
995 | ->on('i_id', '=', 'd_gid') |
||||
996 | ->on('i_file', '=', 'd_file'); |
||||
997 | }) |
||||
998 | ->where('d_file', '=', $this->tree->id()) |
||||
999 | ->where('d_julianday1', '<>', 0) |
||||
1000 | ->where('d_fact', '=', 'BIRT') |
||||
1001 | ->where('i_gedcom', 'NOT LIKE', "%\n1 DEAT%") |
||||
1002 | ->where('i_gedcom', 'NOT LIKE', "%\n1 BURI%") |
||||
1003 | ->where('i_gedcom', 'NOT LIKE', "%\n1 CREM%"); |
||||
1004 | |||||
1005 | if ($sex === 'F' || $sex === 'M' || $sex === 'U' || $sex === 'X') { |
||||
1006 | $query->where('i_sex', '=', $sex); |
||||
1007 | } |
||||
1008 | |||||
1009 | return $query |
||||
1010 | ->groupBy(['i_id', 'i_file']) |
||||
1011 | ->orderBy(new Expression('MIN(d_julianday1)')) |
||||
0 ignored issues
–
show
'MIN(d_julianday1)' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1012 | ->select(['individuals.*']) |
||||
1013 | ->take($limit) |
||||
1014 | ->get() |
||||
1015 | ->map(Registry::individualFactory()->mapper($this->tree)) |
||||
1016 | ->filter(GedcomRecord::accessFilter()); |
||||
1017 | } |
||||
1018 | |||||
1019 | public function commonSurnamesQuery(string $type, bool $totals, int $threshold, int $limit, string $sort): string |
||||
1020 | { |
||||
1021 | $surnames = $this->commonSurnames($limit, $threshold, $sort); |
||||
1022 | |||||
1023 | // find a module providing individual lists |
||||
1024 | $module = Registry::container()->get(ModuleService::class) |
||||
1025 | ->findByComponent(ModuleListInterface::class, $this->tree, Auth::user()) |
||||
1026 | ->first(static fn (ModuleInterface $module): bool => $module instanceof IndividualListModule); |
||||
1027 | |||||
1028 | if ($type === 'list') { |
||||
1029 | return view('lists/surnames-bullet-list', [ |
||||
1030 | 'surnames' => $surnames, |
||||
1031 | 'module' => $module, |
||||
1032 | 'totals' => $totals, |
||||
1033 | 'tree' => $this->tree, |
||||
1034 | ]); |
||||
1035 | } |
||||
1036 | |||||
1037 | return view('lists/surnames-compact-list', [ |
||||
1038 | 'surnames' => $surnames, |
||||
1039 | 'module' => $module, |
||||
1040 | 'totals' => $totals, |
||||
1041 | 'tree' => $this->tree, |
||||
1042 | ]); |
||||
1043 | } |
||||
1044 | |||||
1045 | /** |
||||
1046 | * @return array<object{age:float,century:int,sex:string}> |
||||
0 ignored issues
–
show
|
|||||
1047 | */ |
||||
1048 | public function statsAge(): array |
||||
1049 | { |
||||
1050 | return DB::table('individuals') |
||||
1051 | ->select([ |
||||
1052 | new Expression('AVG(' . DB::prefix('death.d_julianday2') . ' - ' . DB::prefix('birth.d_julianday1') . ') / 365.25 AS age'), |
||||
0 ignored issues
–
show
'AVG(' . Fisharebest\Web...) . ') / 365.25 AS age' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1053 | new Expression('ROUND((' . DB::prefix('death.d_year') . ' + 49) / 100, 0) AS century'), |
||||
1054 | 'i_sex AS sex' |
||||
1055 | ]) |
||||
1056 | ->join('dates AS birth', static function (JoinClause $join): void { |
||||
1057 | $join |
||||
1058 | ->on('birth.d_file', '=', 'i_file') |
||||
1059 | ->on('birth.d_gid', '=', 'i_id'); |
||||
1060 | }) |
||||
1061 | ->join('dates AS death', static function (JoinClause $join): void { |
||||
1062 | $join |
||||
1063 | ->on('death.d_file', '=', 'i_file') |
||||
1064 | ->on('death.d_gid', '=', 'i_id'); |
||||
1065 | }) |
||||
1066 | ->where('i_file', '=', $this->tree->id()) |
||||
1067 | ->where('birth.d_fact', '=', 'BIRT') |
||||
1068 | ->where('death.d_fact', '=', 'DEAT') |
||||
1069 | ->whereIn('birth.d_type', ['@#DGREGORIAN@', '@#DJULIAN@']) |
||||
1070 | ->whereIn('death.d_type', ['@#DGREGORIAN@', '@#DJULIAN@']) |
||||
1071 | ->whereColumn('death.d_julianday1', '>=', 'birth.d_julianday2') |
||||
1072 | ->where('birth.d_julianday2', '<>', 0) |
||||
1073 | ->groupBy(['century', 'sex']) |
||||
1074 | ->orderBy('century') |
||||
1075 | ->orderBy('sex') |
||||
1076 | ->get() |
||||
1077 | ->map(static fn (object $row): object => (object) [ |
||||
1078 | 'age' => (float) $row->age, |
||||
1079 | 'century' => (int) $row->century, |
||||
1080 | 'sex' => $row->sex, |
||||
1081 | ]) |
||||
1082 | ->all(); |
||||
1083 | } |
||||
1084 | |||||
1085 | /** |
||||
1086 | * General query on ages. |
||||
1087 | * |
||||
1088 | * @return array<object{days:int}> |
||||
0 ignored issues
–
show
|
|||||
1089 | */ |
||||
1090 | public function statsAgeQuery(string $sex, int $year1, int $year2): array |
||||
1091 | { |
||||
1092 | $query = $this->birthAndDeathQuery($sex); |
||||
1093 | |||||
1094 | if ($year1 !== 0 && $year2 !== 0) { |
||||
1095 | $query |
||||
1096 | ->whereIn('birth.d_type', ['@#DGREGORIAN@', '@#DJULIAN@']) |
||||
1097 | ->whereIn('death.d_type', ['@#DGREGORIAN@', '@#DJULIAN@']) |
||||
1098 | ->whereBetween('death.d_year', [$year1, $year2]); |
||||
1099 | } |
||||
1100 | |||||
1101 | return $query |
||||
1102 | ->select([new Expression(DB::prefix('death.d_julianday2') . ' - ' . DB::prefix('birth.d_julianday1') . ' AS days')]) |
||||
0 ignored issues
–
show
Fisharebest\Webtrees\DB:...lianday1') . ' AS days' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1103 | ->orderBy('days', 'desc') |
||||
0 ignored issues
–
show
'days' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderBy() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1104 | ->get() |
||||
1105 | ->map(static fn (object $row): object => (object) ['days' => (int) $row->days]) |
||||
1106 | ->all(); |
||||
1107 | } |
||||
1108 | |||||
1109 | private function birthAndDeathQuery(string $sex): Builder |
||||
1110 | { |
||||
1111 | $query = DB::table('individuals') |
||||
1112 | ->where('i_file', '=', $this->tree->id()) |
||||
1113 | ->join('dates AS birth', static function (JoinClause $join): void { |
||||
1114 | $join |
||||
1115 | ->on('birth.d_file', '=', 'i_file') |
||||
1116 | ->on('birth.d_gid', '=', 'i_id'); |
||||
1117 | }) |
||||
1118 | ->join('dates AS death', static function (JoinClause $join): void { |
||||
1119 | $join |
||||
1120 | ->on('death.d_file', '=', 'i_file') |
||||
1121 | ->on('death.d_gid', '=', 'i_id'); |
||||
1122 | }) |
||||
1123 | ->where('birth.d_fact', '=', 'BIRT') |
||||
1124 | ->where('death.d_fact', '=', 'DEAT') |
||||
1125 | ->whereColumn('death.d_julianday1', '>=', 'birth.d_julianday2') |
||||
1126 | ->where('birth.d_julianday2', '<>', 0); |
||||
1127 | |||||
1128 | if ($sex !== 'ALL') { |
||||
1129 | $query->where('i_sex', '=', $sex); |
||||
1130 | } |
||||
1131 | |||||
1132 | return $query; |
||||
1133 | } |
||||
1134 | |||||
1135 | /** |
||||
1136 | * @return object{individual:Individual,days:int}|null |
||||
1137 | */ |
||||
1138 | public function longlifeQuery(string $sex): object|null |
||||
1139 | { |
||||
1140 | return $this->birthAndDeathQuery($sex) |
||||
1141 | ->orderBy('days', 'desc') |
||||
0 ignored issues
–
show
'days' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderBy() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1142 | ->select(['individuals.*', new Expression(DB::prefix('death.d_julianday2') . ' - ' . DB::prefix('birth.d_julianday1') . ' AS days')]) |
||||
0 ignored issues
–
show
Fisharebest\Webtrees\DB:...lianday1') . ' AS days' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1143 | ->take(1) |
||||
1144 | ->get() |
||||
1145 | ->map(fn (object $row): object => (object) [ |
||||
1146 | 'individual' => Registry::individualFactory()->mapper($this->tree)($row), |
||||
1147 | 'days' => (int) $row->days |
||||
1148 | ]) |
||||
1149 | ->first(); |
||||
1150 | } |
||||
1151 | |||||
1152 | /** |
||||
1153 | * @return Collection<int,object{individual:Individual,days:int}> |
||||
1154 | */ |
||||
1155 | public function topTenOldestQuery(string $sex, int $limit): Collection |
||||
1156 | { |
||||
1157 | return $this->birthAndDeathQuery($sex) |
||||
1158 | ->groupBy(['i_id', 'i_file']) |
||||
1159 | ->orderBy('days', 'desc') |
||||
0 ignored issues
–
show
'days' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderBy() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1160 | ->select(['individuals.*', new Expression('MAX(' . DB::prefix('death.d_julianday2') . ' - ' . DB::prefix('birth.d_julianday1') . ') AS days')]) |
||||
0 ignored issues
–
show
'MAX(' . Fisharebest\Web...ianday1') . ') AS days' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1161 | ->take($limit) |
||||
1162 | ->get() |
||||
1163 | ->map(fn (object $row): object => (object) [ |
||||
1164 | 'individual' => Registry::individualFactory()->mapper($this->tree)($row), |
||||
1165 | 'days' => (int) $row->days |
||||
1166 | ]); |
||||
1167 | } |
||||
1168 | |||||
1169 | /** |
||||
1170 | * @return array<string> |
||||
1171 | */ |
||||
1172 | private function getIso3166Countries(): array |
||||
1173 | { |
||||
1174 | // Get the country names for each language |
||||
1175 | $country_to_iso3166 = []; |
||||
1176 | |||||
1177 | $current_language = I18N::languageTag(); |
||||
1178 | |||||
1179 | foreach (I18N::activeLocales() as $locale) { |
||||
1180 | I18N::init($locale->languageTag()); |
||||
1181 | |||||
1182 | $countries = $this->getAllCountries(); |
||||
1183 | |||||
1184 | foreach ($this->iso3166() as $three => $two) { |
||||
1185 | $country_to_iso3166[$three] = $two; |
||||
1186 | $country_to_iso3166[$countries[$three]] = $two; |
||||
1187 | } |
||||
1188 | } |
||||
1189 | |||||
1190 | I18N::init($current_language); |
||||
1191 | |||||
1192 | return $country_to_iso3166; |
||||
1193 | } |
||||
1194 | |||||
1195 | /** |
||||
1196 | * Returns the data structure required by google geochart. |
||||
1197 | * |
||||
1198 | * @param array<int> $places |
||||
1199 | * |
||||
1200 | * @return array<int,array<int|string|array<string,string>>> |
||||
1201 | */ |
||||
1202 | private function createChartData(array $places): array |
||||
1203 | { |
||||
1204 | $data = [ |
||||
1205 | [ |
||||
1206 | I18N::translate('Country'), |
||||
1207 | I18N::translate('Total'), |
||||
1208 | ], |
||||
1209 | ]; |
||||
1210 | |||||
1211 | // webtrees uses 3-letter country codes and localised country names, but google uses 2 letter codes. |
||||
1212 | foreach ($places as $country => $count) { |
||||
1213 | $data[] = [ |
||||
1214 | [ |
||||
1215 | 'v' => $country, |
||||
1216 | 'f' => $this->mapTwoLetterToName($country), |
||||
1217 | ], |
||||
1218 | $count |
||||
1219 | ]; |
||||
1220 | } |
||||
1221 | |||||
1222 | return $data; |
||||
1223 | } |
||||
1224 | |||||
1225 | /** |
||||
1226 | * @return array<string,int> |
||||
1227 | */ |
||||
1228 | private function countIndividualsByCountry(Tree $tree): array |
||||
1229 | { |
||||
1230 | $rows = DB::table('places') |
||||
1231 | ->where('p_file', '=', $tree->id()) |
||||
1232 | ->where('p_parent_id', '=', 0) |
||||
1233 | ->join('placelinks', static function (JoinClause $join): void { |
||||
1234 | $join |
||||
1235 | ->on('pl_file', '=', 'p_file') |
||||
1236 | ->on('pl_p_id', '=', 'p_id'); |
||||
1237 | }) |
||||
1238 | ->join('individuals', static function (JoinClause $join): void { |
||||
1239 | $join |
||||
1240 | ->on('pl_file', '=', 'i_file') |
||||
1241 | ->on('pl_gid', '=', 'i_id'); |
||||
1242 | }) |
||||
1243 | ->groupBy('p_place') |
||||
1244 | ->pluck(new Expression('COUNT(*)'), 'p_place') |
||||
0 ignored issues
–
show
'COUNT(*)' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1245 | ->all(); |
||||
1246 | |||||
1247 | $totals = []; |
||||
1248 | |||||
1249 | $country_to_iso3166 = $this->getIso3166Countries(); |
||||
1250 | |||||
1251 | foreach ($rows as $country => $count) { |
||||
1252 | $country_code = $country_to_iso3166[$country] ?? null; |
||||
1253 | |||||
1254 | if ($country_code !== null) { |
||||
1255 | $totals[$country_code] ??= 0; |
||||
1256 | $totals[$country_code] += $count; |
||||
1257 | } |
||||
1258 | } |
||||
1259 | |||||
1260 | return $totals; |
||||
1261 | } |
||||
1262 | |||||
1263 | /** |
||||
1264 | * @return array<string,int> |
||||
1265 | */ |
||||
1266 | private function countSurnamesByCountry(Tree $tree, string $surname): array |
||||
1267 | { |
||||
1268 | $rows = |
||||
1269 | DB::table('places') |
||||
1270 | ->where('p_file', '=', $tree->id()) |
||||
1271 | ->where('p_parent_id', '=', 0) |
||||
1272 | ->join('placelinks', static function (JoinClause $join): void { |
||||
1273 | $join |
||||
1274 | ->on('pl_file', '=', 'p_file') |
||||
1275 | ->on('pl_p_id', '=', 'p_id'); |
||||
1276 | }) |
||||
1277 | ->join('name', static function (JoinClause $join): void { |
||||
1278 | $join |
||||
1279 | ->on('n_file', '=', 'pl_file') |
||||
1280 | ->on('n_id', '=', 'pl_gid'); |
||||
1281 | }) |
||||
1282 | ->where('n_surn', '=', $surname) |
||||
1283 | ->groupBy('p_place') |
||||
1284 | ->pluck(new Expression('COUNT(*)'), 'p_place'); |
||||
0 ignored issues
–
show
'COUNT(*)' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1285 | |||||
1286 | $totals = []; |
||||
1287 | |||||
1288 | $country_to_iso3166 = $this->getIso3166Countries(); |
||||
1289 | |||||
1290 | foreach ($rows as $country => $count) { |
||||
1291 | $country_code = $country_to_iso3166[$country] ?? null; |
||||
1292 | |||||
1293 | if ($country_code !== null) { |
||||
1294 | $totals[$country_code] ??= 0; |
||||
1295 | $totals[$country_code] += $count; |
||||
1296 | } |
||||
1297 | } |
||||
1298 | |||||
1299 | return $totals; |
||||
1300 | } |
||||
1301 | |||||
1302 | /** |
||||
1303 | * @return array<string,int> |
||||
1304 | */ |
||||
1305 | private function countFamilyEventsByCountry(Tree $tree, string $fact): array |
||||
1306 | { |
||||
1307 | $query = DB::table('places') |
||||
1308 | ->where('p_file', '=', $tree->id()) |
||||
1309 | ->where('p_parent_id', '=', 0) |
||||
1310 | ->join('placelinks', static function (JoinClause $join): void { |
||||
1311 | $join |
||||
1312 | ->on('pl_file', '=', 'p_file') |
||||
1313 | ->on('pl_p_id', '=', 'p_id'); |
||||
1314 | }) |
||||
1315 | ->join('families', static function (JoinClause $join): void { |
||||
1316 | $join |
||||
1317 | ->on('pl_file', '=', 'f_file') |
||||
1318 | ->on('pl_gid', '=', 'f_id'); |
||||
1319 | }) |
||||
1320 | ->select(['p_place AS place', 'f_gedcom AS gedcom']); |
||||
1321 | |||||
1322 | return $this->filterEventPlaces($query, $fact); |
||||
1323 | } |
||||
1324 | |||||
1325 | /** |
||||
1326 | * @return array<string,int> |
||||
1327 | */ |
||||
1328 | private function countIndividualEventsByCountry(Tree $tree, string $fact): array |
||||
1329 | { |
||||
1330 | $query = DB::table('places') |
||||
1331 | ->where('p_file', '=', $tree->id()) |
||||
1332 | ->where('p_parent_id', '=', 0) |
||||
1333 | ->join('placelinks', static function (JoinClause $join): void { |
||||
1334 | $join |
||||
1335 | ->on('pl_file', '=', 'p_file') |
||||
1336 | ->on('pl_p_id', '=', 'p_id'); |
||||
1337 | }) |
||||
1338 | ->join('individuals', static function (JoinClause $join): void { |
||||
1339 | $join |
||||
1340 | ->on('pl_file', '=', 'i_file') |
||||
1341 | ->on('pl_gid', '=', 'i_id'); |
||||
1342 | }) |
||||
1343 | ->select(['p_place AS place', 'i_gedcom AS gedcom']); |
||||
1344 | |||||
1345 | return $this->filterEventPlaces($query, $fact); |
||||
1346 | } |
||||
1347 | |||||
1348 | /** |
||||
1349 | * @return array<string,int> |
||||
1350 | */ |
||||
1351 | private function filterEventPlaces(Builder $query, string $fact): array |
||||
1352 | { |
||||
1353 | $totals = []; |
||||
1354 | |||||
1355 | $country_to_iso3166 = $this->getIso3166Countries(); |
||||
1356 | |||||
1357 | foreach ($query->cursor() as $row) { |
||||
1358 | $country_code = $country_to_iso3166[$row->place] ?? null; |
||||
1359 | |||||
1360 | if ($country_code !== null) { |
||||
1361 | $place_regex = '/\n1 ' . $fact . '(?:\n[2-9].*)*\n2 PLAC.*[, ]' . preg_quote($row->place, '(?:\n|$)/i') . '\n/'; |
||||
1362 | |||||
1363 | if (preg_match($place_regex, $row->gedcom) === 1) { |
||||
1364 | $totals[$country_code] = 1 + ($totals[$country_code] ?? 0); |
||||
1365 | } |
||||
1366 | } |
||||
1367 | } |
||||
1368 | |||||
1369 | return $totals; |
||||
1370 | } |
||||
1371 | |||||
1372 | /** |
||||
1373 | * Create a chart showing where events occurred. |
||||
1374 | * |
||||
1375 | * @param string $chart_shows The type of chart map to show |
||||
1376 | * @param string $chart_type The type of chart to show |
||||
1377 | * @param string $surname The surname for surname based distribution chart |
||||
1378 | */ |
||||
1379 | public function chartDistribution( |
||||
1380 | string $chart_shows = 'world', |
||||
1381 | string $chart_type = '', |
||||
1382 | string $surname = '' |
||||
1383 | ): string { |
||||
1384 | switch ($chart_type) { |
||||
1385 | case 'surname_distribution_chart': |
||||
1386 | $chart_title = I18N::translate('Surname distribution chart') . ': ' . $surname; |
||||
1387 | $surnames = $this->commonSurnames(1, 0, 'count'); |
||||
1388 | $surname = implode(I18N::$list_separator, array_keys(array_shift($surnames) ?? [])); |
||||
1389 | $data = $this->createChartData($this->countSurnamesByCountry($this->tree, $surname)); |
||||
1390 | break; |
||||
1391 | |||||
1392 | case 'birth_distribution_chart': |
||||
1393 | $chart_title = I18N::translate('Birth by country'); |
||||
1394 | $data = $this->createChartData($this->countIndividualEventsByCountry($this->tree, 'BIRT')); |
||||
1395 | break; |
||||
1396 | |||||
1397 | case 'death_distribution_chart': |
||||
1398 | $chart_title = I18N::translate('Death by country'); |
||||
1399 | $data = $this->createChartData($this->countIndividualEventsByCountry($this->tree, 'DEAT')); |
||||
1400 | break; |
||||
1401 | |||||
1402 | case 'marriage_distribution_chart': |
||||
1403 | $chart_title = I18N::translate('Marriage by country'); |
||||
1404 | $data = $this->createChartData($this->countFamilyEventsByCountry($this->tree, 'MARR')); |
||||
1405 | break; |
||||
1406 | |||||
1407 | case 'indi_distribution_chart': |
||||
1408 | default: |
||||
1409 | $chart_title = I18N::translate('Individual distribution chart'); |
||||
1410 | $data = $this->createChartData($this->countIndividualsByCountry($this->tree)); |
||||
1411 | break; |
||||
1412 | } |
||||
1413 | |||||
1414 | return view('statistics/other/charts/geo', [ |
||||
1415 | 'chart_title' => $chart_title, |
||||
1416 | 'chart_color2' => '84beff', |
||||
1417 | 'chart_color3' => 'c3dfff', |
||||
1418 | 'region' => $chart_shows, |
||||
1419 | 'data' => $data, |
||||
1420 | 'language' => I18N::languageTag(), |
||||
1421 | ]); |
||||
1422 | } |
||||
1423 | |||||
1424 | /** |
||||
1425 | * @return array<array{family:Family,count:int}> |
||||
1426 | */ |
||||
1427 | private function topTenGrandFamilyQuery(int $limit): array |
||||
1428 | { |
||||
1429 | return DB::table('families') |
||||
1430 | ->join('link AS children', static function (JoinClause $join): void { |
||||
1431 | $join |
||||
1432 | ->on('children.l_from', '=', 'f_id') |
||||
1433 | ->on('children.l_file', '=', 'f_file') |
||||
1434 | ->where('children.l_type', '=', 'CHIL'); |
||||
1435 | })->join('link AS mchildren', static function (JoinClause $join): void { |
||||
1436 | $join |
||||
1437 | ->on('mchildren.l_file', '=', 'children.l_file') |
||||
1438 | ->on('mchildren.l_from', '=', 'children.l_to') |
||||
1439 | ->where('mchildren.l_type', '=', 'FAMS'); |
||||
1440 | })->join('link AS gchildren', static function (JoinClause $join): void { |
||||
1441 | $join |
||||
1442 | ->on('gchildren.l_file', '=', 'mchildren.l_file') |
||||
1443 | ->on('gchildren.l_from', '=', 'mchildren.l_to') |
||||
1444 | ->where('gchildren.l_type', '=', 'CHIL'); |
||||
1445 | }) |
||||
1446 | ->where('f_file', '=', $this->tree->id()) |
||||
1447 | ->groupBy(['f_id', 'f_file']) |
||||
1448 | ->orderBy(new Expression('COUNT(*)'), 'DESC') |
||||
0 ignored issues
–
show
'COUNT(*)' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1449 | ->select(['families.*']) |
||||
1450 | ->limit($limit) |
||||
1451 | ->get() |
||||
1452 | ->map(Registry::familyFactory()->mapper($this->tree)) |
||||
1453 | ->filter(GedcomRecord::accessFilter()) |
||||
1454 | ->map(static function (Family $family): array { |
||||
1455 | $count = 0; |
||||
1456 | foreach ($family->children() as $child) { |
||||
1457 | foreach ($child->spouseFamilies() as $spouse_family) { |
||||
1458 | $count += $spouse_family->children()->count(); |
||||
1459 | } |
||||
1460 | } |
||||
1461 | |||||
1462 | return [ |
||||
1463 | 'family' => $family, |
||||
1464 | 'count' => $count, |
||||
1465 | ]; |
||||
1466 | }) |
||||
1467 | ->all(); |
||||
1468 | } |
||||
1469 | |||||
1470 | public function topTenLargestGrandFamily(int $limit = 10): string |
||||
1471 | { |
||||
1472 | return view('statistics/families/top10-nolist-grand', [ |
||||
1473 | 'records' => $this->topTenGrandFamilyQuery($limit), |
||||
1474 | ]); |
||||
1475 | } |
||||
1476 | |||||
1477 | public function topTenLargestGrandFamilyList(int $limit = 10): string |
||||
1478 | { |
||||
1479 | return view('statistics/families/top10-list-grand', [ |
||||
1480 | 'records' => $this->topTenGrandFamilyQuery($limit), |
||||
1481 | ]); |
||||
1482 | } |
||||
1483 | |||||
1484 | public function noChildrenFamiliesList(string $type = 'list'): string |
||||
1485 | { |
||||
1486 | $families = DB::table('families') |
||||
1487 | ->where('f_file', '=', $this->tree->id()) |
||||
1488 | ->where('f_numchil', '=', 0) |
||||
1489 | ->get() |
||||
1490 | ->map(Registry::familyFactory()->mapper($this->tree)) |
||||
1491 | ->filter(GedcomRecord::accessFilter()); |
||||
1492 | |||||
1493 | $top10 = []; |
||||
1494 | |||||
1495 | foreach ($families as $family) { |
||||
1496 | if ($type === 'list') { |
||||
1497 | $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->fullName() . '</a></li>'; |
||||
1498 | } else { |
||||
1499 | $top10[] = '<a href="' . e($family->url()) . '">' . $family->fullName() . '</a>'; |
||||
1500 | } |
||||
1501 | } |
||||
1502 | |||||
1503 | if ($type === 'list') { |
||||
1504 | $top10 = implode('', $top10); |
||||
1505 | } else { |
||||
1506 | $top10 = implode('; ', $top10); |
||||
1507 | } |
||||
1508 | |||||
1509 | if ($type === 'list') { |
||||
1510 | return '<ul>' . $top10 . '</ul>'; |
||||
1511 | } |
||||
1512 | |||||
1513 | return $top10; |
||||
1514 | } |
||||
1515 | |||||
1516 | /** |
||||
1517 | * Returns the calculated age the time of event. |
||||
1518 | * |
||||
1519 | * @param int $age The age from the database record |
||||
1520 | */ |
||||
1521 | private function calculateAge(int $age): string |
||||
1522 | { |
||||
1523 | if ($age < 31) { |
||||
1524 | return I18N::plural('%s day', '%s days', $age, I18N::number($age)); |
||||
1525 | } |
||||
1526 | |||||
1527 | if ($age < 365) { |
||||
1528 | $months = (int) ($age / 30.5); |
||||
1529 | |||||
1530 | return I18N::plural('%s month', '%s months', $months, I18N::number($months)); |
||||
1531 | } |
||||
1532 | |||||
1533 | $years = (int) ($age / 365.25); |
||||
1534 | |||||
1535 | return I18N::plural('%s year', '%s years', $years, I18N::number($years)); |
||||
1536 | } |
||||
1537 | |||||
1538 | public function topAgeBetweenSiblings(): string |
||||
1539 | { |
||||
1540 | $rows = $this->maximumAgeBetweenSiblings(1); |
||||
1541 | |||||
1542 | if ($rows === []) { |
||||
1543 | return I18N::translate('This information is not available.'); |
||||
1544 | } |
||||
1545 | |||||
1546 | return $rows[0]->age; |
||||
1547 | } |
||||
1548 | |||||
1549 | public function topAgeBetweenSiblingsFullName(): string |
||||
1550 | { |
||||
1551 | $rows = $this->maximumAgeBetweenSiblings(1); |
||||
1552 | |||||
1553 | if ($rows === []) { |
||||
1554 | return I18N::translate('This information is not available.'); |
||||
1555 | } |
||||
1556 | |||||
1557 | return view('statistics/families/top10-nolist-age', ['record' => (array) $rows[0]]); |
||||
1558 | } |
||||
1559 | |||||
1560 | public function topAgeBetweenSiblingsList(int $limit, bool $unique_families): string |
||||
1561 | { |
||||
1562 | $rows = $this->maximumAgeBetweenSiblings($limit); |
||||
1563 | $records = []; |
||||
1564 | $dist = []; |
||||
1565 | |||||
1566 | foreach ($rows as $row) { |
||||
1567 | if (!$unique_families || !in_array($row->family, $dist, true)) { |
||||
1568 | $records[] = [ |
||||
1569 | 'child1' => $row->child1, |
||||
1570 | 'child2' => $row->child2, |
||||
1571 | 'family' => $row->family, |
||||
1572 | 'age' => $row->age, |
||||
1573 | ]; |
||||
1574 | |||||
1575 | $dist[] = $row->family; |
||||
1576 | } |
||||
1577 | } |
||||
1578 | |||||
1579 | return view('statistics/families/top10-list-age', [ |
||||
1580 | 'records' => $records, |
||||
1581 | ]); |
||||
1582 | } |
||||
1583 | |||||
1584 | /** |
||||
1585 | * @return array<object{f_numchil:int,total:int}> |
||||
0 ignored issues
–
show
|
|||||
1586 | */ |
||||
1587 | public function statsChildrenQuery(int $year1, int $year2): array |
||||
1588 | { |
||||
1589 | $query = DB::table('families') |
||||
1590 | ->where('f_file', '=', $this->tree->id()) |
||||
1591 | ->groupBy(['f_numchil']) |
||||
1592 | ->select(['f_numchil', new Expression('COUNT(*) AS total')]); |
||||
0 ignored issues
–
show
'COUNT(*) AS total' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1593 | |||||
1594 | if ($year1 !== 0 && $year2 !== 0) { |
||||
1595 | $query |
||||
1596 | ->join('dates', static function (JoinClause $join): void { |
||||
1597 | $join |
||||
1598 | ->on('d_file', '=', 'f_file') |
||||
1599 | ->on('d_gid', '=', 'f_id'); |
||||
1600 | }) |
||||
1601 | ->where('d_fact', '=', 'MARR') |
||||
1602 | ->whereIn('d_type', ['@#DGREGORIAN@', '@#DJULIAN@']) |
||||
1603 | ->whereBetween('d_year', [$year1, $year2]); |
||||
1604 | } |
||||
1605 | |||||
1606 | return $query->get() |
||||
1607 | ->map(static fn (object $row): object => (object) [ |
||||
1608 | 'f_numchil' => (int) $row->f_numchil, |
||||
1609 | 'total' => (int) $row->total, |
||||
1610 | ]) |
||||
1611 | ->all(); |
||||
1612 | } |
||||
1613 | |||||
1614 | /** |
||||
1615 | * @return array<array{family:Family,count:int}> |
||||
1616 | */ |
||||
1617 | private function topTenFamilyQuery(int $limit): array |
||||
1618 | { |
||||
1619 | return DB::table('families') |
||||
1620 | ->where('f_file', '=', $this->tree->id()) |
||||
1621 | ->orderBy('f_numchil', 'DESC') |
||||
1622 | ->limit($limit) |
||||
1623 | ->get() |
||||
1624 | ->map(Registry::familyFactory()->mapper($this->tree)) |
||||
1625 | ->filter(GedcomRecord::accessFilter()) |
||||
1626 | ->map(static fn (Family $family): array => [ |
||||
1627 | 'family' => $family, |
||||
1628 | 'count' => $family->numberOfChildren(), |
||||
1629 | ]) |
||||
1630 | ->all(); |
||||
1631 | } |
||||
1632 | |||||
1633 | public function topTenLargestFamily(int $limit = 10): string |
||||
1634 | { |
||||
1635 | $records = $this->topTenFamilyQuery($limit); |
||||
1636 | |||||
1637 | return view('statistics/families/top10-nolist', [ |
||||
1638 | 'records' => $records, |
||||
1639 | ]); |
||||
1640 | } |
||||
1641 | |||||
1642 | public function topTenLargestFamilyList(int $limit = 10): string |
||||
1643 | { |
||||
1644 | $records = $this->topTenFamilyQuery($limit); |
||||
1645 | |||||
1646 | return view('statistics/families/top10-list', [ |
||||
1647 | 'records' => $records, |
||||
1648 | ]); |
||||
1649 | } |
||||
1650 | |||||
1651 | public function parentsQuery(string $type, string $age_dir, string $sex, bool $show_years): string |
||||
1652 | { |
||||
1653 | if ($sex === 'F') { |
||||
1654 | $sex_field = 'WIFE'; |
||||
1655 | } else { |
||||
1656 | $sex_field = 'HUSB'; |
||||
1657 | } |
||||
1658 | |||||
1659 | if ($age_dir !== 'ASC') { |
||||
1660 | $age_dir = 'DESC'; |
||||
1661 | } |
||||
1662 | |||||
1663 | $row = DB::table('link AS parentfamily') |
||||
1664 | ->join('link AS childfamily', static function (JoinClause $join): void { |
||||
1665 | $join |
||||
1666 | ->on('childfamily.l_file', '=', 'parentfamily.l_file') |
||||
1667 | ->on('childfamily.l_from', '=', 'parentfamily.l_from') |
||||
1668 | ->where('childfamily.l_type', '=', 'CHIL'); |
||||
1669 | }) |
||||
1670 | ->join('dates AS birth', static function (JoinClause $join): void { |
||||
1671 | $join |
||||
1672 | ->on('birth.d_file', '=', 'parentfamily.l_file') |
||||
1673 | ->on('birth.d_gid', '=', 'parentfamily.l_to') |
||||
1674 | ->where('birth.d_fact', '=', 'BIRT') |
||||
1675 | ->where('birth.d_julianday1', '<>', 0); |
||||
1676 | }) |
||||
1677 | ->join('dates AS childbirth', static function (JoinClause $join): void { |
||||
1678 | $join |
||||
1679 | ->on('childbirth.d_file', '=', 'parentfamily.l_file') |
||||
1680 | ->on('childbirth.d_gid', '=', 'childfamily.l_to') |
||||
1681 | ->where('childbirth.d_fact', '=', 'BIRT'); |
||||
1682 | }) |
||||
1683 | ->where('childfamily.l_file', '=', $this->tree->id()) |
||||
1684 | ->where('parentfamily.l_type', '=', $sex_field) |
||||
1685 | ->where('childbirth.d_julianday2', '>', new Expression(DB::prefix('birth.d_julianday1'))) |
||||
1686 | ->select(['parentfamily.l_to AS id', new Expression(DB::prefix('childbirth.d_julianday2') . ' - ' . DB::prefix('birth.d_julianday1') . ' AS age')]) |
||||
0 ignored issues
–
show
Fisharebest\Webtrees\DB:...ulianday1') . ' AS age' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1687 | ->take(1) |
||||
1688 | ->orderBy('age', $age_dir) |
||||
1689 | ->get() |
||||
1690 | ->first(); |
||||
1691 | |||||
1692 | if ($row === null) { |
||||
1693 | return I18N::translate('This information is not available.'); |
||||
1694 | } |
||||
1695 | |||||
1696 | $person = Registry::individualFactory()->make($row->id, $this->tree); |
||||
1697 | |||||
1698 | switch ($type) { |
||||
1699 | default: |
||||
1700 | case 'full': |
||||
1701 | if ($person !== null && $person->canShow()) { |
||||
1702 | $result = $person->formatList(); |
||||
1703 | } else { |
||||
1704 | $result = I18N::translate('This information is private and cannot be shown.'); |
||||
1705 | } |
||||
1706 | break; |
||||
1707 | |||||
1708 | case 'name': |
||||
1709 | $result = '<a href="' . e($person->url()) . '">' . $person->fullName() . '</a>'; |
||||
1710 | break; |
||||
1711 | |||||
1712 | case 'age': |
||||
1713 | $age = $row->age; |
||||
1714 | |||||
1715 | if ($show_years) { |
||||
1716 | $result = $this->calculateAge((int) $row->age); |
||||
1717 | } else { |
||||
1718 | $result = (string) floor($age / 365.25); |
||||
1719 | } |
||||
1720 | |||||
1721 | break; |
||||
1722 | } |
||||
1723 | |||||
1724 | return $result; |
||||
1725 | } |
||||
1726 | |||||
1727 | /** |
||||
1728 | * General query on age at marriage. |
||||
1729 | * |
||||
1730 | * @param string $type |
||||
1731 | * @param string $age_dir "ASC" or "DESC" |
||||
1732 | * @param int $limit |
||||
1733 | */ |
||||
1734 | public function ageOfMarriageQuery(string $type, string $age_dir, int $limit): string |
||||
1735 | { |
||||
1736 | $hrows = DB::table('families') |
||||
1737 | ->where('f_file', '=', $this->tree->id()) |
||||
1738 | ->join('dates AS married', static function (JoinClause $join): void { |
||||
1739 | $join |
||||
1740 | ->on('married.d_file', '=', 'f_file') |
||||
1741 | ->on('married.d_gid', '=', 'f_id') |
||||
1742 | ->where('married.d_fact', '=', 'MARR') |
||||
1743 | ->where('married.d_julianday1', '<>', 0); |
||||
1744 | }) |
||||
1745 | ->join('dates AS husbdeath', static function (JoinClause $join): void { |
||||
1746 | $join |
||||
1747 | ->on('husbdeath.d_gid', '=', 'f_husb') |
||||
1748 | ->on('husbdeath.d_file', '=', 'f_file') |
||||
1749 | ->where('husbdeath.d_fact', '=', 'DEAT'); |
||||
1750 | }) |
||||
1751 | ->whereColumn('married.d_julianday1', '<', 'husbdeath.d_julianday2') |
||||
1752 | ->groupBy(['f_id']) |
||||
1753 | ->select(['f_id AS family', new Expression('MIN(' . DB::prefix('husbdeath.d_julianday2') . ' - ' . DB::prefix('married.d_julianday1') . ') AS age')]) |
||||
0 ignored issues
–
show
'MIN(' . Fisharebest\Web...lianday1') . ') AS age' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1754 | ->get() |
||||
1755 | ->all(); |
||||
1756 | |||||
1757 | $wrows = DB::table('families') |
||||
1758 | ->where('f_file', '=', $this->tree->id()) |
||||
1759 | ->join('dates AS married', static function (JoinClause $join): void { |
||||
1760 | $join |
||||
1761 | ->on('married.d_file', '=', 'f_file') |
||||
1762 | ->on('married.d_gid', '=', 'f_id') |
||||
1763 | ->where('married.d_fact', '=', 'MARR') |
||||
1764 | ->where('married.d_julianday1', '<>', 0); |
||||
1765 | }) |
||||
1766 | ->join('dates AS wifedeath', static function (JoinClause $join): void { |
||||
1767 | $join |
||||
1768 | ->on('wifedeath.d_gid', '=', 'f_wife') |
||||
1769 | ->on('wifedeath.d_file', '=', 'f_file') |
||||
1770 | ->where('wifedeath.d_fact', '=', 'DEAT'); |
||||
1771 | }) |
||||
1772 | ->whereColumn('married.d_julianday1', '<', 'wifedeath.d_julianday2') |
||||
1773 | ->groupBy(['f_id']) |
||||
1774 | ->select(['f_id AS family', new Expression('MIN(' . DB::prefix('wifedeath.d_julianday2') . ' - ' . DB::prefix('married.d_julianday1') . ') AS age')]) |
||||
1775 | ->get() |
||||
1776 | ->all(); |
||||
1777 | |||||
1778 | $drows = DB::table('families') |
||||
1779 | ->where('f_file', '=', $this->tree->id()) |
||||
1780 | ->join('dates AS married', static function (JoinClause $join): void { |
||||
1781 | $join |
||||
1782 | ->on('married.d_file', '=', 'f_file') |
||||
1783 | ->on('married.d_gid', '=', 'f_id') |
||||
1784 | ->where('married.d_fact', '=', 'MARR') |
||||
1785 | ->where('married.d_julianday1', '<>', 0); |
||||
1786 | }) |
||||
1787 | ->join('dates AS divorced', static function (JoinClause $join): void { |
||||
1788 | $join |
||||
1789 | ->on('divorced.d_gid', '=', 'f_id') |
||||
1790 | ->on('divorced.d_file', '=', 'f_file') |
||||
1791 | ->whereIn('divorced.d_fact', ['DIV', 'ANUL', '_SEPR']); |
||||
1792 | }) |
||||
1793 | ->whereColumn('married.d_julianday1', '<', 'divorced.d_julianday2') |
||||
1794 | ->groupBy(['f_id']) |
||||
1795 | ->select(['f_id AS family', new Expression('MIN(' . DB::prefix('divorced.d_julianday2') . ' - ' . DB::prefix('married.d_julianday1') . ') AS age')]) |
||||
1796 | ->get() |
||||
1797 | ->all(); |
||||
1798 | |||||
1799 | $rows = []; |
||||
1800 | foreach ($drows as $family) { |
||||
1801 | $rows[$family->family] = $family->age; |
||||
1802 | } |
||||
1803 | |||||
1804 | foreach ($hrows as $family) { |
||||
1805 | if (!isset($rows[$family->family])) { |
||||
1806 | $rows[$family->family] = $family->age; |
||||
1807 | } |
||||
1808 | } |
||||
1809 | |||||
1810 | foreach ($wrows as $family) { |
||||
1811 | if (!isset($rows[$family->family])) { |
||||
1812 | $rows[$family->family] = $family->age; |
||||
1813 | } elseif ($rows[$family->family] > $family->age) { |
||||
1814 | $rows[$family->family] = $family->age; |
||||
1815 | } |
||||
1816 | } |
||||
1817 | |||||
1818 | if ($age_dir === 'DESC') { |
||||
1819 | arsort($rows); |
||||
1820 | } else { |
||||
1821 | asort($rows); |
||||
1822 | } |
||||
1823 | |||||
1824 | $top10 = []; |
||||
1825 | $i = 0; |
||||
1826 | foreach ($rows as $xref => $age) { |
||||
1827 | $family = Registry::familyFactory()->make((string) $xref, $this->tree); |
||||
1828 | if ($type === 'name') { |
||||
1829 | return $family->formatList(); |
||||
1830 | } |
||||
1831 | |||||
1832 | $age = $this->calculateAge((int) $age); |
||||
1833 | |||||
1834 | if ($type === 'age') { |
||||
1835 | return $age; |
||||
1836 | } |
||||
1837 | |||||
1838 | $husb = $family->husband(); |
||||
1839 | $wife = $family->wife(); |
||||
1840 | |||||
1841 | if ( |
||||
1842 | $husb instanceof Individual && |
||||
1843 | $wife instanceof Individual && |
||||
1844 | ($husb->getAllDeathDates() || !$husb->isDead()) && |
||||
1845 | ($wife->getAllDeathDates() || !$wife->isDead()) |
||||
1846 | ) { |
||||
1847 | if ($family->canShow()) { |
||||
1848 | if ($type === 'list') { |
||||
1849 | $top10[] = '<li><a href="' . e($family->url()) . '">' . $family->fullName() . '</a> (' . $age . ')' . '</li>'; |
||||
1850 | } else { |
||||
1851 | $top10[] = '<a href="' . e($family->url()) . '">' . $family->fullName() . '</a> (' . $age . ')'; |
||||
1852 | } |
||||
1853 | } |
||||
1854 | if (++$i === $limit) { |
||||
1855 | break; |
||||
1856 | } |
||||
1857 | } |
||||
1858 | } |
||||
1859 | |||||
1860 | if ($type === 'list') { |
||||
1861 | $top10 = implode('', $top10); |
||||
1862 | } else { |
||||
1863 | $top10 = implode('; ', $top10); |
||||
1864 | } |
||||
1865 | |||||
1866 | if (I18N::direction() === 'rtl') { |
||||
1867 | $top10 = str_replace([ |
||||
1868 | '[', |
||||
1869 | ']', |
||||
1870 | '(', |
||||
1871 | ')', |
||||
1872 | '+', |
||||
1873 | ], [ |
||||
1874 | '‏[', |
||||
1875 | '‏]', |
||||
1876 | '‏(', |
||||
1877 | '‏)', |
||||
1878 | '‏+', |
||||
1879 | ], $top10); |
||||
1880 | } |
||||
1881 | |||||
1882 | if ($type === 'list') { |
||||
1883 | return '<ul>' . $top10 . '</ul>'; |
||||
1884 | } |
||||
1885 | |||||
1886 | return $top10; |
||||
1887 | } |
||||
1888 | |||||
1889 | /** |
||||
1890 | * @return array<array{family:Family,age:string}> |
||||
1891 | */ |
||||
1892 | private function ageBetweenSpousesQuery(string $age_dir, int $limit): array |
||||
1893 | { |
||||
1894 | $query = DB::table('families') |
||||
1895 | ->where('f_file', '=', $this->tree->id()) |
||||
1896 | ->join('dates AS wife', static function (JoinClause $join): void { |
||||
1897 | $join |
||||
1898 | ->on('wife.d_gid', '=', 'f_wife') |
||||
1899 | ->on('wife.d_file', '=', 'f_file') |
||||
1900 | ->where('wife.d_fact', '=', 'BIRT') |
||||
1901 | ->where('wife.d_julianday1', '<>', 0); |
||||
1902 | }) |
||||
1903 | ->join('dates AS husb', static function (JoinClause $join): void { |
||||
1904 | $join |
||||
1905 | ->on('husb.d_gid', '=', 'f_husb') |
||||
1906 | ->on('husb.d_file', '=', 'f_file') |
||||
1907 | ->where('husb.d_fact', '=', 'BIRT') |
||||
1908 | ->where('husb.d_julianday1', '<>', 0); |
||||
1909 | }); |
||||
1910 | |||||
1911 | if ($age_dir === 'DESC') { |
||||
1912 | $query |
||||
1913 | ->whereColumn('wife.d_julianday1', '>=', 'husb.d_julianday1') |
||||
1914 | ->orderBy(new Expression('MIN(' . DB::prefix('wife.d_julianday1') . ') - MIN(' . DB::prefix('husb.d_julianday1') . ')'), 'DESC'); |
||||
0 ignored issues
–
show
'MIN(' . Fisharebest\Web...sb.d_julianday1') . ')' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
1915 | } else { |
||||
1916 | $query |
||||
1917 | ->whereColumn('husb.d_julianday1', '>=', 'wife.d_julianday1') |
||||
1918 | ->orderBy(new Expression('MIN(' . DB::prefix('husb.d_julianday1') . ') - MIN(' . DB::prefix('wife.d_julianday1') . ')'), 'DESC'); |
||||
1919 | } |
||||
1920 | |||||
1921 | return $query |
||||
1922 | ->groupBy(['f_id', 'f_file']) |
||||
1923 | ->select(['families.*']) |
||||
1924 | ->take($limit) |
||||
1925 | ->get() |
||||
1926 | ->map(Registry::familyFactory()->mapper($this->tree)) |
||||
1927 | ->filter(GedcomRecord::accessFilter()) |
||||
1928 | ->map(function (Family $family) use ($age_dir): array { |
||||
1929 | $husb_birt_jd = $family->husband()->getBirthDate()->minimumJulianDay(); |
||||
1930 | $wife_birt_jd = $family->wife()->getBirthDate()->minimumJulianDay(); |
||||
1931 | |||||
1932 | if ($age_dir === 'DESC') { |
||||
1933 | $diff = $wife_birt_jd - $husb_birt_jd; |
||||
1934 | } else { |
||||
1935 | $diff = $husb_birt_jd - $wife_birt_jd; |
||||
1936 | } |
||||
1937 | |||||
1938 | return [ |
||||
1939 | 'family' => $family, |
||||
1940 | 'age' => $this->calculateAge($diff), |
||||
1941 | ]; |
||||
1942 | }) |
||||
1943 | ->all(); |
||||
1944 | } |
||||
1945 | |||||
1946 | public function ageBetweenSpousesMF(int $limit = 10): string |
||||
1947 | { |
||||
1948 | $records = $this->ageBetweenSpousesQuery('DESC', $limit); |
||||
1949 | |||||
1950 | return view('statistics/families/top10-nolist-spouses', [ |
||||
1951 | 'records' => $records, |
||||
1952 | ]); |
||||
1953 | } |
||||
1954 | |||||
1955 | public function ageBetweenSpousesMFList(int $limit = 10): string |
||||
1956 | { |
||||
1957 | $records = $this->ageBetweenSpousesQuery('DESC', $limit); |
||||
1958 | |||||
1959 | return view('statistics/families/top10-list-spouses', [ |
||||
1960 | 'records' => $records, |
||||
1961 | ]); |
||||
1962 | } |
||||
1963 | |||||
1964 | public function ageBetweenSpousesFM(int $limit = 10): string |
||||
1965 | { |
||||
1966 | return view('statistics/families/top10-nolist-spouses', [ |
||||
1967 | 'records' => $this->ageBetweenSpousesQuery('ASC', $limit), |
||||
1968 | ]); |
||||
1969 | } |
||||
1970 | |||||
1971 | public function ageBetweenSpousesFMList(int $limit = 10): string |
||||
1972 | { |
||||
1973 | return view('statistics/families/top10-list-spouses', [ |
||||
1974 | 'records' => $this->ageBetweenSpousesQuery('ASC', $limit), |
||||
1975 | ]); |
||||
1976 | } |
||||
1977 | |||||
1978 | /** |
||||
1979 | * @return array<object{f_id:string,d_gid:string,age:int}> |
||||
0 ignored issues
–
show
|
|||||
1980 | */ |
||||
1981 | public function statsMarrAgeQuery(string $sex, int $year1, int $year2): array |
||||
1982 | { |
||||
1983 | $query = DB::table('dates AS married') |
||||
1984 | ->join('families', static function (JoinClause $join): void { |
||||
1985 | $join |
||||
1986 | ->on('f_file', '=', 'married.d_file') |
||||
1987 | ->on('f_id', '=', 'married.d_gid'); |
||||
1988 | }) |
||||
1989 | ->join('dates AS birth', static function (JoinClause $join) use ($sex): void { |
||||
1990 | $join |
||||
1991 | ->on('birth.d_file', '=', 'married.d_file') |
||||
1992 | ->on('birth.d_gid', '=', $sex === 'M' ? 'f_husb' : 'f_wife') |
||||
1993 | ->where('birth.d_julianday1', '<>', 0) |
||||
1994 | ->where('birth.d_fact', '=', 'BIRT') |
||||
1995 | ->whereIn('birth.d_type', ['@#DGREGORIAN@', '@#DJULIAN@']); |
||||
1996 | }) |
||||
1997 | ->where('married.d_file', '=', $this->tree->id()) |
||||
1998 | ->where('married.d_fact', '=', 'MARR') |
||||
1999 | ->whereIn('married.d_type', ['@#DGREGORIAN@', '@#DJULIAN@']) |
||||
2000 | ->whereColumn('married.d_julianday1', '>', 'birth.d_julianday1') |
||||
2001 | ->select(['f_id', 'birth.d_gid', new Expression(DB::prefix('married.d_julianday2') . ' - ' . DB::prefix('birth.d_julianday1') . ' AS age')]); |
||||
0 ignored issues
–
show
Fisharebest\Webtrees\DB:...ulianday1') . ' AS age' of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
2002 | |||||
2003 | if ($year1 !== 0 && $year2 !== 0) { |
||||
2004 | $query->whereBetween('married.d_year', [$year1, $year2]); |
||||
2005 | } |
||||
2006 | |||||
2007 | return $query |
||||
2008 | ->get() |
||||
2009 | ->map(static fn (object $row): object => (object) [ |
||||
2010 | 'f_id' => $row->f_id, |
||||
2011 | 'd_gid' => $row->d_gid, |
||||
2012 | 'age' => (int) $row->age, |
||||
2013 | ]) |
||||
2014 | ->all(); |
||||
2015 | } |
||||
2016 | |||||
2017 | /** |
||||
2018 | * Query the database for marriage tags. |
||||
2019 | * |
||||
2020 | * @param string $show "full", "name" or "age" |
||||
2021 | * @param string $age_dir "ASC" or "DESC" |
||||
2022 | * @param string $sex "F" or "M" |
||||
2023 | * @param bool $show_years |
||||
2024 | */ |
||||
2025 | public function marriageQuery(string $show, string $age_dir, string $sex, bool $show_years): string |
||||
2026 | { |
||||
2027 | if ($sex === 'F') { |
||||
2028 | $sex_field = 'f_wife'; |
||||
2029 | } else { |
||||
2030 | $sex_field = 'f_husb'; |
||||
2031 | } |
||||
2032 | |||||
2033 | if ($age_dir !== 'ASC') { |
||||
2034 | $age_dir = 'DESC'; |
||||
2035 | } |
||||
2036 | |||||
2037 | $row = DB::table('families') |
||||
2038 | ->join('dates AS married', static function (JoinClause $join): void { |
||||
2039 | $join |
||||
2040 | ->on('married.d_file', '=', 'f_file') |
||||
2041 | ->on('married.d_gid', '=', 'f_id') |
||||
2042 | ->where('married.d_fact', '=', 'MARR'); |
||||
2043 | }) |
||||
2044 | ->join('individuals', static function (JoinClause $join) use ($sex, $sex_field): void { |
||||
2045 | $join |
||||
2046 | ->on('i_file', '=', 'f_file') |
||||
2047 | ->on('i_id', '=', $sex_field) |
||||
2048 | ->where('i_sex', '=', $sex); |
||||
2049 | }) |
||||
2050 | ->join('dates AS birth', static function (JoinClause $join): void { |
||||
2051 | $join |
||||
2052 | ->on('birth.d_file', '=', 'i_file') |
||||
2053 | ->on('birth.d_gid', '=', 'i_id') |
||||
2054 | ->where('birth.d_fact', '=', 'BIRT') |
||||
2055 | ->where('birth.d_julianday1', '<>', 0); |
||||
2056 | }) |
||||
2057 | ->where('f_file', '=', $this->tree->id()) |
||||
2058 | ->where('married.d_julianday2', '>', new Expression(DB::prefix('birth.d_julianday1'))) |
||||
2059 | ->orderBy(new Expression(DB::prefix('married.d_julianday2') . ' - ' . DB::prefix('birth.d_julianday1')), $age_dir) |
||||
0 ignored issues
–
show
Fisharebest\Webtrees\DB:...x('birth.d_julianday1') of type string is incompatible with the type Illuminate\Database\Query\TValue expected by parameter $value of Illuminate\Database\Quer...pression::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
2060 | ->select(['f_id AS famid', $sex_field, new Expression(DB::prefix('married.d_julianday2') . ' - ' . DB::prefix('birth.d_julianday1') . ' AS age'), 'i_id']) |
||||
2061 | ->take(1) |
||||
2062 | ->get() |
||||
2063 | ->first(); |
||||
2064 | |||||
2065 | if ($row === null) { |
||||
2066 | return I18N::translate('This information is not available.'); |
||||
2067 | } |
||||
2068 | |||||
2069 | $family = Registry::familyFactory()->make($row->famid, $this->tree); |
||||
2070 | $person = Registry::individualFactory()->make($row->i_id, $this->tree); |
||||
2071 | |||||
2072 | switch ($show) { |
||||
2073 | default: |
||||
2074 | case 'full': |
||||
2075 | if ($family !== null && $family->canShow()) { |
||||
2076 | $result = $family->formatList(); |
||||
2077 | } else { |
||||
2078 | $result = I18N::translate('This information is private and cannot be shown.'); |
||||
2079 | } |
||||
2080 | break; |
||||
2081 | |||||
2082 | case 'name': |
||||
2083 | $result = '<a href="' . e($family->url()) . '">' . $person->fullName() . '</a>'; |
||||
2084 | break; |
||||
2085 | |||||
2086 | case 'age': |
||||
2087 | $age = $row->age; |
||||
2088 | |||||
2089 | if ($show_years) { |
||||
2090 | $result = $this->calculateAge((int) $row->age); |
||||
2091 | } else { |
||||
2092 | $result = I18N::number((int) ($age / 365.25)); |
||||
2093 | } |
||||
2094 | |||||
2095 | break; |
||||
2096 | } |
||||
2097 | |||||
2098 | return $result; |
||||
2099 | } |
||||
2100 | |||||
2101 | /** |
||||
2102 | * Who is currently logged in? |
||||
2103 | * |
||||
2104 | * @param string $type "list" or "nolist" |
||||
2105 | */ |
||||
2106 | private function usersLoggedInQuery(string $type): string |
||||
2107 | { |
||||
2108 | $content = ''; |
||||
2109 | $anonymous = 0; |
||||
2110 | $logged_in = []; |
||||
2111 | |||||
2112 | foreach ($this->user_service->allLoggedIn() as $user) { |
||||
2113 | if (Auth::isAdmin() || $user->getPreference(UserInterface::PREF_IS_VISIBLE_ONLINE) === '1') { |
||||
2114 | $logged_in[] = $user; |
||||
2115 | } else { |
||||
2116 | $anonymous++; |
||||
2117 | } |
||||
2118 | } |
||||
2119 | |||||
2120 | $count_logged_in = count($logged_in); |
||||
2121 | |||||
2122 | if ($count_logged_in === 0 && $anonymous === 0) { |
||||
2123 | $content .= I18N::translate('No signed-in and no anonymous users'); |
||||
2124 | } |
||||
2125 | |||||
2126 | if ($anonymous > 0) { |
||||
2127 | $content .= '<b>' . I18N::plural('%s anonymous signed-in user', '%s anonymous signed-in users', $anonymous, I18N::number($anonymous)) . '</b>'; |
||||
2128 | } |
||||
2129 | |||||
2130 | if ($count_logged_in > 0) { |
||||
2131 | if ($anonymous !== 0) { |
||||
2132 | if ($type === 'list') { |
||||
2133 | $content .= '<br><br>'; |
||||
2134 | } else { |
||||
2135 | $content .= ' ' . I18N::translate('and') . ' '; |
||||
2136 | } |
||||
2137 | } |
||||
2138 | $content .= '<b>' . I18N::plural('%s signed-in user', '%s signed-in users', $count_logged_in, I18N::number($count_logged_in)) . '</b>'; |
||||
2139 | if ($type === 'list') { |
||||
2140 | $content .= '<ul>'; |
||||
2141 | } else { |
||||
2142 | $content .= ': '; |
||||
2143 | } |
||||
2144 | } |
||||
2145 | |||||
2146 | if (Auth::check()) { |
||||
2147 | foreach ($logged_in as $user) { |
||||
2148 | if ($type === 'list') { |
||||
2149 | $content .= '<li>'; |
||||
2150 | } |
||||
2151 | |||||
2152 | $individual = Registry::individualFactory()->make($this->tree->getUserPreference($user, UserInterface::PREF_TREE_ACCOUNT_XREF), $this->tree); |
||||
2153 | |||||
2154 | if ($individual instanceof Individual && $individual->canShow()) { |
||||
2155 | $content .= '<a href="' . e($individual->url()) . '">' . e($user->realName()) . '</a>'; |
||||
2156 | } else { |
||||
2157 | $content .= e($user->realName()); |
||||
2158 | } |
||||
2159 | |||||
2160 | $content .= ' - ' . e($user->userName()); |
||||
2161 | |||||
2162 | if ($user->getPreference(UserInterface::PREF_CONTACT_METHOD) !== MessageService::CONTACT_METHOD_NONE && Auth::id() !== $user->id()) { |
||||
2163 | $content .= '<a href="' . e(route(MessagePage::class, ['to' => $user->userName(), 'tree' => $this->tree->name()])) . '" class="btn btn-link" title="' . I18N::translate('Send a message') . '">' . view('icons/email') . '</a>'; |
||||
2164 | } |
||||
2165 | |||||
2166 | if ($type === 'list') { |
||||
2167 | $content .= '</li>'; |
||||
2168 | } |
||||
2169 | } |
||||
2170 | } |
||||
2171 | |||||
2172 | if ($type === 'list') { |
||||
2173 | $content .= '</ul>'; |
||||
2174 | } |
||||
2175 | |||||
2176 | return $content; |
||||
2177 | } |
||||
2178 | |||||
2179 | public function usersLoggedIn(): string |
||||
2180 | { |
||||
2181 | return $this->usersLoggedInQuery('nolist'); |
||||
2182 | } |
||||
2183 | |||||
2184 | public function usersLoggedInList(): string |
||||
2185 | { |
||||
2186 | return $this->usersLoggedInQuery('list'); |
||||
2187 | } |
||||
2188 | |||||
2189 | /** |
||||
2190 | * Century name, English => 21st, Polish => XXI, etc. |
||||
2191 | */ |
||||
2192 | private function centuryName(int $century): string |
||||
2193 | { |
||||
2194 | if ($century < 0) { |
||||
2195 | return I18N::translate('%s BCE', $this->centuryName(-$century)); |
||||
2196 | } |
||||
2197 | |||||
2198 | // The current chart engine (Google charts) can't handle <sup></sup> markup |
||||
2199 | return match ($century) { |
||||
2200 | 21 => strip_tags(I18N::translateContext('CENTURY', '21st')), |
||||
2201 | 20 => strip_tags(I18N::translateContext('CENTURY', '20th')), |
||||
2202 | 19 => strip_tags(I18N::translateContext('CENTURY', '19th')), |
||||
2203 | 18 => strip_tags(I18N::translateContext('CENTURY', '18th')), |
||||
2204 | 17 => strip_tags(I18N::translateContext('CENTURY', '17th')), |
||||
2205 | 16 => strip_tags(I18N::translateContext('CENTURY', '16th')), |
||||
2206 | 15 => strip_tags(I18N::translateContext('CENTURY', '15th')), |
||||
2207 | 14 => strip_tags(I18N::translateContext('CENTURY', '14th')), |
||||
2208 | 13 => strip_tags(I18N::translateContext('CENTURY', '13th')), |
||||
2209 | 12 => strip_tags(I18N::translateContext('CENTURY', '12th')), |
||||
2210 | 11 => strip_tags(I18N::translateContext('CENTURY', '11th')), |
||||
2211 | 10 => strip_tags(I18N::translateContext('CENTURY', '10th')), |
||||
2212 | 9 => strip_tags(I18N::translateContext('CENTURY', '9th')), |
||||
2213 | 8 => strip_tags(I18N::translateContext('CENTURY', '8th')), |
||||
2214 | 7 => strip_tags(I18N::translateContext('CENTURY', '7th')), |
||||
2215 | 6 => strip_tags(I18N::translateContext('CENTURY', '6th')), |
||||
2216 | 5 => strip_tags(I18N::translateContext('CENTURY', '5th')), |
||||
2217 | 4 => strip_tags(I18N::translateContext('CENTURY', '4th')), |
||||
2218 | 3 => strip_tags(I18N::translateContext('CENTURY', '3rd')), |
||||
2219 | 2 => strip_tags(I18N::translateContext('CENTURY', '2nd')), |
||||
2220 | 1 => strip_tags(I18N::translateContext('CENTURY', '1st')), |
||||
2221 | default => ($century - 1) . '01-' . $century . '00', |
||||
2222 | }; |
||||
2223 | } |
||||
2224 | |||||
2225 | /** |
||||
2226 | * @return array<string> |
||||
2227 | */ |
||||
2228 | private function getAllCountries(): array |
||||
2229 | { |
||||
2230 | return [ |
||||
2231 | /* I18N: Name of a country or state */ |
||||
2232 | '???' => I18N::translate('Unknown'), |
||||
2233 | /* I18N: Name of a country or state */ |
||||
2234 | 'ABW' => I18N::translate('Aruba'), |
||||
2235 | /* I18N: Name of a country or state */ |
||||
2236 | 'AFG' => I18N::translate('Afghanistan'), |
||||
2237 | /* I18N: Name of a country or state */ |
||||
2238 | 'AGO' => I18N::translate('Angola'), |
||||
2239 | /* I18N: Name of a country or state */ |
||||
2240 | 'AIA' => I18N::translate('Anguilla'), |
||||
2241 | /* I18N: Name of a country or state */ |
||||
2242 | 'ALA' => I18N::translate('Åland Islands'), |
||||
2243 | /* I18N: Name of a country or state */ |
||||
2244 | 'ALB' => I18N::translate('Albania'), |
||||
2245 | /* I18N: Name of a country or state */ |
||||
2246 | 'AND' => I18N::translate('Andorra'), |
||||
2247 | /* I18N: Name of a country or state */ |
||||
2248 | 'ARE' => I18N::translate('United Arab Emirates'), |
||||
2249 | /* I18N: Name of a country or state */ |
||||
2250 | 'ARG' => I18N::translate('Argentina'), |
||||
2251 | /* I18N: Name of a country or state */ |
||||
2252 | 'ARM' => I18N::translate('Armenia'), |
||||
2253 | /* I18N: Name of a country or state */ |
||||
2254 | 'ASM' => I18N::translate('American Samoa'), |
||||
2255 | /* I18N: Name of a country or state */ |
||||
2256 | 'ATA' => I18N::translate('Antarctica'), |
||||
2257 | /* I18N: Name of a country or state */ |
||||
2258 | 'ATF' => I18N::translate('French Southern Territories'), |
||||
2259 | /* I18N: Name of a country or state */ |
||||
2260 | 'ATG' => I18N::translate('Antigua and Barbuda'), |
||||
2261 | /* I18N: Name of a country or state */ |
||||
2262 | 'AUS' => I18N::translate('Australia'), |
||||
2263 | /* I18N: Name of a country or state */ |
||||
2264 | 'AUT' => I18N::translate('Austria'), |
||||
2265 | /* I18N: Name of a country or state */ |
||||
2266 | 'AZE' => I18N::translate('Azerbaijan'), |
||||
2267 | /* I18N: Name of a country or state */ |
||||
2268 | 'AZR' => I18N::translate('Azores'), |
||||
2269 | /* I18N: Name of a country or state */ |
||||
2270 | 'BDI' => I18N::translate('Burundi'), |
||||
2271 | /* I18N: Name of a country or state */ |
||||
2272 | 'BEL' => I18N::translate('Belgium'), |
||||
2273 | /* I18N: Name of a country or state */ |
||||
2274 | 'BEN' => I18N::translate('Benin'), |
||||
2275 | // BES => Bonaire, Sint Eustatius and Saba |
||||
2276 | /* I18N: Name of a country or state */ |
||||
2277 | 'BFA' => I18N::translate('Burkina Faso'), |
||||
2278 | /* I18N: Name of a country or state */ |
||||
2279 | 'BGD' => I18N::translate('Bangladesh'), |
||||
2280 | /* I18N: Name of a country or state */ |
||||
2281 | 'BGR' => I18N::translate('Bulgaria'), |
||||
2282 | /* I18N: Name of a country or state */ |
||||
2283 | 'BHR' => I18N::translate('Bahrain'), |
||||
2284 | /* I18N: Name of a country or state */ |
||||
2285 | 'BHS' => I18N::translate('Bahamas'), |
||||
2286 | /* I18N: Name of a country or state */ |
||||
2287 | 'BIH' => I18N::translate('Bosnia and Herzegovina'), |
||||
2288 | // BLM => Saint Barthélemy |
||||
2289 | 'BLM' => I18N::translate('Saint Barthélemy'), |
||||
2290 | /* I18N: Name of a country or state */ |
||||
2291 | 'BLR' => I18N::translate('Belarus'), |
||||
2292 | /* I18N: Name of a country or state */ |
||||
2293 | 'BLZ' => I18N::translate('Belize'), |
||||
2294 | /* I18N: Name of a country or state */ |
||||
2295 | 'BMU' => I18N::translate('Bermuda'), |
||||
2296 | /* I18N: Name of a country or state */ |
||||
2297 | 'BOL' => I18N::translate('Bolivia'), |
||||
2298 | /* I18N: Name of a country or state */ |
||||
2299 | 'BRA' => I18N::translate('Brazil'), |
||||
2300 | /* I18N: Name of a country or state */ |
||||
2301 | 'BRB' => I18N::translate('Barbados'), |
||||
2302 | /* I18N: Name of a country or state */ |
||||
2303 | 'BRN' => I18N::translate('Brunei Darussalam'), |
||||
2304 | /* I18N: Name of a country or state */ |
||||
2305 | 'BTN' => I18N::translate('Bhutan'), |
||||
2306 | /* I18N: Name of a country or state */ |
||||
2307 | 'BVT' => I18N::translate('Bouvet Island'), |
||||
2308 | /* I18N: Name of a country or state */ |
||||
2309 | 'BWA' => I18N::translate('Botswana'), |
||||
2310 | /* I18N: Name of a country or state */ |
||||
2311 | 'CAF' => I18N::translate('Central African Republic'), |
||||
2312 | /* I18N: Name of a country or state */ |
||||
2313 | 'CAN' => I18N::translate('Canada'), |
||||
2314 | /* I18N: Name of a country or state */ |
||||
2315 | 'CCK' => I18N::translate('Cocos (Keeling) Islands'), |
||||
2316 | /* I18N: Name of a country or state */ |
||||
2317 | 'CHE' => I18N::translate('Switzerland'), |
||||
2318 | /* I18N: Name of a country or state */ |
||||
2319 | 'CHL' => I18N::translate('Chile'), |
||||
2320 | /* I18N: Name of a country or state */ |
||||
2321 | 'CHN' => I18N::translate('China'), |
||||
2322 | /* I18N: Name of a country or state */ |
||||
2323 | 'CIV' => I18N::translate('Côte d’Ivoire'), |
||||
2324 | /* I18N: Name of a country or state */ |
||||
2325 | 'CMR' => I18N::translate('Cameroon'), |
||||
2326 | /* I18N: Name of a country or state */ |
||||
2327 | 'COD' => I18N::translate('Democratic Republic of the Congo'), |
||||
2328 | /* I18N: Name of a country or state */ |
||||
2329 | 'COG' => I18N::translate('Republic of the Congo'), |
||||
2330 | /* I18N: Name of a country or state */ |
||||
2331 | 'COK' => I18N::translate('Cook Islands'), |
||||
2332 | /* I18N: Name of a country or state */ |
||||
2333 | 'COL' => I18N::translate('Colombia'), |
||||
2334 | /* I18N: Name of a country or state */ |
||||
2335 | 'COM' => I18N::translate('Comoros'), |
||||
2336 | /* I18N: Name of a country or state */ |
||||
2337 | 'CPV' => I18N::translate('Cape Verde'), |
||||
2338 | /* I18N: Name of a country or state */ |
||||
2339 | 'CRI' => I18N::translate('Costa Rica'), |
||||
2340 | /* I18N: Name of a country or state */ |
||||
2341 | 'CUB' => I18N::translate('Cuba'), |
||||
2342 | /* I18N: Name of a country or state */ |
||||
2343 | 'CUW' => I18N::translate('Curaçao'), |
||||
2344 | /* I18N: Name of a country or state */ |
||||
2345 | 'CXR' => I18N::translate('Christmas Island'), |
||||
2346 | /* I18N: Name of a country or state */ |
||||
2347 | 'CYM' => I18N::translate('Cayman Islands'), |
||||
2348 | /* I18N: Name of a country or state */ |
||||
2349 | 'CYP' => I18N::translate('Cyprus'), |
||||
2350 | /* I18N: Name of a country or state */ |
||||
2351 | 'CZE' => I18N::translate('Czech Republic'), |
||||
2352 | /* I18N: Name of a country or state */ |
||||
2353 | 'DEU' => I18N::translate('Germany'), |
||||
2354 | /* I18N: Name of a country or state */ |
||||
2355 | 'DJI' => I18N::translate('Djibouti'), |
||||
2356 | /* I18N: Name of a country or state */ |
||||
2357 | 'DMA' => I18N::translate('Dominica'), |
||||
2358 | /* I18N: Name of a country or state */ |
||||
2359 | 'DNK' => I18N::translate('Denmark'), |
||||
2360 | /* I18N: Name of a country or state */ |
||||
2361 | 'DOM' => I18N::translate('Dominican Republic'), |
||||
2362 | /* I18N: Name of a country or state */ |
||||
2363 | 'DZA' => I18N::translate('Algeria'), |
||||
2364 | /* I18N: Name of a country or state */ |
||||
2365 | 'ECU' => I18N::translate('Ecuador'), |
||||
2366 | /* I18N: Name of a country or state */ |
||||
2367 | 'EGY' => I18N::translate('Egypt'), |
||||
2368 | /* I18N: Name of a country or state */ |
||||
2369 | 'ENG' => I18N::translate('England'), |
||||
2370 | /* I18N: Name of a country or state */ |
||||
2371 | 'ERI' => I18N::translate('Eritrea'), |
||||
2372 | /* I18N: Name of a country or state */ |
||||
2373 | 'ESH' => I18N::translate('Western Sahara'), |
||||
2374 | /* I18N: Name of a country or state */ |
||||
2375 | 'ESP' => I18N::translate('Spain'), |
||||
2376 | /* I18N: Name of a country or state */ |
||||
2377 | 'EST' => I18N::translate('Estonia'), |
||||
2378 | /* I18N: Name of a country or state */ |
||||
2379 | 'ETH' => I18N::translate('Ethiopia'), |
||||
2380 | /* I18N: Name of a country or state */ |
||||
2381 | 'FIN' => I18N::translate('Finland'), |
||||
2382 | /* I18N: Name of a country or state */ |
||||
2383 | 'FJI' => I18N::translate('Fiji'), |
||||
2384 | /* I18N: Name of a country or state */ |
||||
2385 | 'FLD' => I18N::translate('Flanders'), |
||||
2386 | /* I18N: Name of a country or state */ |
||||
2387 | 'FLK' => I18N::translate('Falkland Islands'), |
||||
2388 | /* I18N: Name of a country or state */ |
||||
2389 | 'FRA' => I18N::translate('France'), |
||||
2390 | /* I18N: Name of a country or state */ |
||||
2391 | 'FRO' => I18N::translate('Faroe Islands'), |
||||
2392 | /* I18N: Name of a country or state */ |
||||
2393 | 'FSM' => I18N::translate('Micronesia'), |
||||
2394 | /* I18N: Name of a country or state */ |
||||
2395 | 'GAB' => I18N::translate('Gabon'), |
||||
2396 | /* I18N: Name of a country or state */ |
||||
2397 | 'GBR' => I18N::translate('United Kingdom'), |
||||
2398 | /* I18N: Name of a country or state */ |
||||
2399 | 'GEO' => I18N::translate('Georgia'), |
||||
2400 | /* I18N: Name of a country or state */ |
||||
2401 | 'GGY' => I18N::translate('Guernsey'), |
||||
2402 | /* I18N: Name of a country or state */ |
||||
2403 | 'GHA' => I18N::translate('Ghana'), |
||||
2404 | /* I18N: Name of a country or state */ |
||||
2405 | 'GIB' => I18N::translate('Gibraltar'), |
||||
2406 | /* I18N: Name of a country or state */ |
||||
2407 | 'GIN' => I18N::translate('Guinea'), |
||||
2408 | /* I18N: Name of a country or state */ |
||||
2409 | 'GLP' => I18N::translate('Guadeloupe'), |
||||
2410 | /* I18N: Name of a country or state */ |
||||
2411 | 'GMB' => I18N::translate('Gambia'), |
||||
2412 | /* I18N: Name of a country or state */ |
||||
2413 | 'GNB' => I18N::translate('Guinea-Bissau'), |
||||
2414 | /* I18N: Name of a country or state */ |
||||
2415 | 'GNQ' => I18N::translate('Equatorial Guinea'), |
||||
2416 | /* I18N: Name of a country or state */ |
||||
2417 | 'GRC' => I18N::translate('Greece'), |
||||
2418 | /* I18N: Name of a country or state */ |
||||
2419 | 'GRD' => I18N::translate('Grenada'), |
||||
2420 | /* I18N: Name of a country or state */ |
||||
2421 | 'GRL' => I18N::translate('Greenland'), |
||||
2422 | /* I18N: Name of a country or state */ |
||||
2423 | 'GTM' => I18N::translate('Guatemala'), |
||||
2424 | /* I18N: Name of a country or state */ |
||||
2425 | 'GUF' => I18N::translate('French Guiana'), |
||||
2426 | /* I18N: Name of a country or state */ |
||||
2427 | 'GUM' => I18N::translate('Guam'), |
||||
2428 | /* I18N: Name of a country or state */ |
||||
2429 | 'GUY' => I18N::translate('Guyana'), |
||||
2430 | /* I18N: Name of a country or state */ |
||||
2431 | 'HKG' => I18N::translate('Hong Kong'), |
||||
2432 | /* I18N: Name of a country or state */ |
||||
2433 | 'HMD' => I18N::translate('Heard Island and McDonald Islands'), |
||||
2434 | /* I18N: Name of a country or state */ |
||||
2435 | 'HND' => I18N::translate('Honduras'), |
||||
2436 | /* I18N: Name of a country or state */ |
||||
2437 | 'HRV' => I18N::translate('Croatia'), |
||||
2438 | /* I18N: Name of a country or state */ |
||||
2439 | 'HTI' => I18N::translate('Haiti'), |
||||
2440 | /* I18N: Name of a country or state */ |
||||
2441 | 'HUN' => I18N::translate('Hungary'), |
||||
2442 | /* I18N: Name of a country or state */ |
||||
2443 | 'IDN' => I18N::translate('Indonesia'), |
||||
2444 | /* I18N: Name of a country or state */ |
||||
2445 | 'IND' => I18N::translate('India'), |
||||
2446 | /* I18N: Name of a country or state */ |
||||
2447 | 'IOM' => I18N::translate('Isle of Man'), |
||||
2448 | /* I18N: Name of a country or state */ |
||||
2449 | 'IOT' => I18N::translate('British Indian Ocean Territory'), |
||||
2450 | /* I18N: Name of a country or state */ |
||||
2451 | 'IRL' => I18N::translate('Ireland'), |
||||
2452 | /* I18N: Name of a country or state */ |
||||
2453 | 'IRN' => I18N::translate('Iran'), |
||||
2454 | /* I18N: Name of a country or state */ |
||||
2455 | 'IRQ' => I18N::translate('Iraq'), |
||||
2456 | /* I18N: Name of a country or state */ |
||||
2457 | 'ISL' => I18N::translate('Iceland'), |
||||
2458 | /* I18N: Name of a country or state */ |
||||
2459 | 'ISR' => I18N::translate('Israel'), |
||||
2460 | /* I18N: Name of a country or state */ |
||||
2461 | 'ITA' => I18N::translate('Italy'), |
||||
2462 | /* I18N: Name of a country or state */ |
||||
2463 | 'JAM' => I18N::translate('Jamaica'), |
||||
2464 | //'JEY' => Jersey |
||||
2465 | /* I18N: Name of a country or state */ |
||||
2466 | 'JOR' => I18N::translate('Jordan'), |
||||
2467 | /* I18N: Name of a country or state */ |
||||
2468 | 'JPN' => I18N::translate('Japan'), |
||||
2469 | /* I18N: Name of a country or state */ |
||||
2470 | 'KAZ' => I18N::translate('Kazakhstan'), |
||||
2471 | /* I18N: Name of a country or state */ |
||||
2472 | 'KEN' => I18N::translate('Kenya'), |
||||
2473 | /* I18N: Name of a country or state */ |
||||
2474 | 'KGZ' => I18N::translate('Kyrgyzstan'), |
||||
2475 | /* I18N: Name of a country or state */ |
||||
2476 | 'KHM' => I18N::translate('Cambodia'), |
||||
2477 | /* I18N: Name of a country or state */ |
||||
2478 | 'KIR' => I18N::translate('Kiribati'), |
||||
2479 | /* I18N: Name of a country or state */ |
||||
2480 | 'KNA' => I18N::translate('Saint Kitts and Nevis'), |
||||
2481 | /* I18N: Name of a country or state */ |
||||
2482 | 'KOR' => I18N::translate('Korea'), |
||||
2483 | /* I18N: Name of a country or state */ |
||||
2484 | 'KWT' => I18N::translate('Kuwait'), |
||||
2485 | /* I18N: Name of a country or state */ |
||||
2486 | 'LAO' => I18N::translate('Laos'), |
||||
2487 | /* I18N: Name of a country or state */ |
||||
2488 | 'LBN' => I18N::translate('Lebanon'), |
||||
2489 | /* I18N: Name of a country or state */ |
||||
2490 | 'LBR' => I18N::translate('Liberia'), |
||||
2491 | /* I18N: Name of a country or state */ |
||||
2492 | 'LBY' => I18N::translate('Libya'), |
||||
2493 | /* I18N: Name of a country or state */ |
||||
2494 | 'LCA' => I18N::translate('Saint Lucia'), |
||||
2495 | /* I18N: Name of a country or state */ |
||||
2496 | 'LIE' => I18N::translate('Liechtenstein'), |
||||
2497 | /* I18N: Name of a country or state */ |
||||
2498 | 'LKA' => I18N::translate('Sri Lanka'), |
||||
2499 | /* I18N: Name of a country or state */ |
||||
2500 | 'LSO' => I18N::translate('Lesotho'), |
||||
2501 | /* I18N: Name of a country or state */ |
||||
2502 | 'LTU' => I18N::translate('Lithuania'), |
||||
2503 | /* I18N: Name of a country or state */ |
||||
2504 | 'LUX' => I18N::translate('Luxembourg'), |
||||
2505 | /* I18N: Name of a country or state */ |
||||
2506 | 'LVA' => I18N::translate('Latvia'), |
||||
2507 | /* I18N: Name of a country or state */ |
||||
2508 | 'MAC' => I18N::translate('Macau'), |
||||
2509 | // MAF => Saint Martin |
||||
2510 | /* I18N: Name of a country or state */ |
||||
2511 | 'MAR' => I18N::translate('Morocco'), |
||||
2512 | /* I18N: Name of a country or state */ |
||||
2513 | 'MCO' => I18N::translate('Monaco'), |
||||
2514 | /* I18N: Name of a country or state */ |
||||
2515 | 'MDA' => I18N::translate('Moldova'), |
||||
2516 | /* I18N: Name of a country or state */ |
||||
2517 | 'MDG' => I18N::translate('Madagascar'), |
||||
2518 | /* I18N: Name of a country or state */ |
||||
2519 | 'MDV' => I18N::translate('Maldives'), |
||||
2520 | /* I18N: Name of a country or state */ |
||||
2521 | 'MEX' => I18N::translate('Mexico'), |
||||
2522 | /* I18N: Name of a country or state */ |
||||
2523 | 'MHL' => I18N::translate('Marshall Islands'), |
||||
2524 | /* I18N: Name of a country or state */ |
||||
2525 | 'MKD' => I18N::translate('Macedonia'), |
||||
2526 | /* I18N: Name of a country or state */ |
||||
2527 | 'MLI' => I18N::translate('Mali'), |
||||
2528 | /* I18N: Name of a country or state */ |
||||
2529 | 'MLT' => I18N::translate('Malta'), |
||||
2530 | /* I18N: Name of a country or state */ |
||||
2531 | 'MMR' => I18N::translate('Myanmar'), |
||||
2532 | /* I18N: Name of a country or state */ |
||||
2533 | 'MNG' => I18N::translate('Mongolia'), |
||||
2534 | /* I18N: Name of a country or state */ |
||||
2535 | 'MNP' => I18N::translate('Northern Mariana Islands'), |
||||
2536 | /* I18N: Name of a country or state */ |
||||
2537 | 'MNT' => I18N::translate('Montenegro'), |
||||
2538 | /* I18N: Name of a country or state */ |
||||
2539 | 'MOZ' => I18N::translate('Mozambique'), |
||||
2540 | /* I18N: Name of a country or state */ |
||||
2541 | 'MRT' => I18N::translate('Mauritania'), |
||||
2542 | /* I18N: Name of a country or state */ |
||||
2543 | 'MSR' => I18N::translate('Montserrat'), |
||||
2544 | /* I18N: Name of a country or state */ |
||||
2545 | 'MTQ' => I18N::translate('Martinique'), |
||||
2546 | /* I18N: Name of a country or state */ |
||||
2547 | 'MUS' => I18N::translate('Mauritius'), |
||||
2548 | /* I18N: Name of a country or state */ |
||||
2549 | 'MWI' => I18N::translate('Malawi'), |
||||
2550 | /* I18N: Name of a country or state */ |
||||
2551 | 'MYS' => I18N::translate('Malaysia'), |
||||
2552 | /* I18N: Name of a country or state */ |
||||
2553 | 'MYT' => I18N::translate('Mayotte'), |
||||
2554 | /* I18N: Name of a country or state */ |
||||
2555 | 'NAM' => I18N::translate('Namibia'), |
||||
2556 | /* I18N: Name of a country or state */ |
||||
2557 | 'NCL' => I18N::translate('New Caledonia'), |
||||
2558 | /* I18N: Name of a country or state */ |
||||
2559 | 'NER' => I18N::translate('Niger'), |
||||
2560 | /* I18N: Name of a country or state */ |
||||
2561 | 'NFK' => I18N::translate('Norfolk Island'), |
||||
2562 | /* I18N: Name of a country or state */ |
||||
2563 | 'NGA' => I18N::translate('Nigeria'), |
||||
2564 | /* I18N: Name of a country or state */ |
||||
2565 | 'NIC' => I18N::translate('Nicaragua'), |
||||
2566 | /* I18N: Name of a country or state */ |
||||
2567 | 'NIR' => I18N::translate('Northern Ireland'), |
||||
2568 | /* I18N: Name of a country or state */ |
||||
2569 | 'NIU' => I18N::translate('Niue'), |
||||
2570 | /* I18N: Name of a country or state */ |
||||
2571 | 'NLD' => I18N::translate('Netherlands'), |
||||
2572 | /* I18N: Name of a country or state */ |
||||
2573 | 'NOR' => I18N::translate('Norway'), |
||||
2574 | /* I18N: Name of a country or state */ |
||||
2575 | 'NPL' => I18N::translate('Nepal'), |
||||
2576 | /* I18N: Name of a country or state */ |
||||
2577 | 'NRU' => I18N::translate('Nauru'), |
||||
2578 | /* I18N: Name of a country or state */ |
||||
2579 | 'NZL' => I18N::translate('New Zealand'), |
||||
2580 | /* I18N: Name of a country or state */ |
||||
2581 | 'OMN' => I18N::translate('Oman'), |
||||
2582 | /* I18N: Name of a country or state */ |
||||
2583 | 'PAK' => I18N::translate('Pakistan'), |
||||
2584 | /* I18N: Name of a country or state */ |
||||
2585 | 'PAN' => I18N::translate('Panama'), |
||||
2586 | /* I18N: Name of a country or state */ |
||||
2587 | 'PCN' => I18N::translate('Pitcairn'), |
||||
2588 | /* I18N: Name of a country or state */ |
||||
2589 | 'PER' => I18N::translate('Peru'), |
||||
2590 | /* I18N: Name of a country or state */ |
||||
2591 | 'PHL' => I18N::translate('Philippines'), |
||||
2592 | /* I18N: Name of a country or state */ |
||||
2593 | 'PLW' => I18N::translate('Palau'), |
||||
2594 | /* I18N: Name of a country or state */ |
||||
2595 | 'PNG' => I18N::translate('Papua New Guinea'), |
||||
2596 | /* I18N: Name of a country or state */ |
||||
2597 | 'POL' => I18N::translate('Poland'), |
||||
2598 | /* I18N: Name of a country or state */ |
||||
2599 | 'PRI' => I18N::translate('Puerto Rico'), |
||||
2600 | /* I18N: Name of a country or state */ |
||||
2601 | 'PRK' => I18N::translate('North Korea'), |
||||
2602 | /* I18N: Name of a country or state */ |
||||
2603 | 'PRT' => I18N::translate('Portugal'), |
||||
2604 | /* I18N: Name of a country or state */ |
||||
2605 | 'PRY' => I18N::translate('Paraguay'), |
||||
2606 | /* I18N: Name of a country or state */ |
||||
2607 | 'PSE' => I18N::translate('Occupied Palestinian Territory'), |
||||
2608 | /* I18N: Name of a country or state */ |
||||
2609 | 'PYF' => I18N::translate('French Polynesia'), |
||||
2610 | /* I18N: Name of a country or state */ |
||||
2611 | 'QAT' => I18N::translate('Qatar'), |
||||
2612 | /* I18N: Name of a country or state */ |
||||
2613 | 'REU' => I18N::translate('Réunion'), |
||||
2614 | /* I18N: Name of a country or state */ |
||||
2615 | 'ROM' => I18N::translate('Romania'), |
||||
2616 | /* I18N: Name of a country or state */ |
||||
2617 | 'RUS' => I18N::translate('Russia'), |
||||
2618 | /* I18N: Name of a country or state */ |
||||
2619 | 'RWA' => I18N::translate('Rwanda'), |
||||
2620 | /* I18N: Name of a country or state */ |
||||
2621 | 'SAU' => I18N::translate('Saudi Arabia'), |
||||
2622 | /* I18N: Name of a country or state */ |
||||
2623 | 'SCT' => I18N::translate('Scotland'), |
||||
2624 | /* I18N: Name of a country or state */ |
||||
2625 | 'SDN' => I18N::translate('Sudan'), |
||||
2626 | /* I18N: Name of a country or state */ |
||||
2627 | 'SEA' => I18N::translate('At sea'), |
||||
2628 | /* I18N: Name of a country or state */ |
||||
2629 | 'SEN' => I18N::translate('Senegal'), |
||||
2630 | /* I18N: Name of a country or state */ |
||||
2631 | 'SER' => I18N::translate('Serbia'), |
||||
2632 | /* I18N: Name of a country or state */ |
||||
2633 | 'SGP' => I18N::translate('Singapore'), |
||||
2634 | /* I18N: Name of a country or state */ |
||||
2635 | 'SGS' => I18N::translate('South Georgia and the South Sandwich Islands'), |
||||
2636 | /* I18N: Name of a country or state */ |
||||
2637 | 'SHN' => I18N::translate('Saint Helena'), |
||||
2638 | /* I18N: Name of a country or state */ |
||||
2639 | 'SJM' => I18N::translate('Svalbard and Jan Mayen'), |
||||
2640 | /* I18N: Name of a country or state */ |
||||
2641 | 'SLB' => I18N::translate('Solomon Islands'), |
||||
2642 | /* I18N: Name of a country or state */ |
||||
2643 | 'SLE' => I18N::translate('Sierra Leone'), |
||||
2644 | /* I18N: Name of a country or state */ |
||||
2645 | 'SLV' => I18N::translate('El Salvador'), |
||||
2646 | /* I18N: Name of a country or state */ |
||||
2647 | 'SMR' => I18N::translate('San Marino'), |
||||
2648 | /* I18N: Name of a country or state */ |
||||
2649 | 'SOM' => I18N::translate('Somalia'), |
||||
2650 | /* I18N: Name of a country or state */ |
||||
2651 | 'SPM' => I18N::translate('Saint Pierre and Miquelon'), |
||||
2652 | /* I18N: Name of a country or state */ |
||||
2653 | 'SSD' => I18N::translate('South Sudan'), |
||||
2654 | /* I18N: Name of a country or state */ |
||||
2655 | 'STP' => I18N::translate('Sao Tome and Principe'), |
||||
2656 | /* I18N: Name of a country or state */ |
||||
2657 | 'SUR' => I18N::translate('Suriname'), |
||||
2658 | /* I18N: Name of a country or state */ |
||||
2659 | 'SVK' => I18N::translate('Slovakia'), |
||||
2660 | /* I18N: Name of a country or state */ |
||||
2661 | 'SVN' => I18N::translate('Slovenia'), |
||||
2662 | /* I18N: Name of a country or state */ |
||||
2663 | 'SWE' => I18N::translate('Sweden'), |
||||
2664 | /* I18N: Name of a country or state */ |
||||
2665 | 'SWZ' => I18N::translate('Swaziland'), |
||||
2666 | // SXM => Sint Maarten |
||||
2667 | /* I18N: Name of a country or state */ |
||||
2668 | 'SYC' => I18N::translate('Seychelles'), |
||||
2669 | /* I18N: Name of a country or state */ |
||||
2670 | 'SYR' => I18N::translate('Syria'), |
||||
2671 | /* I18N: Name of a country or state */ |
||||
2672 | 'TCA' => I18N::translate('Turks and Caicos Islands'), |
||||
2673 | /* I18N: Name of a country or state */ |
||||
2674 | 'TCD' => I18N::translate('Chad'), |
||||
2675 | /* I18N: Name of a country or state */ |
||||
2676 | 'TGO' => I18N::translate('Togo'), |
||||
2677 | /* I18N: Name of a country or state */ |
||||
2678 | 'THA' => I18N::translate('Thailand'), |
||||
2679 | /* I18N: Name of a country or state */ |
||||
2680 | 'TJK' => I18N::translate('Tajikistan'), |
||||
2681 | /* I18N: Name of a country or state */ |
||||
2682 | 'TKL' => I18N::translate('Tokelau'), |
||||
2683 | /* I18N: Name of a country or state */ |
||||
2684 | 'TKM' => I18N::translate('Turkmenistan'), |
||||
2685 | /* I18N: Name of a country or state */ |
||||
2686 | 'TLS' => I18N::translate('Timor-Leste'), |
||||
2687 | /* I18N: Name of a country or state */ |
||||
2688 | 'TON' => I18N::translate('Tonga'), |
||||
2689 | /* I18N: Name of a country or state */ |
||||
2690 | 'TTO' => I18N::translate('Trinidad and Tobago'), |
||||
2691 | /* I18N: Name of a country or state */ |
||||
2692 | 'TUN' => I18N::translate('Tunisia'), |
||||
2693 | /* I18N: Name of a country or state */ |
||||
2694 | 'TUR' => I18N::translate('Turkey'), |
||||
2695 | /* I18N: Name of a country or state */ |
||||
2696 | 'TUV' => I18N::translate('Tuvalu'), |
||||
2697 | /* I18N: Name of a country or state */ |
||||
2698 | 'TWN' => I18N::translate('Taiwan'), |
||||
2699 | /* I18N: Name of a country or state */ |
||||
2700 | 'TZA' => I18N::translate('Tanzania'), |
||||
2701 | /* I18N: Name of a country or state */ |
||||
2702 | 'UGA' => I18N::translate('Uganda'), |
||||
2703 | /* I18N: Name of a country or state */ |
||||
2704 | 'UKR' => I18N::translate('Ukraine'), |
||||
2705 | /* I18N: Name of a country or state */ |
||||
2706 | 'UMI' => I18N::translate('US Minor Outlying Islands'), |
||||
2707 | /* I18N: Name of a country or state */ |
||||
2708 | 'URY' => I18N::translate('Uruguay'), |
||||
2709 | /* I18N: Name of a country or state */ |
||||
2710 | 'USA' => I18N::translate('United States'), |
||||
2711 | /* I18N: Name of a country or state */ |
||||
2712 | 'UZB' => I18N::translate('Uzbekistan'), |
||||
2713 | /* I18N: Name of a country or state */ |
||||
2714 | 'VAT' => I18N::translate('Vatican City'), |
||||
2715 | /* I18N: Name of a country or state */ |
||||
2716 | 'VCT' => I18N::translate('Saint Vincent and the Grenadines'), |
||||
2717 | /* I18N: Name of a country or state */ |
||||
2718 | 'VEN' => I18N::translate('Venezuela'), |
||||
2719 | /* I18N: Name of a country or state */ |
||||
2720 | 'VGB' => I18N::translate('British Virgin Islands'), |
||||
2721 | /* I18N: Name of a country or state */ |
||||
2722 | 'VIR' => I18N::translate('US Virgin Islands'), |
||||
2723 | /* I18N: Name of a country or state */ |
||||
2724 | 'VNM' => I18N::translate('Vietnam'), |
||||
2725 | /* I18N: Name of a country or state */ |
||||
2726 | 'VUT' => I18N::translate('Vanuatu'), |
||||
2727 | /* I18N: Name of a country or state */ |
||||
2728 | 'WLF' => I18N::translate('Wallis and Futuna'), |
||||
2729 | /* I18N: Name of a country or state */ |
||||
2730 | 'WLS' => I18N::translate('Wales'), |
||||
2731 | /* I18N: Name of a country or state */ |
||||
2732 | 'WSM' => I18N::translate('Samoa'), |
||||
2733 | /* I18N: Name of a country or state */ |
||||
2734 | 'YEM' => I18N::translate('Yemen'), |
||||
2735 | /* I18N: Name of a country or state */ |
||||
2736 | 'ZAF' => I18N::translate('South Africa'), |
||||
2737 | /* I18N: Name of a country or state */ |
||||
2738 | 'ZMB' => I18N::translate('Zambia'), |
||||
2739 | /* I18N: Name of a country or state */ |
||||
2740 | 'ZWE' => I18N::translate('Zimbabwe'), |
||||
2741 | ]; |
||||
2742 | } |
||||
2743 | |||||
2744 | /** |
||||
2745 | * ISO3166 3 letter codes, with their 2 letter equivalent. |
||||
2746 | * NOTE: this is not 1:1. ENG/SCO/WAL/NIR => GB |
||||
2747 | * NOTE: this also includes chapman codes and others. Should it? |
||||
2748 | * |
||||
2749 | * @return array<string> |
||||
2750 | */ |
||||
2751 | private function iso3166(): array |
||||
2752 | { |
||||
2753 | return [ |
||||
2754 | 'GBR' => 'GB', // Must come before ENG, NIR, SCT and WLS |
||||
2755 | 'ABW' => 'AW', |
||||
2756 | 'AFG' => 'AF', |
||||
2757 | 'AGO' => 'AO', |
||||
2758 | 'AIA' => 'AI', |
||||
2759 | 'ALA' => 'AX', |
||||
2760 | 'ALB' => 'AL', |
||||
2761 | 'AND' => 'AD', |
||||
2762 | 'ARE' => 'AE', |
||||
2763 | 'ARG' => 'AR', |
||||
2764 | 'ARM' => 'AM', |
||||
2765 | 'ASM' => 'AS', |
||||
2766 | 'ATA' => 'AQ', |
||||
2767 | 'ATF' => 'TF', |
||||
2768 | 'ATG' => 'AG', |
||||
2769 | 'AUS' => 'AU', |
||||
2770 | 'AUT' => 'AT', |
||||
2771 | 'AZE' => 'AZ', |
||||
2772 | 'BDI' => 'BI', |
||||
2773 | 'BEL' => 'BE', |
||||
2774 | 'BEN' => 'BJ', |
||||
2775 | 'BFA' => 'BF', |
||||
2776 | 'BGD' => 'BD', |
||||
2777 | 'BGR' => 'BG', |
||||
2778 | 'BHR' => 'BH', |
||||
2779 | 'BHS' => 'BS', |
||||
2780 | 'BIH' => 'BA', |
||||
2781 | 'BLR' => 'BY', |
||||
2782 | 'BLZ' => 'BZ', |
||||
2783 | 'BMU' => 'BM', |
||||
2784 | 'BOL' => 'BO', |
||||
2785 | 'BRA' => 'BR', |
||||
2786 | 'BRB' => 'BB', |
||||
2787 | 'BRN' => 'BN', |
||||
2788 | 'BTN' => 'BT', |
||||
2789 | 'BVT' => 'BV', |
||||
2790 | 'BWA' => 'BW', |
||||
2791 | 'CAF' => 'CF', |
||||
2792 | 'CAN' => 'CA', |
||||
2793 | 'CCK' => 'CC', |
||||
2794 | 'CHE' => 'CH', |
||||
2795 | 'CHL' => 'CL', |
||||
2796 | 'CHN' => 'CN', |
||||
2797 | 'CIV' => 'CI', |
||||
2798 | 'CMR' => 'CM', |
||||
2799 | 'COD' => 'CD', |
||||
2800 | 'COG' => 'CG', |
||||
2801 | 'COK' => 'CK', |
||||
2802 | 'COL' => 'CO', |
||||
2803 | 'COM' => 'KM', |
||||
2804 | 'CPV' => 'CV', |
||||
2805 | 'CRI' => 'CR', |
||||
2806 | 'CUB' => 'CU', |
||||
2807 | 'CXR' => 'CX', |
||||
2808 | 'CYM' => 'KY', |
||||
2809 | 'CYP' => 'CY', |
||||
2810 | 'CZE' => 'CZ', |
||||
2811 | 'DEU' => 'DE', |
||||
2812 | 'DJI' => 'DJ', |
||||
2813 | 'DMA' => 'DM', |
||||
2814 | 'DNK' => 'DK', |
||||
2815 | 'DOM' => 'DO', |
||||
2816 | 'DZA' => 'DZ', |
||||
2817 | 'ECU' => 'EC', |
||||
2818 | 'EGY' => 'EG', |
||||
2819 | 'ENG' => 'GB', |
||||
2820 | 'ERI' => 'ER', |
||||
2821 | 'ESH' => 'EH', |
||||
2822 | 'ESP' => 'ES', |
||||
2823 | 'EST' => 'EE', |
||||
2824 | 'ETH' => 'ET', |
||||
2825 | 'FIN' => 'FI', |
||||
2826 | 'FJI' => 'FJ', |
||||
2827 | 'FLK' => 'FK', |
||||
2828 | 'FRA' => 'FR', |
||||
2829 | 'FRO' => 'FO', |
||||
2830 | 'FSM' => 'FM', |
||||
2831 | 'GAB' => 'GA', |
||||
2832 | 'GEO' => 'GE', |
||||
2833 | 'GHA' => 'GH', |
||||
2834 | 'GIB' => 'GI', |
||||
2835 | 'GIN' => 'GN', |
||||
2836 | 'GLP' => 'GP', |
||||
2837 | 'GMB' => 'GM', |
||||
2838 | 'GNB' => 'GW', |
||||
2839 | 'GNQ' => 'GQ', |
||||
2840 | 'GRC' => 'GR', |
||||
2841 | 'GRD' => 'GD', |
||||
2842 | 'GRL' => 'GL', |
||||
2843 | 'GTM' => 'GT', |
||||
2844 | 'GUF' => 'GF', |
||||
2845 | 'GUM' => 'GU', |
||||
2846 | 'GUY' => 'GY', |
||||
2847 | 'HKG' => 'HK', |
||||
2848 | 'HMD' => 'HM', |
||||
2849 | 'HND' => 'HN', |
||||
2850 | 'HRV' => 'HR', |
||||
2851 | 'HTI' => 'HT', |
||||
2852 | 'HUN' => 'HU', |
||||
2853 | 'IDN' => 'ID', |
||||
2854 | 'IND' => 'IN', |
||||
2855 | 'IOT' => 'IO', |
||||
2856 | 'IRL' => 'IE', |
||||
2857 | 'IRN' => 'IR', |
||||
2858 | 'IRQ' => 'IQ', |
||||
2859 | 'ISL' => 'IS', |
||||
2860 | 'ISR' => 'IL', |
||||
2861 | 'ITA' => 'IT', |
||||
2862 | 'JAM' => 'JM', |
||||
2863 | 'JOR' => 'JO', |
||||
2864 | 'JPN' => 'JP', |
||||
2865 | 'KAZ' => 'KZ', |
||||
2866 | 'KEN' => 'KE', |
||||
2867 | 'KGZ' => 'KG', |
||||
2868 | 'KHM' => 'KH', |
||||
2869 | 'KIR' => 'KI', |
||||
2870 | 'KNA' => 'KN', |
||||
2871 | 'KOR' => 'KO', |
||||
2872 | 'KWT' => 'KW', |
||||
2873 | 'LAO' => 'LA', |
||||
2874 | 'LBN' => 'LB', |
||||
2875 | 'LBR' => 'LR', |
||||
2876 | 'LBY' => 'LY', |
||||
2877 | 'LCA' => 'LC', |
||||
2878 | 'LIE' => 'LI', |
||||
2879 | 'LKA' => 'LK', |
||||
2880 | 'LSO' => 'LS', |
||||
2881 | 'LTU' => 'LT', |
||||
2882 | 'LUX' => 'LU', |
||||
2883 | 'LVA' => 'LV', |
||||
2884 | 'MAC' => 'MO', |
||||
2885 | 'MAR' => 'MA', |
||||
2886 | 'MCO' => 'MC', |
||||
2887 | 'MDA' => 'MD', |
||||
2888 | 'MDG' => 'MG', |
||||
2889 | 'MDV' => 'MV', |
||||
2890 | 'MEX' => 'MX', |
||||
2891 | 'MHL' => 'MH', |
||||
2892 | 'MKD' => 'MK', |
||||
2893 | 'MLI' => 'ML', |
||||
2894 | 'MLT' => 'MT', |
||||
2895 | 'MMR' => 'MM', |
||||
2896 | 'MNG' => 'MN', |
||||
2897 | 'MNP' => 'MP', |
||||
2898 | 'MNT' => 'ME', |
||||
2899 | 'MOZ' => 'MZ', |
||||
2900 | 'MRT' => 'MR', |
||||
2901 | 'MSR' => 'MS', |
||||
2902 | 'MTQ' => 'MQ', |
||||
2903 | 'MUS' => 'MU', |
||||
2904 | 'MWI' => 'MW', |
||||
2905 | 'MYS' => 'MY', |
||||
2906 | 'MYT' => 'YT', |
||||
2907 | 'NAM' => 'NA', |
||||
2908 | 'NCL' => 'NC', |
||||
2909 | 'NER' => 'NE', |
||||
2910 | 'NFK' => 'NF', |
||||
2911 | 'NGA' => 'NG', |
||||
2912 | 'NIC' => 'NI', |
||||
2913 | 'NIR' => 'GB', |
||||
2914 | 'NIU' => 'NU', |
||||
2915 | 'NLD' => 'NL', |
||||
2916 | 'NOR' => 'NO', |
||||
2917 | 'NPL' => 'NP', |
||||
2918 | 'NRU' => 'NR', |
||||
2919 | 'NZL' => 'NZ', |
||||
2920 | 'OMN' => 'OM', |
||||
2921 | 'PAK' => 'PK', |
||||
2922 | 'PAN' => 'PA', |
||||
2923 | 'PCN' => 'PN', |
||||
2924 | 'PER' => 'PE', |
||||
2925 | 'PHL' => 'PH', |
||||
2926 | 'PLW' => 'PW', |
||||
2927 | 'PNG' => 'PG', |
||||
2928 | 'POL' => 'PL', |
||||
2929 | 'PRI' => 'PR', |
||||
2930 | 'PRK' => 'KP', |
||||
2931 | 'PRT' => 'PT', |
||||
2932 | 'PRY' => 'PY', |
||||
2933 | 'PSE' => 'PS', |
||||
2934 | 'PYF' => 'PF', |
||||
2935 | 'QAT' => 'QA', |
||||
2936 | 'REU' => 'RE', |
||||
2937 | 'ROM' => 'RO', |
||||
2938 | 'RUS' => 'RU', |
||||
2939 | 'RWA' => 'RW', |
||||
2940 | 'SAU' => 'SA', |
||||
2941 | 'SCT' => 'GB', |
||||
2942 | 'SDN' => 'SD', |
||||
2943 | 'SEN' => 'SN', |
||||
2944 | 'SER' => 'RS', |
||||
2945 | 'SGP' => 'SG', |
||||
2946 | 'SGS' => 'GS', |
||||
2947 | 'SHN' => 'SH', |
||||
2948 | 'SJM' => 'SJ', |
||||
2949 | 'SLB' => 'SB', |
||||
2950 | 'SLE' => 'SL', |
||||
2951 | 'SLV' => 'SV', |
||||
2952 | 'SMR' => 'SM', |
||||
2953 | 'SOM' => 'SO', |
||||
2954 | 'SPM' => 'PM', |
||||
2955 | 'STP' => 'ST', |
||||
2956 | 'SUR' => 'SR', |
||||
2957 | 'SVK' => 'SK', |
||||
2958 | 'SVN' => 'SI', |
||||
2959 | 'SWE' => 'SE', |
||||
2960 | 'SWZ' => 'SZ', |
||||
2961 | 'SYC' => 'SC', |
||||
2962 | 'SYR' => 'SY', |
||||
2963 | 'TCA' => 'TC', |
||||
2964 | 'TCD' => 'TD', |
||||
2965 | 'TGO' => 'TG', |
||||
2966 | 'THA' => 'TH', |
||||
2967 | 'TJK' => 'TJ', |
||||
2968 | 'TKL' => 'TK', |
||||
2969 | 'TKM' => 'TM', |
||||
2970 | 'TLS' => 'TL', |
||||
2971 | 'TON' => 'TO', |
||||
2972 | 'TTO' => 'TT', |
||||
2973 | 'TUN' => 'TN', |
||||
2974 | 'TUR' => 'TR', |
||||
2975 | 'TUV' => 'TV', |
||||
2976 | 'TWN' => 'TW', |
||||
2977 | 'TZA' => 'TZ', |
||||
2978 | 'UGA' => 'UG', |
||||
2979 | 'UKR' => 'UA', |
||||
2980 | 'UMI' => 'UM', |
||||
2981 | 'URY' => 'UY', |
||||
2982 | 'USA' => 'US', |
||||
2983 | 'UZB' => 'UZ', |
||||
2984 | 'VAT' => 'VA', |
||||
2985 | 'VCT' => 'VC', |
||||
2986 | 'VEN' => 'VE', |
||||
2987 | 'VGB' => 'VG', |
||||
2988 | 'VIR' => 'VI', |
||||
2989 | 'VNM' => 'VN', |
||||
2990 | 'VUT' => 'VU', |
||||
2991 | 'WLF' => 'WF', |
||||
2992 | 'WLS' => 'GB', |
||||
2993 | 'WSM' => 'WS', |
||||
2994 | 'YEM' => 'YE', |
||||
2995 | 'ZAF' => 'ZA', |
||||
2996 | 'ZMB' => 'ZM', |
||||
2997 | 'ZWE' => 'ZW', |
||||
2998 | ]; |
||||
2999 | } |
||||
3000 | |||||
3001 | /** |
||||
3002 | * Returns the translated country name based on the given two letter country code. |
||||
3003 | */ |
||||
3004 | private function mapTwoLetterToName(string $twoLetterCode): string |
||||
3005 | { |
||||
3006 | $threeLetterCode = array_search($twoLetterCode, $this->iso3166(), true); |
||||
3007 | $threeLetterCode = $threeLetterCode ?: '???'; |
||||
3008 | |||||
3009 | return $this->getAllCountries()[$threeLetterCode]; |
||||
3010 | } |
||||
3011 | } |
||||
3012 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths