xref: /webtrees/app/Statistics.php (revision 3ee4c7ef16663dd8419c69876f7c40ed549d5490)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2023 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
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees;
21
22use Fisharebest\Webtrees\Module\ModuleBlockInterface;
23use Fisharebest\Webtrees\Module\ModuleInterface;
24use Fisharebest\Webtrees\Services\ModuleService;
25use Fisharebest\Webtrees\Services\UserService;
26use Fisharebest\Webtrees\Statistics\Repository\BrowserRepository;
27use Fisharebest\Webtrees\Statistics\Repository\ContactRepository;
28use Fisharebest\Webtrees\Statistics\Repository\EventRepository;
29use Fisharebest\Webtrees\Statistics\Repository\FamilyDatesRepository;
30use Fisharebest\Webtrees\Statistics\Repository\FamilyRepository;
31use Fisharebest\Webtrees\Statistics\Repository\FavoritesRepository;
32use Fisharebest\Webtrees\Statistics\Repository\GedcomRepository;
33use Fisharebest\Webtrees\Statistics\Repository\HitCountRepository;
34use Fisharebest\Webtrees\Statistics\Repository\IndividualRepository;
35use Fisharebest\Webtrees\Statistics\Repository\Interfaces\BrowserRepositoryInterface;
36use Fisharebest\Webtrees\Statistics\Repository\Interfaces\ContactRepositoryInterface;
37use Fisharebest\Webtrees\Statistics\Repository\Interfaces\EventRepositoryInterface;
38use Fisharebest\Webtrees\Statistics\Repository\Interfaces\FamilyDatesRepositoryInterface;
39use Fisharebest\Webtrees\Statistics\Repository\Interfaces\FavoritesRepositoryInterface;
40use Fisharebest\Webtrees\Statistics\Repository\Interfaces\GedcomRepositoryInterface;
41use Fisharebest\Webtrees\Statistics\Repository\Interfaces\HitCountRepositoryInterface;
42use Fisharebest\Webtrees\Statistics\Repository\Interfaces\IndividualRepositoryInterface;
43use Fisharebest\Webtrees\Statistics\Repository\Interfaces\LatestUserRepositoryInterface;
44use Fisharebest\Webtrees\Statistics\Repository\Interfaces\MediaRepositoryInterface;
45use Fisharebest\Webtrees\Statistics\Repository\Interfaces\MessageRepositoryInterface;
46use Fisharebest\Webtrees\Statistics\Repository\Interfaces\NewsRepositoryInterface;
47use Fisharebest\Webtrees\Statistics\Repository\Interfaces\PlaceRepositoryInterface;
48use Fisharebest\Webtrees\Statistics\Repository\Interfaces\ServerRepositoryInterface;
49use Fisharebest\Webtrees\Statistics\Repository\Interfaces\UserRepositoryInterface;
50use Fisharebest\Webtrees\Statistics\Repository\LatestUserRepository;
51use Fisharebest\Webtrees\Statistics\Repository\MediaRepository;
52use Fisharebest\Webtrees\Statistics\Repository\MessageRepository;
53use Fisharebest\Webtrees\Statistics\Repository\NewsRepository;
54use Fisharebest\Webtrees\Statistics\Repository\PlaceRepository;
55use Fisharebest\Webtrees\Statistics\Repository\ServerRepository;
56use Fisharebest\Webtrees\Statistics\Repository\UserRepository;
57use Fisharebest\Webtrees\Statistics\Service\CenturyService;
58use Fisharebest\Webtrees\Statistics\Service\ColorService;
59use Fisharebest\Webtrees\Statistics\Service\CountryService;
60use Illuminate\Database\Query\Builder;
61use Illuminate\Support\Collection;
62use ReflectionClass;
63use ReflectionException;
64use ReflectionMethod;
65use ReflectionNamedType;
66
67use function count;
68use function in_array;
69use function str_contains;
70
71/**
72 * A selection of pre-formatted statistical queries.
73 * These are primarily used for embedded keywords on HTML blocks, but
74 * are also used elsewhere in the code.
75 */
76class Statistics implements
77    GedcomRepositoryInterface,
78    IndividualRepositoryInterface,
79    EventRepositoryInterface,
80    MediaRepositoryInterface,
81    UserRepositoryInterface,
82    ServerRepositoryInterface,
83    BrowserRepositoryInterface,
84    HitCountRepositoryInterface,
85    LatestUserRepositoryInterface,
86    FavoritesRepositoryInterface,
87    NewsRepositoryInterface,
88    MessageRepositoryInterface,
89    ContactRepositoryInterface,
90    FamilyDatesRepositoryInterface,
91    PlaceRepositoryInterface
92{
93    private Tree $tree;
94
95    private GedcomRepository $gedcom_repository;
96
97    private IndividualRepository $individual_repository;
98
99    private FamilyRepository $family_repository;
100
101    private MediaRepository $media_repository;
102
103    private EventRepository $event_repository;
104
105    private UserRepository $user_repository;
106
107    private ServerRepository $server_repository;
108
109    private BrowserRepository $browser_repository;
110
111    private HitCountRepository $hit_count_repository;
112
113    private LatestUserRepository $latest_user_repository;
114
115    private FavoritesRepository $favorites_repository;
116
117    private NewsRepository $news_repository;
118
119    private MessageRepository $message_repository;
120
121    private ContactRepository $contact_repository;
122
123    private FamilyDatesRepository $family_dates_repository;
124
125    private PlaceRepository $place_repository;
126
127    private ModuleService $module_service;
128
129    /**
130     * Create the statistics for a tree.
131     *
132     * @param CenturyService $century_service
133     * @param ColorService   $color_service
134     * @param CountryService $country_service
135     * @param ModuleService  $module_service
136     * @param Tree           $tree Generate statistics for this tree
137     * @param UserService    $user_service
138     */
139    public function __construct(
140        CenturyService $century_service,
141        ColorService $color_service,
142        CountryService $country_service,
143        ModuleService $module_service,
144        Tree $tree,
145        UserService $user_service
146    ) {
147        $this->tree                    = $tree;
148        $this->gedcom_repository       = new GedcomRepository($tree);
149        $this->individual_repository   = new IndividualRepository($century_service, $color_service, $tree);
150        $this->family_repository       = new FamilyRepository($century_service, $color_service, $tree);
151        $this->family_dates_repository = new FamilyDatesRepository($tree);
152        $this->media_repository        = new MediaRepository($color_service, $tree);
153        $this->event_repository        = new EventRepository($tree);
154        $this->user_repository         = new UserRepository($tree, $user_service);
155        $this->server_repository       = new ServerRepository();
156        $this->browser_repository      = new BrowserRepository();
157        $this->hit_count_repository    = new HitCountRepository($tree, $user_service);
158        $this->latest_user_repository  = new LatestUserRepository($user_service);
159        $this->favorites_repository    = new FavoritesRepository($tree, $module_service);
160        $this->news_repository         = new NewsRepository($tree);
161        $this->message_repository      = new MessageRepository();
162        $this->contact_repository      = new ContactRepository($tree, $user_service);
163        $this->place_repository        = new PlaceRepository($tree, $country_service, $this->individual_repository);
164        $this->module_service          = $module_service;
165    }
166
167    /**
168     * Return a string of all supported tags and an example of its output in table row form.
169     *
170     * @return string
171     */
172    public function getAllTagsTable(): string
173    {
174        try {
175            $class = new ReflectionClass($this);
176
177            $public_methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
178
179            $examples = Collection::make($public_methods)
180                ->filter(static fn (ReflectionMethod $method): bool => !in_array($method->getName(), ['embedTags', 'getAllTagsTable'], true))
181                ->filter(static function (ReflectionMethod $method): bool {
182                    $type = $method->getReturnType();
183
184                    return $type instanceof ReflectionNamedType && $type->getName() === 'string';
185                })
186                ->sort(static fn (ReflectionMethod $x, ReflectionMethod $y): int => $x->getName() <=> $y->getName())
187                ->map(function (ReflectionMethod $method): string {
188                    $tag = $method->getName();
189
190                    return '<dt>#' . $tag . '#</dt><dd>' . $this->$tag() . '</dd>';
191                });
192
193            return '<dl>' . $examples->implode('') . '</dl>';
194        } catch (ReflectionException $ex) {
195            return $ex->getMessage();
196        }
197    }
198
199    /**
200     * Embed tags in text
201     *
202     * @param string $text
203     *
204     * @return string
205     */
206    public function embedTags(string $text): string
207    {
208        if (str_contains($text, '#')) {
209            $text = strtr($text, $this->getTags($text));
210        }
211
212        return $text;
213    }
214
215    /**
216     * @return string
217     */
218    public function gedcomFilename(): string
219    {
220        return $this->gedcom_repository->gedcomFilename();
221    }
222
223    /**
224     * @return int
225     */
226    public function gedcomId(): int
227    {
228        return $this->gedcom_repository->gedcomId();
229    }
230
231    /**
232     * @return string
233     */
234    public function gedcomTitle(): string
235    {
236        return $this->gedcom_repository->gedcomTitle();
237    }
238
239    /**
240     * @return string
241     */
242    public function gedcomCreatedSoftware(): string
243    {
244        return $this->gedcom_repository->gedcomCreatedSoftware();
245    }
246
247    /**
248     * @return string
249     */
250    public function gedcomCreatedVersion(): string
251    {
252        return $this->gedcom_repository->gedcomCreatedVersion();
253    }
254
255    /**
256     * @return string
257     */
258    public function gedcomDate(): string
259    {
260        return $this->gedcom_repository->gedcomDate();
261    }
262
263    /**
264     * @return string
265     */
266    public function gedcomUpdated(): string
267    {
268        return $this->gedcom_repository->gedcomUpdated();
269    }
270
271    /**
272     * @return string
273     */
274    public function gedcomRootId(): string
275    {
276        return $this->gedcom_repository->gedcomRootId();
277    }
278
279    /**
280     * @return string
281     */
282    public function totalRecords(): string
283    {
284        return $this->individual_repository->totalRecords();
285    }
286
287    /**
288     * @return string
289     */
290    public function totalIndividuals(): string
291    {
292        return $this->individual_repository->totalIndividuals();
293    }
294
295    /**
296     * @return string
297     */
298    public function totalIndisWithSources(): string
299    {
300        return $this->individual_repository->totalIndisWithSources();
301    }
302
303    /**
304     * @return string
305     */
306    public function totalIndisWithSourcesPercentage(): string
307    {
308        return $this->individual_repository->totalIndisWithSourcesPercentage();
309    }
310
311    /**
312     * @param string|null $color_from
313     * @param string|null $color_to
314     *
315     * @return string
316     */
317    public function chartIndisWithSources(
318        string|null $color_from = null,
319        string|null $color_to = null
320    ): string {
321        return $this->individual_repository->chartIndisWithSources($color_from, $color_to);
322    }
323
324    /**
325     * @return string
326     */
327    public function totalIndividualsPercentage(): string
328    {
329        return $this->individual_repository->totalIndividualsPercentage();
330    }
331
332    /**
333     * @return string
334     */
335    public function totalFamilies(): string
336    {
337        return $this->individual_repository->totalFamilies();
338    }
339
340    /**
341     * @return string
342     */
343    public function totalFamiliesPercentage(): string
344    {
345        return $this->individual_repository->totalFamiliesPercentage();
346    }
347
348    /**
349     * @return string
350     */
351    public function totalFamsWithSources(): string
352    {
353        return $this->individual_repository->totalFamsWithSources();
354    }
355
356    /**
357     * @return string
358     */
359    public function totalFamsWithSourcesPercentage(): string
360    {
361        return $this->individual_repository->totalFamsWithSourcesPercentage();
362    }
363
364    /**
365     * @param string|null $color_from
366     * @param string|null $color_to
367     *
368     * @return string
369     */
370    public function chartFamsWithSources(
371        string|null $color_from = null,
372        string|null $color_to = null
373    ): string {
374        return $this->individual_repository->chartFamsWithSources($color_from, $color_to);
375    }
376
377    /**
378     * @return string
379     */
380    public function totalSources(): string
381    {
382        return $this->individual_repository->totalSources();
383    }
384
385    /**
386     * @return string
387     */
388    public function totalSourcesPercentage(): string
389    {
390        return $this->individual_repository->totalSourcesPercentage();
391    }
392
393    /**
394     * @return string
395     */
396    public function totalNotes(): string
397    {
398        return $this->individual_repository->totalNotes();
399    }
400
401    /**
402     * @return string
403     */
404    public function totalNotesPercentage(): string
405    {
406        return $this->individual_repository->totalNotesPercentage();
407    }
408
409    /**
410     * @return string
411     */
412    public function totalRepositories(): string
413    {
414        return $this->individual_repository->totalRepositories();
415    }
416
417    /**
418     * @return string
419     */
420    public function totalRepositoriesPercentage(): string
421    {
422        return $this->individual_repository->totalRepositoriesPercentage();
423    }
424
425    /**
426     * @param array<string> ...$params
427     *
428     * @return string
429     */
430    public function totalSurnames(...$params): string
431    {
432        return $this->individual_repository->totalSurnames(...$params);
433    }
434
435    /**
436     * @param array<string> ...$params
437     *
438     * @return string
439     */
440    public function totalGivennames(...$params): string
441    {
442        return $this->individual_repository->totalGivennames(...$params);
443    }
444
445    /**
446     * @param array<string> $events
447     *
448     * @return string
449     */
450    public function totalEvents(array $events = []): string
451    {
452        return $this->event_repository->totalEvents($events);
453    }
454
455    /**
456     * @return string
457     */
458    public function totalEventsBirth(): string
459    {
460        return $this->event_repository->totalEventsBirth();
461    }
462
463    /**
464     * @return string
465     */
466    public function totalBirths(): string
467    {
468        return $this->event_repository->totalBirths();
469    }
470
471    /**
472     * @return string
473     */
474    public function totalEventsDeath(): string
475    {
476        return $this->event_repository->totalEventsDeath();
477    }
478
479    /**
480     * @return string
481     */
482    public function totalDeaths(): string
483    {
484        return $this->event_repository->totalDeaths();
485    }
486
487    /**
488     * @return string
489     */
490    public function totalEventsMarriage(): string
491    {
492        return $this->event_repository->totalEventsMarriage();
493    }
494
495    /**
496     * @return string
497     */
498    public function totalMarriages(): string
499    {
500        return $this->event_repository->totalMarriages();
501    }
502
503    /**
504     * @return string
505     */
506    public function totalEventsDivorce(): string
507    {
508        return $this->event_repository->totalEventsDivorce();
509    }
510
511    /**
512     * @return string
513     */
514    public function totalDivorces(): string
515    {
516        return $this->event_repository->totalDivorces();
517    }
518
519    /**
520     * @return string
521     */
522    public function totalEventsOther(): string
523    {
524        return $this->event_repository->totalEventsOther();
525    }
526
527    /**
528     * @return string
529     */
530    public function totalSexMales(): string
531    {
532        return $this->individual_repository->totalSexMales();
533    }
534
535    /**
536     * @return string
537     */
538    public function totalSexMalesPercentage(): string
539    {
540        return $this->individual_repository->totalSexMalesPercentage();
541    }
542
543    /**
544     * @return string
545     */
546    public function totalSexFemales(): string
547    {
548        return $this->individual_repository->totalSexFemales();
549    }
550
551    /**
552     * @return string
553     */
554    public function totalSexFemalesPercentage(): string
555    {
556        return $this->individual_repository->totalSexFemalesPercentage();
557    }
558
559    /**
560     * @return string
561     */
562    public function totalSexUnknown(): string
563    {
564        return $this->individual_repository->totalSexUnknown();
565    }
566
567    /**
568     * @return string
569     */
570    public function totalSexUnknownPercentage(): string
571    {
572        return $this->individual_repository->totalSexUnknownPercentage();
573    }
574
575    /**
576     * @param string|null $color_female
577     * @param string|null $color_male
578     * @param string|null $color_unknown
579     *
580     * @return string
581     */
582    public function chartSex(
583        string|null $color_female = null,
584        string|null $color_male = null,
585        string|null $color_unknown = null
586    ): string {
587        return $this->individual_repository->chartSex($color_female, $color_male, $color_unknown);
588    }
589
590    /**
591     * @return string
592     */
593    public function totalLiving(): string
594    {
595        return $this->individual_repository->totalLiving();
596    }
597
598    /**
599     * @return string
600     */
601    public function totalLivingPercentage(): string
602    {
603        return $this->individual_repository->totalLivingPercentage();
604    }
605
606    /**
607     * @return string
608     */
609    public function totalDeceased(): string
610    {
611        return $this->individual_repository->totalDeceased();
612    }
613
614    /**
615     * @return string
616     */
617    public function totalDeceasedPercentage(): string
618    {
619        return $this->individual_repository->totalDeceasedPercentage();
620    }
621
622    /**
623     * @param string|null $color_living
624     * @param string|null $color_dead
625     *
626     * @return string
627     */
628    public function chartMortality(string|null $color_living = null, string|null $color_dead = null): string
629    {
630        return $this->individual_repository->chartMortality($color_living, $color_dead);
631    }
632
633    /**
634     * @return string
635     */
636    public function totalMedia(): string
637    {
638        return $this->media_repository->totalMedia();
639    }
640
641    /**
642     * @return string
643     */
644    public function totalMediaAudio(): string
645    {
646        return $this->media_repository->totalMediaAudio();
647    }
648
649    /**
650     * @return string
651     */
652    public function totalMediaBook(): string
653    {
654        return $this->media_repository->totalMediaBook();
655    }
656
657    /**
658     * @return string
659     */
660    public function totalMediaCard(): string
661    {
662        return $this->media_repository->totalMediaCard();
663    }
664
665    /**
666     * @return string
667     */
668    public function totalMediaCertificate(): string
669    {
670        return $this->media_repository->totalMediaCertificate();
671    }
672
673    /**
674     * @return string
675     */
676    public function totalMediaCoatOfArms(): string
677    {
678        return $this->media_repository->totalMediaCoatOfArms();
679    }
680
681    /**
682     * @return string
683     */
684    public function totalMediaDocument(): string
685    {
686        return $this->media_repository->totalMediaDocument();
687    }
688
689    /**
690     * @return string
691     */
692    public function totalMediaElectronic(): string
693    {
694        return $this->media_repository->totalMediaElectronic();
695    }
696
697    /**
698     * @return string
699     */
700    public function totalMediaMagazine(): string
701    {
702        return $this->media_repository->totalMediaMagazine();
703    }
704
705    /**
706     * @return string
707     */
708    public function totalMediaManuscript(): string
709    {
710        return $this->media_repository->totalMediaManuscript();
711    }
712
713    /**
714     * @return string
715     */
716    public function totalMediaMap(): string
717    {
718        return $this->media_repository->totalMediaMap();
719    }
720
721    /**
722     * @return string
723     */
724    public function totalMediaFiche(): string
725    {
726        return $this->media_repository->totalMediaFiche();
727    }
728
729    /**
730     * @return string
731     */
732    public function totalMediaFilm(): string
733    {
734        return $this->media_repository->totalMediaFilm();
735    }
736
737    /**
738     * @return string
739     */
740    public function totalMediaNewspaper(): string
741    {
742        return $this->media_repository->totalMediaNewspaper();
743    }
744
745    /**
746     * @return string
747     */
748    public function totalMediaPainting(): string
749    {
750        return $this->media_repository->totalMediaPainting();
751    }
752
753    /**
754     * @return string
755     */
756    public function totalMediaPhoto(): string
757    {
758        return $this->media_repository->totalMediaPhoto();
759    }
760
761    /**
762     * @return string
763     */
764    public function totalMediaTombstone(): string
765    {
766        return $this->media_repository->totalMediaTombstone();
767    }
768
769    /**
770     * @return string
771     */
772    public function totalMediaVideo(): string
773    {
774        return $this->media_repository->totalMediaVideo();
775    }
776
777    /**
778     * @return string
779     */
780    public function totalMediaOther(): string
781    {
782        return $this->media_repository->totalMediaOther();
783    }
784
785    /**
786     * @return string
787     */
788    public function totalMediaUnknown(): string
789    {
790        return $this->media_repository->totalMediaUnknown();
791    }
792
793    /**
794     * @param string|null $color_from
795     * @param string|null $color_to
796     *
797     * @return string
798     */
799    public function chartMedia(string|null $color_from = null, string|null $color_to = null): string
800    {
801        return $this->media_repository->chartMedia($color_from, $color_to);
802    }
803
804    /**
805     * @return string
806     */
807    public function totalPlaces(): string
808    {
809        return $this->place_repository->totalPlaces();
810    }
811
812    /**
813     * @param string $chart_shows
814     * @param string $chart_type
815     * @param string $surname
816     *
817     * @return string
818     */
819    public function chartDistribution(
820        string $chart_shows = 'world',
821        string $chart_type = '',
822        string $surname = ''
823    ): string {
824        return $this->place_repository->chartDistribution($chart_shows, $chart_type, $surname);
825    }
826
827    /**
828     * @return string
829     */
830    public function commonCountriesList(): string
831    {
832        return $this->place_repository->commonCountriesList();
833    }
834
835    /**
836     * @return string
837     */
838    public function commonBirthPlacesList(): string
839    {
840        return $this->place_repository->commonBirthPlacesList();
841    }
842
843    /**
844     * @return string
845     */
846    public function commonDeathPlacesList(): string
847    {
848        return $this->place_repository->commonDeathPlacesList();
849    }
850
851    /**
852     * @return string
853     */
854    public function commonMarriagePlacesList(): string
855    {
856        return $this->place_repository->commonMarriagePlacesList();
857    }
858
859    /**
860     * @return string
861     */
862    public function firstBirth(): string
863    {
864        return $this->family_dates_repository->firstBirth();
865    }
866
867    /**
868     * @return string
869     */
870    public function firstBirthYear(): string
871    {
872        return $this->family_dates_repository->firstBirthYear();
873    }
874
875    /**
876     * @return string
877     */
878    public function firstBirthName(): string
879    {
880        return $this->family_dates_repository->firstBirthName();
881    }
882
883    /**
884     * @return string
885     */
886    public function firstBirthPlace(): string
887    {
888        return $this->family_dates_repository->firstBirthPlace();
889    }
890
891    /**
892     * @return string
893     */
894    public function lastBirth(): string
895    {
896        return $this->family_dates_repository->lastBirth();
897    }
898
899    /**
900     * @return string
901     */
902    public function lastBirthYear(): string
903    {
904        return $this->family_dates_repository->lastBirthYear();
905    }
906
907    /**
908     * @return string
909     */
910    public function lastBirthName(): string
911    {
912        return $this->family_dates_repository->lastBirthName();
913    }
914
915    /**
916     * @return string
917     */
918    public function lastBirthPlace(): string
919    {
920        return $this->family_dates_repository->lastBirthPlace();
921    }
922
923    /**
924     * @param int $year1
925     * @param int $year2
926     *
927     * @return Builder
928     */
929    public function statsBirthQuery(int $year1 = -1, int $year2 = -1): Builder
930    {
931        return $this->individual_repository->statsBirthQuery($year1, $year2);
932    }
933
934    /**
935     * @param int $year1
936     * @param int $year2
937     *
938     * @return Builder
939     */
940    public function statsBirthBySexQuery(int $year1 = -1, int $year2 = -1): Builder
941    {
942        return $this->individual_repository->statsBirthBySexQuery($year1, $year2);
943    }
944
945    /**
946     * @param string|null $color_from
947     * @param string|null $color_to
948     *
949     * @return string
950     */
951    public function statsBirth(string|null $color_from = null, string|null $color_to = null): string
952    {
953        return $this->individual_repository->statsBirth($color_from, $color_to);
954    }
955
956    /**
957     * @return string
958     */
959    public function firstDeath(): string
960    {
961        return $this->family_dates_repository->firstDeath();
962    }
963
964    /**
965     * @return string
966     */
967    public function firstDeathYear(): string
968    {
969        return $this->family_dates_repository->firstDeathYear();
970    }
971
972    /**
973     * @return string
974     */
975    public function firstDeathName(): string
976    {
977        return $this->family_dates_repository->firstDeathName();
978    }
979
980    /**
981     * @return string
982     */
983    public function firstDeathPlace(): string
984    {
985        return $this->family_dates_repository->firstDeathPlace();
986    }
987
988    /**
989     * @return string
990     */
991    public function lastDeath(): string
992    {
993        return $this->family_dates_repository->lastDeath();
994    }
995
996    /**
997     * @return string
998     */
999    public function lastDeathYear(): string
1000    {
1001        return $this->family_dates_repository->lastDeathYear();
1002    }
1003
1004    /**
1005     * @return string
1006     */
1007    public function lastDeathName(): string
1008    {
1009        return $this->family_dates_repository->lastDeathName();
1010    }
1011
1012    /**
1013     * @return string
1014     */
1015    public function lastDeathPlace(): string
1016    {
1017        return $this->family_dates_repository->lastDeathPlace();
1018    }
1019
1020    /**
1021     * @param int $year1
1022     * @param int $year2
1023     *
1024     * @return Builder
1025     */
1026    public function statsDeathQuery(int $year1 = -1, int $year2 = -1): Builder
1027    {
1028        return $this->individual_repository->statsDeathQuery($year1, $year2);
1029    }
1030
1031    /**
1032     * @param int $year1
1033     * @param int $year2
1034     *
1035     * @return Builder
1036     */
1037    public function statsDeathBySexQuery(int $year1 = -1, int $year2 = -1): Builder
1038    {
1039        return $this->individual_repository->statsDeathBySexQuery($year1, $year2);
1040    }
1041
1042    /**
1043     * @param string|null $color_from
1044     * @param string|null $color_to
1045     *
1046     * @return string
1047     */
1048    public function statsDeath(string|null $color_from = null, string|null $color_to = null): string
1049    {
1050        return $this->individual_repository->statsDeath($color_from, $color_to);
1051    }
1052
1053    /**
1054     * General query on ages.
1055     *
1056     * @param string $related
1057     * @param string $sex
1058     * @param int    $year1
1059     * @param int    $year2
1060     *
1061     * @return array<array<object>>
1062     */
1063    public function statsAgeQuery(string $related = 'BIRT', string $sex = 'BOTH', int $year1 = -1, int $year2 = -1): array
1064    {
1065        return $this->individual_repository->statsAgeQuery($related, $sex, $year1, $year2);
1066    }
1067
1068    /**
1069     * @return string
1070     */
1071    public function statsAge(): string
1072    {
1073        return $this->individual_repository->statsAge();
1074    }
1075
1076    /**
1077     * @return string
1078     */
1079    public function longestLife(): string
1080    {
1081        return $this->individual_repository->longestLife();
1082    }
1083
1084    /**
1085     * @return string
1086     */
1087    public function longestLifeAge(): string
1088    {
1089        return $this->individual_repository->longestLifeAge();
1090    }
1091
1092    /**
1093     * @return string
1094     */
1095    public function longestLifeName(): string
1096    {
1097        return $this->individual_repository->longestLifeName();
1098    }
1099
1100    /**
1101     * @return string
1102     */
1103    public function longestLifeFemale(): string
1104    {
1105        return $this->individual_repository->longestLifeFemale();
1106    }
1107
1108    /**
1109     * @return string
1110     */
1111    public function longestLifeFemaleAge(): string
1112    {
1113        return $this->individual_repository->longestLifeFemaleAge();
1114    }
1115
1116    /**
1117     * @return string
1118     */
1119    public function longestLifeFemaleName(): string
1120    {
1121        return $this->individual_repository->longestLifeFemaleName();
1122    }
1123
1124    /**
1125     * @return string
1126     */
1127    public function longestLifeMale(): string
1128    {
1129        return $this->individual_repository->longestLifeMale();
1130    }
1131
1132    /**
1133     * @return string
1134     */
1135    public function longestLifeMaleAge(): string
1136    {
1137        return $this->individual_repository->longestLifeMaleAge();
1138    }
1139
1140    /**
1141     * @return string
1142     */
1143    public function longestLifeMaleName(): string
1144    {
1145        return $this->individual_repository->longestLifeMaleName();
1146    }
1147
1148    /**
1149     * @param string $total
1150     *
1151     * @return string
1152     */
1153    public function topTenOldest(string $total = '10'): string
1154    {
1155        return $this->individual_repository->topTenOldest((int) $total);
1156    }
1157
1158    /**
1159     * @param string $total
1160     *
1161     * @return string
1162     */
1163    public function topTenOldestList(string $total = '10'): string
1164    {
1165        return $this->individual_repository->topTenOldestList((int) $total);
1166    }
1167
1168    /**
1169     * @param string $total
1170     *
1171     * @return string
1172     */
1173    public function topTenOldestFemale(string $total = '10'): string
1174    {
1175        return $this->individual_repository->topTenOldestFemale((int) $total);
1176    }
1177
1178    /**
1179     * @param string $total
1180     *
1181     * @return string
1182     */
1183    public function topTenOldestFemaleList(string $total = '10'): string
1184    {
1185        return $this->individual_repository->topTenOldestFemaleList((int) $total);
1186    }
1187
1188    /**
1189     * @param string $total
1190     *
1191     * @return string
1192     */
1193    public function topTenOldestMale(string $total = '10'): string
1194    {
1195        return $this->individual_repository->topTenOldestMale((int) $total);
1196    }
1197
1198    /**
1199     * @param string $total
1200     *
1201     * @return string
1202     */
1203    public function topTenOldestMaleList(string $total = '10'): string
1204    {
1205        return $this->individual_repository->topTenOldestMaleList((int) $total);
1206    }
1207
1208    /**
1209     * @param string $total
1210     *
1211     * @return string
1212     */
1213    public function topTenOldestAlive(string $total = '10'): string
1214    {
1215        return $this->individual_repository->topTenOldestAlive((int) $total);
1216    }
1217
1218    /**
1219     * @param string $total
1220     *
1221     * @return string
1222     */
1223    public function topTenOldestListAlive(string $total = '10'): string
1224    {
1225        return $this->individual_repository->topTenOldestListAlive((int) $total);
1226    }
1227
1228    /**
1229     * @param string $total
1230     *
1231     * @return string
1232     */
1233    public function topTenOldestFemaleAlive(string $total = '10'): string
1234    {
1235        return $this->individual_repository->topTenOldestFemaleAlive((int) $total);
1236    }
1237
1238    /**
1239     * @param string $total
1240     *
1241     * @return string
1242     */
1243    public function topTenOldestFemaleListAlive(string $total = '10'): string
1244    {
1245        return $this->individual_repository->topTenOldestFemaleListAlive((int) $total);
1246    }
1247
1248    /**
1249     * @param string $total
1250     *
1251     * @return string
1252     */
1253    public function topTenOldestMaleAlive(string $total = '10'): string
1254    {
1255        return $this->individual_repository->topTenOldestMaleAlive((int) $total);
1256    }
1257
1258    /**
1259     * @param string $total
1260     *
1261     * @return string
1262     */
1263    public function topTenOldestMaleListAlive(string $total = '10'): string
1264    {
1265        return $this->individual_repository->topTenOldestMaleListAlive((int) $total);
1266    }
1267
1268    /**
1269     * @param string $show_years
1270     *
1271     * @return string
1272     */
1273    public function averageLifespan(string $show_years = ''): string
1274    {
1275        return $this->individual_repository->averageLifespan((bool) $show_years);
1276    }
1277
1278    /**
1279     * @param string $show_years
1280     *
1281     * @return string
1282     */
1283    public function averageLifespanFemale(string $show_years = ''): string
1284    {
1285        return $this->individual_repository->averageLifespanFemale((bool) $show_years);
1286    }
1287
1288    /**
1289     * @param string $show_years
1290     *
1291     * @return string
1292     */
1293    public function averageLifespanMale(string $show_years = ''): string
1294    {
1295        return $this->individual_repository->averageLifespanMale((bool) $show_years);
1296    }
1297
1298    /**
1299     * @return string
1300     */
1301    public function firstEvent(): string
1302    {
1303        return $this->event_repository->firstEvent();
1304    }
1305
1306    /**
1307     * @return string
1308     */
1309    public function firstEventYear(): string
1310    {
1311        return $this->event_repository->firstEventYear();
1312    }
1313
1314    /**
1315     * @return string
1316     */
1317    public function firstEventType(): string
1318    {
1319        return $this->event_repository->firstEventType();
1320    }
1321
1322    /**
1323     * @return string
1324     */
1325    public function firstEventName(): string
1326    {
1327        return $this->event_repository->firstEventName();
1328    }
1329
1330    /**
1331     * @return string
1332     */
1333    public function firstEventPlace(): string
1334    {
1335        return $this->event_repository->firstEventPlace();
1336    }
1337
1338    /**
1339     * @return string
1340     */
1341    public function lastEvent(): string
1342    {
1343        return $this->event_repository->lastEvent();
1344    }
1345
1346    /**
1347     * @return string
1348     */
1349    public function lastEventYear(): string
1350    {
1351        return $this->event_repository->lastEventYear();
1352    }
1353
1354    /**
1355     * @return string
1356     */
1357    public function lastEventType(): string
1358    {
1359        return $this->event_repository->lastEventType();
1360    }
1361
1362    /**
1363     * @return string
1364     */
1365    public function lastEventName(): string
1366    {
1367        return $this->event_repository->lastEventName();
1368    }
1369
1370    /**
1371     * @return string
1372     */
1373    public function lastEventPlace(): string
1374    {
1375        return $this->event_repository->lastEventPlace();
1376    }
1377
1378    /**
1379     * @return string
1380     */
1381    public function firstMarriage(): string
1382    {
1383        return $this->family_dates_repository->firstMarriage();
1384    }
1385
1386    /**
1387     * @return string
1388     */
1389    public function firstMarriageYear(): string
1390    {
1391        return $this->family_dates_repository->firstMarriageYear();
1392    }
1393
1394    /**
1395     * @return string
1396     */
1397    public function firstMarriageName(): string
1398    {
1399        return $this->family_dates_repository->firstMarriageName();
1400    }
1401
1402    /**
1403     * @return string
1404     */
1405    public function firstMarriagePlace(): string
1406    {
1407        return $this->family_dates_repository->firstMarriagePlace();
1408    }
1409
1410    /**
1411     * @return string
1412     */
1413    public function lastMarriage(): string
1414    {
1415        return $this->family_dates_repository->lastMarriage();
1416    }
1417
1418    /**
1419     * @return string
1420     */
1421    public function lastMarriageYear(): string
1422    {
1423        return $this->family_dates_repository->lastMarriageYear();
1424    }
1425
1426    /**
1427     * @return string
1428     */
1429    public function lastMarriageName(): string
1430    {
1431        return $this->family_dates_repository->lastMarriageName();
1432    }
1433
1434    /**
1435     * @return string
1436     */
1437    public function lastMarriagePlace(): string
1438    {
1439        return $this->family_dates_repository->lastMarriagePlace();
1440    }
1441
1442    /**
1443     * @param int $year1
1444     * @param int $year2
1445     *
1446     * @return Builder
1447     */
1448    public function statsMarriageQuery(int $year1 = -1, int $year2 = -1): Builder
1449    {
1450        return $this->family_repository->statsMarriageQuery($year1, $year2);
1451    }
1452
1453    /**
1454     * @param int $year1
1455     * @param int $year2
1456     *
1457     * @return Builder
1458     */
1459    public function statsFirstMarriageQuery(int $year1 = -1, int $year2 = -1): Builder
1460    {
1461        return $this->family_repository->statsFirstMarriageQuery($year1, $year2);
1462    }
1463
1464    /**
1465     * @param string|null $color_from
1466     * @param string|null $color_to
1467     *
1468     * @return string
1469     */
1470    public function statsMarr(string|null $color_from = null, string|null $color_to = null): string
1471    {
1472        return $this->family_repository->statsMarr($color_from, $color_to);
1473    }
1474
1475    /**
1476     * @return string
1477     */
1478    public function firstDivorce(): string
1479    {
1480        return $this->family_dates_repository->firstDivorce();
1481    }
1482
1483    /**
1484     * @return string
1485     */
1486    public function firstDivorceYear(): string
1487    {
1488        return $this->family_dates_repository->firstDivorceYear();
1489    }
1490
1491    /**
1492     * @return string
1493     */
1494    public function firstDivorceName(): string
1495    {
1496        return $this->family_dates_repository->firstDivorceName();
1497    }
1498
1499    /**
1500     * @return string
1501     */
1502    public function firstDivorcePlace(): string
1503    {
1504        return $this->family_dates_repository->firstDivorcePlace();
1505    }
1506
1507    /**
1508     * @return string
1509     */
1510    public function lastDivorce(): string
1511    {
1512        return $this->family_dates_repository->lastDivorce();
1513    }
1514
1515    /**
1516     * @return string
1517     */
1518    public function lastDivorceYear(): string
1519    {
1520        return $this->family_dates_repository->lastDivorceYear();
1521    }
1522
1523    /**
1524     * @return string
1525     */
1526    public function lastDivorceName(): string
1527    {
1528        return $this->family_dates_repository->lastDivorceName();
1529    }
1530
1531    /**
1532     * @return string
1533     */
1534    public function lastDivorcePlace(): string
1535    {
1536        return $this->family_dates_repository->lastDivorcePlace();
1537    }
1538
1539    /**
1540     * @param string|null $color_from
1541     * @param string|null $color_to
1542     *
1543     * @return string
1544     */
1545    public function statsDiv(string|null $color_from = null, string|null $color_to = null): string
1546    {
1547        return $this->family_repository->statsDiv($color_from, $color_to);
1548    }
1549
1550    /**
1551     * @return string
1552     */
1553    public function youngestMarriageFemale(): string
1554    {
1555        return $this->family_repository->youngestMarriageFemale();
1556    }
1557
1558    /**
1559     * @return string
1560     */
1561    public function youngestMarriageFemaleName(): string
1562    {
1563        return $this->family_repository->youngestMarriageFemaleName();
1564    }
1565
1566    /**
1567     * @param string $show_years
1568     *
1569     * @return string
1570     */
1571    public function youngestMarriageFemaleAge(string $show_years = ''): string
1572    {
1573        return $this->family_repository->youngestMarriageFemaleAge($show_years);
1574    }
1575
1576    /**
1577     * @return string
1578     */
1579    public function oldestMarriageFemale(): string
1580    {
1581        return $this->family_repository->oldestMarriageFemale();
1582    }
1583
1584    /**
1585     * @return string
1586     */
1587    public function oldestMarriageFemaleName(): string
1588    {
1589        return $this->family_repository->oldestMarriageFemaleName();
1590    }
1591
1592    /**
1593     * @param string $show_years
1594     *
1595     * @return string
1596     */
1597    public function oldestMarriageFemaleAge(string $show_years = ''): string
1598    {
1599        return $this->family_repository->oldestMarriageFemaleAge($show_years);
1600    }
1601
1602    /**
1603     * @return string
1604     */
1605    public function youngestMarriageMale(): string
1606    {
1607        return $this->family_repository->youngestMarriageMale();
1608    }
1609
1610    /**
1611     * @return string
1612     */
1613    public function youngestMarriageMaleName(): string
1614    {
1615        return $this->family_repository->youngestMarriageMaleName();
1616    }
1617
1618    /**
1619     * @param string $show_years
1620     *
1621     * @return string
1622     */
1623    public function youngestMarriageMaleAge(string $show_years = ''): string
1624    {
1625        return $this->family_repository->youngestMarriageMaleAge($show_years);
1626    }
1627
1628    /**
1629     * @return string
1630     */
1631    public function oldestMarriageMale(): string
1632    {
1633        return $this->family_repository->oldestMarriageMale();
1634    }
1635
1636    /**
1637     * @return string
1638     */
1639    public function oldestMarriageMaleName(): string
1640    {
1641        return $this->family_repository->oldestMarriageMaleName();
1642    }
1643
1644    /**
1645     * @param string $show_years
1646     *
1647     * @return string
1648     */
1649    public function oldestMarriageMaleAge(string $show_years = ''): string
1650    {
1651        return $this->family_repository->oldestMarriageMaleAge($show_years);
1652    }
1653
1654    /**
1655     * @param string $sex
1656     * @param int    $year1
1657     * @param int    $year2
1658     *
1659     * @return array<object>
1660     */
1661    public function statsMarrAgeQuery(string $sex, int $year1 = -1, int $year2 = -1): array
1662    {
1663        return $this->family_repository->statsMarrAgeQuery($sex, $year1, $year2);
1664    }
1665
1666    /**
1667     * @return string
1668     */
1669    public function statsMarrAge(): string
1670    {
1671        return $this->family_repository->statsMarrAge();
1672    }
1673
1674    /**
1675     * @param string $total
1676     *
1677     * @return string
1678     */
1679    public function ageBetweenSpousesMF(string $total = '10'): string
1680    {
1681        return $this->family_repository->ageBetweenSpousesMF((int) $total);
1682    }
1683
1684    /**
1685     * @param string $total
1686     *
1687     * @return string
1688     */
1689    public function ageBetweenSpousesMFList(string $total = '10'): string
1690    {
1691        return $this->family_repository->ageBetweenSpousesMFList((int) $total);
1692    }
1693
1694    /**
1695     * @param string $total
1696     *
1697     * @return string
1698     */
1699    public function ageBetweenSpousesFM(string $total = '10'): string
1700    {
1701        return $this->family_repository->ageBetweenSpousesFM((int) $total);
1702    }
1703
1704    /**
1705     * @param string $total
1706     *
1707     * @return string
1708     */
1709    public function ageBetweenSpousesFMList(string $total = '10'): string
1710    {
1711        return $this->family_repository->ageBetweenSpousesFMList((int) $total);
1712    }
1713
1714    /**
1715     * @return string
1716     */
1717    public function topAgeOfMarriageFamily(): string
1718    {
1719        return $this->family_repository->topAgeOfMarriageFamily();
1720    }
1721
1722    /**
1723     * @return string
1724     */
1725    public function topAgeOfMarriage(): string
1726    {
1727        return $this->family_repository->topAgeOfMarriage();
1728    }
1729
1730    /**
1731     * @param string $total
1732     *
1733     * @return string
1734     */
1735    public function topAgeOfMarriageFamilies(string $total = '10'): string
1736    {
1737        return $this->family_repository->topAgeOfMarriageFamilies((int) $total);
1738    }
1739
1740    /**
1741     * @param string $total
1742     *
1743     * @return string
1744     */
1745    public function topAgeOfMarriageFamiliesList(string $total = '10'): string
1746    {
1747        return $this->family_repository->topAgeOfMarriageFamiliesList((int) $total);
1748    }
1749
1750    /**
1751     * @return string
1752     */
1753    public function minAgeOfMarriageFamily(): string
1754    {
1755        return $this->family_repository->minAgeOfMarriageFamily();
1756    }
1757
1758    /**
1759     * @return string
1760     */
1761    public function minAgeOfMarriage(): string
1762    {
1763        return $this->family_repository->minAgeOfMarriage();
1764    }
1765
1766    /**
1767     * @param string $total
1768     *
1769     * @return string
1770     */
1771    public function minAgeOfMarriageFamilies(string $total = '10'): string
1772    {
1773        return $this->family_repository->minAgeOfMarriageFamilies((int) $total);
1774    }
1775
1776    /**
1777     * @param string $total
1778     *
1779     * @return string
1780     */
1781    public function minAgeOfMarriageFamiliesList(string $total = '10'): string
1782    {
1783        return $this->family_repository->minAgeOfMarriageFamiliesList((int) $total);
1784    }
1785
1786    /**
1787     * @return string
1788     */
1789    public function youngestMother(): string
1790    {
1791        return $this->family_repository->youngestMother();
1792    }
1793
1794    /**
1795     * @return string
1796     */
1797    public function youngestMotherName(): string
1798    {
1799        return $this->family_repository->youngestMotherName();
1800    }
1801
1802    /**
1803     * @param string $show_years
1804     *
1805     * @return string
1806     */
1807    public function youngestMotherAge(string $show_years = ''): string
1808    {
1809        return $this->family_repository->youngestMotherAge($show_years);
1810    }
1811
1812    /**
1813     * @return string
1814     */
1815    public function oldestMother(): string
1816    {
1817        return $this->family_repository->oldestMother();
1818    }
1819
1820    /**
1821     * @return string
1822     */
1823    public function oldestMotherName(): string
1824    {
1825        return $this->family_repository->oldestMotherName();
1826    }
1827
1828    /**
1829     * @param string $show_years
1830     *
1831     * @return string
1832     */
1833    public function oldestMotherAge(string $show_years = ''): string
1834    {
1835        return $this->family_repository->oldestMotherAge($show_years);
1836    }
1837
1838    /**
1839     * @return string
1840     */
1841    public function youngestFather(): string
1842    {
1843        return $this->family_repository->youngestFather();
1844    }
1845
1846    /**
1847     * @return string
1848     */
1849    public function youngestFatherName(): string
1850    {
1851        return $this->family_repository->youngestFatherName();
1852    }
1853
1854    /**
1855     * @param string $show_years
1856     *
1857     * @return string
1858     */
1859    public function youngestFatherAge(string $show_years = ''): string
1860    {
1861        return $this->family_repository->youngestFatherAge($show_years);
1862    }
1863
1864    /**
1865     * @return string
1866     */
1867    public function oldestFather(): string
1868    {
1869        return $this->family_repository->oldestFather();
1870    }
1871
1872    /**
1873     * @return string
1874     */
1875    public function oldestFatherName(): string
1876    {
1877        return $this->family_repository->oldestFatherName();
1878    }
1879
1880    /**
1881     * @param string $show_years
1882     *
1883     * @return string
1884     */
1885    public function oldestFatherAge(string $show_years = ''): string
1886    {
1887        return $this->family_repository->oldestFatherAge($show_years);
1888    }
1889
1890    /**
1891     * @return string
1892     */
1893    public function totalMarriedMales(): string
1894    {
1895        return $this->family_repository->totalMarriedMales();
1896    }
1897
1898    /**
1899     * @return string
1900     */
1901    public function totalMarriedFemales(): string
1902    {
1903        return $this->family_repository->totalMarriedFemales();
1904    }
1905
1906    /**
1907     * @param int $year1
1908     * @param int $year2
1909     *
1910     * @return Builder
1911     */
1912    public function monthFirstChildQuery(int $year1 = -1, int $year2 = -1): Builder
1913    {
1914        return $this->family_repository->monthFirstChildQuery($year1, $year2);
1915    }
1916
1917    /**
1918     * @param int $year1
1919     * @param int $year2
1920     *
1921     * @return Builder
1922     */
1923    public function monthFirstChildBySexQuery(int $year1 = -1, int $year2 = -1): Builder
1924    {
1925        return $this->family_repository->monthFirstChildBySexQuery($year1, $year2);
1926    }
1927
1928    /**
1929     * @return string
1930     */
1931    public function largestFamily(): string
1932    {
1933        return $this->family_repository->largestFamily();
1934    }
1935
1936    /**
1937     * @return string
1938     */
1939    public function largestFamilySize(): string
1940    {
1941        return $this->family_repository->largestFamilySize();
1942    }
1943
1944    /**
1945     * @return string
1946     */
1947    public function largestFamilyName(): string
1948    {
1949        return $this->family_repository->largestFamilyName();
1950    }
1951
1952    /**
1953     * @param string $total
1954     *
1955     * @return string
1956     */
1957    public function topTenLargestFamily(string $total = '10'): string
1958    {
1959        return $this->family_repository->topTenLargestFamily((int) $total);
1960    }
1961
1962    /**
1963     * @param string $total
1964     *
1965     * @return string
1966     */
1967    public function topTenLargestFamilyList(string $total = '10'): string
1968    {
1969        return $this->family_repository->topTenLargestFamilyList((int) $total);
1970    }
1971
1972    /**
1973     * @param string|null $color_from
1974     * @param string|null $color_to
1975     * @param string      $total
1976     *
1977     * @return string
1978     */
1979    public function chartLargestFamilies(
1980        string|null $color_from = null,
1981        string|null $color_to = null,
1982        string $total = '10'
1983    ): string {
1984        return $this->family_repository->chartLargestFamilies($color_from, $color_to, (int) $total);
1985    }
1986
1987    /**
1988     * @return string
1989     */
1990    public function totalChildren(): string
1991    {
1992        return $this->family_repository->totalChildren();
1993    }
1994
1995    /**
1996     * @return string
1997     */
1998    public function averageChildren(): string
1999    {
2000        return $this->family_repository->averageChildren();
2001    }
2002
2003    /**
2004     * @param int $year1
2005     * @param int $year2
2006     *
2007     * @return array<object>
2008     */
2009    public function statsChildrenQuery(int $year1 = -1, int $year2 = -1): array
2010    {
2011        return $this->family_repository->statsChildrenQuery($year1, $year2);
2012    }
2013
2014    /**
2015     * @return string
2016     */
2017    public function statsChildren(): string
2018    {
2019        return $this->family_repository->statsChildren();
2020    }
2021
2022    /**
2023     * @param string $total
2024     *
2025     * @return string
2026     */
2027    public function topAgeBetweenSiblingsName(string $total = '10'): string
2028    {
2029        return $this->family_repository->topAgeBetweenSiblingsName((int) $total);
2030    }
2031
2032    /**
2033     * @param string $total
2034     *
2035     * @return string
2036     */
2037    public function topAgeBetweenSiblings(string $total = '10'): string
2038    {
2039        return $this->family_repository->topAgeBetweenSiblings((int) $total);
2040    }
2041
2042    /**
2043     * @param string $total
2044     *
2045     * @return string
2046     */
2047    public function topAgeBetweenSiblingsFullName(string $total = '10'): string
2048    {
2049        return $this->family_repository->topAgeBetweenSiblingsFullName((int) $total);
2050    }
2051
2052    /**
2053     * @param string $total
2054     * @param string $one
2055     *
2056     * @return string
2057     */
2058    public function topAgeBetweenSiblingsList(string $total = '10', string $one = ''): string
2059    {
2060        return $this->family_repository->topAgeBetweenSiblingsList((int) $total, $one);
2061    }
2062
2063    /**
2064     * @return string
2065     */
2066    public function noChildrenFamilies(): string
2067    {
2068        return $this->family_repository->noChildrenFamilies();
2069    }
2070
2071    /**
2072     * @param string $type
2073     *
2074     * @return string
2075     */
2076    public function noChildrenFamiliesList(string $type = 'list'): string
2077    {
2078        return $this->family_repository->noChildrenFamiliesList($type);
2079    }
2080
2081    /**
2082     * @param string $year1
2083     * @param string $year2
2084     *
2085     * @return string
2086     */
2087    public function chartNoChildrenFamilies(
2088        string $year1 = '-1',
2089        string $year2 = '-1'
2090    ): string {
2091        return $this->family_repository->chartNoChildrenFamilies((int) $year1, (int) $year2);
2092    }
2093
2094    /**
2095     * @param string $total
2096     *
2097     * @return string
2098     */
2099    public function topTenLargestGrandFamily(string $total = '10'): string
2100    {
2101        return $this->family_repository->topTenLargestGrandFamily((int) $total);
2102    }
2103
2104    /**
2105     * @param string $total
2106     *
2107     * @return string
2108     */
2109    public function topTenLargestGrandFamilyList(string $total = '10'): string
2110    {
2111        return $this->family_repository->topTenLargestGrandFamilyList((int) $total);
2112    }
2113
2114    /**
2115     * @return string
2116     */
2117    public function getCommonSurname(): string
2118    {
2119        return $this->individual_repository->getCommonSurname();
2120    }
2121
2122    /**
2123     * @param string $threshold
2124     * @param string $number_of_surnames
2125     * @param string $sorting
2126     *
2127     * @return string
2128     */
2129    public function commonSurnames(
2130        string $threshold = '1',
2131        string $number_of_surnames = '10',
2132        string $sorting = 'alpha'
2133    ): string {
2134        return $this->individual_repository->commonSurnames((int) $threshold, (int) $number_of_surnames, $sorting);
2135    }
2136
2137    /**
2138     * @param string $threshold
2139     * @param string $number_of_surnames
2140     * @param string $sorting
2141     *
2142     * @return string
2143     */
2144    public function commonSurnamesTotals(
2145        string $threshold = '1',
2146        string $number_of_surnames = '10',
2147        string $sorting = 'count'
2148    ): string {
2149        return $this->individual_repository->commonSurnamesTotals((int) $threshold, (int) $number_of_surnames, $sorting);
2150    }
2151
2152    /**
2153     * @param string $threshold
2154     * @param string $number_of_surnames
2155     * @param string $sorting
2156     *
2157     * @return string
2158     */
2159    public function commonSurnamesList(
2160        string $threshold = '1',
2161        string $number_of_surnames = '10',
2162        string $sorting = 'alpha'
2163    ): string {
2164        return $this->individual_repository->commonSurnamesList((int) $threshold, (int) $number_of_surnames, $sorting);
2165    }
2166
2167    /**
2168     * @param string $threshold
2169     * @param string $number_of_surnames
2170     * @param string $sorting
2171     *
2172     * @return string
2173     */
2174    public function commonSurnamesListTotals(
2175        string $threshold = '1',
2176        string $number_of_surnames = '10',
2177        string $sorting = 'count'
2178    ): string {
2179        return $this->individual_repository
2180            ->commonSurnamesListTotals((int) $threshold, (int) $number_of_surnames, $sorting);
2181    }
2182
2183    /**
2184     * @param string|null $color_from
2185     * @param string|null $color_to
2186     * @param string      $number_of_surnames
2187     *
2188     * @return string
2189     */
2190    public function chartCommonSurnames(
2191        string|null $color_from = null,
2192        string|null $color_to = null,
2193        string $number_of_surnames = '10'
2194    ): string {
2195        return $this->individual_repository
2196            ->chartCommonSurnames($color_from, $color_to, (int) $number_of_surnames);
2197    }
2198
2199    /**
2200     * @param string $threshold
2201     * @param string $maxtoshow
2202     *
2203     * @return string
2204     */
2205    public function commonGiven(string $threshold = '1', string $maxtoshow = '10'): string
2206    {
2207        return $this->individual_repository->commonGiven((int) $threshold, (int) $maxtoshow);
2208    }
2209
2210    /**
2211     * @param string $threshold
2212     * @param string $maxtoshow
2213     *
2214     * @return string
2215     */
2216    public function commonGivenTotals(string $threshold = '1', string $maxtoshow = '10'): string
2217    {
2218        return $this->individual_repository->commonGivenTotals((int) $threshold, (int) $maxtoshow);
2219    }
2220
2221    /**
2222     * @param string $threshold
2223     * @param string $maxtoshow
2224     *
2225     * @return string
2226     */
2227    public function commonGivenList(string $threshold = '1', string $maxtoshow = '10'): string
2228    {
2229        return $this->individual_repository->commonGivenList((int) $threshold, (int) $maxtoshow);
2230    }
2231
2232    /**
2233     * @param string $threshold
2234     * @param string $maxtoshow
2235     *
2236     * @return string
2237     */
2238    public function commonGivenListTotals(string $threshold = '1', string $maxtoshow = '10'): string
2239    {
2240        return $this->individual_repository->commonGivenListTotals((int) $threshold, (int) $maxtoshow);
2241    }
2242
2243    /**
2244     * @param string $threshold
2245     * @param string $maxtoshow
2246     *
2247     * @return string
2248     */
2249    public function commonGivenTable(string $threshold = '1', string $maxtoshow = '10'): string
2250    {
2251        return $this->individual_repository->commonGivenTable((int) $threshold, (int) $maxtoshow);
2252    }
2253
2254    /**
2255     * @param string $threshold
2256     * @param string $maxtoshow
2257     *
2258     * @return string
2259     */
2260    public function commonGivenFemale(string $threshold = '1', string $maxtoshow = '10'): string
2261    {
2262        return $this->individual_repository->commonGivenFemale((int) $threshold, (int) $maxtoshow);
2263    }
2264
2265    /**
2266     * @param string $threshold
2267     * @param string $maxtoshow
2268     *
2269     * @return string
2270     */
2271    public function commonGivenFemaleTotals(string $threshold = '1', string $maxtoshow = '10'): string
2272    {
2273        return $this->individual_repository->commonGivenFemaleTotals((int) $threshold, (int) $maxtoshow);
2274    }
2275
2276    /**
2277     * @param string $threshold
2278     * @param string $maxtoshow
2279     *
2280     * @return string
2281     */
2282    public function commonGivenFemaleList(string $threshold = '1', string $maxtoshow = '10'): string
2283    {
2284        return $this->individual_repository->commonGivenFemaleList((int) $threshold, (int) $maxtoshow);
2285    }
2286
2287    /**
2288     * @param string $threshold
2289     * @param string $maxtoshow
2290     *
2291     * @return string
2292     */
2293    public function commonGivenFemaleListTotals(string $threshold = '1', string $maxtoshow = '10'): string
2294    {
2295        return $this->individual_repository->commonGivenFemaleListTotals((int) $threshold, (int) $maxtoshow);
2296    }
2297
2298    /**
2299     * @param string $threshold
2300     * @param string $maxtoshow
2301     *
2302     * @return string
2303     */
2304    public function commonGivenFemaleTable(string $threshold = '1', string $maxtoshow = '10'): string
2305    {
2306        return $this->individual_repository->commonGivenFemaleTable((int) $threshold, (int) $maxtoshow);
2307    }
2308
2309    /**
2310     * @param string $threshold
2311     * @param string $maxtoshow
2312     *
2313     * @return string
2314     */
2315    public function commonGivenMale(string $threshold = '1', string $maxtoshow = '10'): string
2316    {
2317        return $this->individual_repository->commonGivenMale((int) $threshold, (int) $maxtoshow);
2318    }
2319
2320    /**
2321     * @param string $threshold
2322     * @param string $maxtoshow
2323     *
2324     * @return string
2325     */
2326    public function commonGivenMaleTotals(string $threshold = '1', string $maxtoshow = '10'): string
2327    {
2328        return $this->individual_repository->commonGivenMaleTotals((int) $threshold, (int) $maxtoshow);
2329    }
2330
2331    /**
2332     * @param string $threshold
2333     * @param string $maxtoshow
2334     *
2335     * @return string
2336     */
2337    public function commonGivenMaleList(string $threshold = '1', string $maxtoshow = '10'): string
2338    {
2339        return $this->individual_repository->commonGivenMaleList((int) $threshold, (int) $maxtoshow);
2340    }
2341
2342    /**
2343     * @param string $threshold
2344     * @param string $maxtoshow
2345     *
2346     * @return string
2347     */
2348    public function commonGivenMaleListTotals(string $threshold = '1', string $maxtoshow = '10'): string
2349    {
2350        return $this->individual_repository->commonGivenMaleListTotals((int) $threshold, (int) $maxtoshow);
2351    }
2352
2353    /**
2354     * @param string $threshold
2355     * @param string $maxtoshow
2356     *
2357     * @return string
2358     */
2359    public function commonGivenMaleTable(string $threshold = '1', string $maxtoshow = '10'): string
2360    {
2361        return $this->individual_repository->commonGivenMaleTable((int) $threshold, (int) $maxtoshow);
2362    }
2363
2364    /**
2365     * @param string $threshold
2366     * @param string $maxtoshow
2367     *
2368     * @return string
2369     */
2370    public function commonGivenUnknown(string $threshold = '1', string $maxtoshow = '10'): string
2371    {
2372        return $this->individual_repository->commonGivenUnknown((int) $threshold, (int) $maxtoshow);
2373    }
2374
2375    /**
2376     * @param string $threshold
2377     * @param string $maxtoshow
2378     *
2379     * @return string
2380     */
2381    public function commonGivenUnknownTotals(string $threshold = '1', string $maxtoshow = '10'): string
2382    {
2383        return $this->individual_repository->commonGivenUnknownTotals((int) $threshold, (int) $maxtoshow);
2384    }
2385
2386    /**
2387     * @param string $threshold
2388     * @param string $maxtoshow
2389     *
2390     * @return string
2391     */
2392    public function commonGivenUnknownList(string $threshold = '1', string $maxtoshow = '10'): string
2393    {
2394        return $this->individual_repository->commonGivenUnknownList((int) $threshold, (int) $maxtoshow);
2395    }
2396
2397    /**
2398     * @param string $threshold
2399     * @param string $maxtoshow
2400     *
2401     * @return string
2402     */
2403    public function commonGivenUnknownListTotals(string $threshold = '1', string $maxtoshow = '10'): string
2404    {
2405        return $this->individual_repository->commonGivenUnknownListTotals((int) $threshold, (int) $maxtoshow);
2406    }
2407
2408    /**
2409     * @param string $threshold
2410     * @param string $maxtoshow
2411     *
2412     * @return string
2413     */
2414    public function commonGivenUnknownTable(string $threshold = '1', string $maxtoshow = '10'): string
2415    {
2416        return $this->individual_repository->commonGivenUnknownTable((int) $threshold, (int) $maxtoshow);
2417    }
2418
2419    /**
2420     * @param string|null $color_from
2421     * @param string|null $color_to
2422     * @param string      $maxtoshow
2423     *
2424     * @return string
2425     */
2426    public function chartCommonGiven(
2427        string|null $color_from = null,
2428        string|null $color_to = null,
2429        string $maxtoshow = '7'
2430    ): string {
2431        return $this->individual_repository->chartCommonGiven($color_from, $color_to, (int) $maxtoshow);
2432    }
2433
2434    /**
2435     * @return string
2436     */
2437    public function usersLoggedIn(): string
2438    {
2439        return $this->user_repository->usersLoggedIn();
2440    }
2441
2442    /**
2443     * @return string
2444     */
2445    public function usersLoggedInList(): string
2446    {
2447        return $this->user_repository->usersLoggedInList();
2448    }
2449
2450    /**
2451     * @return int
2452     */
2453    public function usersLoggedInTotal(): int
2454    {
2455        return $this->user_repository->usersLoggedInTotal();
2456    }
2457
2458    /**
2459     * @return int
2460     */
2461    public function usersLoggedInTotalAnon(): int
2462    {
2463        return $this->user_repository->usersLoggedInTotalAnon();
2464    }
2465
2466    /**
2467     * @return int
2468     */
2469    public function usersLoggedInTotalVisible(): int
2470    {
2471        return $this->user_repository->usersLoggedInTotalVisible();
2472    }
2473
2474    /**
2475     * @return string
2476     */
2477    public function userId(): string
2478    {
2479        return $this->user_repository->userId();
2480    }
2481
2482    /**
2483     * @param string $visitor_text
2484     *
2485     * @return string
2486     */
2487    public function userName(string $visitor_text = ''): string
2488    {
2489        return $this->user_repository->userName($visitor_text);
2490    }
2491
2492    /**
2493     * @return string
2494     */
2495    public function userFullName(): string
2496    {
2497        return $this->user_repository->userFullName();
2498    }
2499
2500    /**
2501     * @return string
2502     */
2503    public function totalUsers(): string
2504    {
2505        return $this->user_repository->totalUsers();
2506    }
2507
2508    /**
2509     * @return string
2510     */
2511    public function totalAdmins(): string
2512    {
2513        return $this->user_repository->totalAdmins();
2514    }
2515
2516    /**
2517     * @return string
2518     */
2519    public function totalNonAdmins(): string
2520    {
2521        return $this->user_repository->totalNonAdmins();
2522    }
2523
2524    /**
2525     * @return string
2526     */
2527    public function latestUserId(): string
2528    {
2529        return $this->latest_user_repository->latestUserId();
2530    }
2531
2532    /**
2533     * @return string
2534     */
2535    public function latestUserName(): string
2536    {
2537        return $this->latest_user_repository->latestUserName();
2538    }
2539
2540    /**
2541     * @return string
2542     */
2543    public function latestUserFullName(): string
2544    {
2545        return $this->latest_user_repository->latestUserFullName();
2546    }
2547
2548    /**
2549     * @param string|null $format
2550     *
2551     * @return string
2552     */
2553    public function latestUserRegDate(string|null $format = null): string
2554    {
2555        return $this->latest_user_repository->latestUserRegDate($format);
2556    }
2557
2558    /**
2559     * @param string|null $format
2560     *
2561     * @return string
2562     */
2563    public function latestUserRegTime(string|null $format = null): string
2564    {
2565        return $this->latest_user_repository->latestUserRegTime($format);
2566    }
2567
2568    /**
2569     * @param string|null $yes
2570     * @param string|null $no
2571     *
2572     * @return string
2573     */
2574    public function latestUserLoggedin(string|null $yes = null, string|null $no = null): string
2575    {
2576        return $this->latest_user_repository->latestUserLoggedin($yes, $no);
2577    }
2578
2579    /**
2580     * @return string
2581     */
2582    public function contactWebmaster(): string
2583    {
2584        return $this->contact_repository->contactWebmaster();
2585    }
2586
2587    /**
2588     * @return string
2589     */
2590    public function contactGedcom(): string
2591    {
2592        return $this->contact_repository->contactGedcom();
2593    }
2594
2595    /**
2596     * @return string
2597     */
2598    public function serverDate(): string
2599    {
2600        return $this->server_repository->serverDate();
2601    }
2602
2603    /**
2604     * @return string
2605     */
2606    public function serverTime(): string
2607    {
2608        return $this->server_repository->serverTime();
2609    }
2610
2611    /**
2612     * @return string
2613     */
2614    public function serverTime24(): string
2615    {
2616        return $this->server_repository->serverTime24();
2617    }
2618
2619    /**
2620     * What is the timezone of the server.
2621     *
2622     * @return string
2623     */
2624    public function serverTimezone(): string
2625    {
2626        return $this->server_repository->serverTimezone();
2627    }
2628
2629    /**
2630     * @return string
2631     */
2632    public function browserDate(): string
2633    {
2634        return $this->browser_repository->browserDate();
2635    }
2636
2637    /**
2638     * @return string
2639     */
2640    public function browserTime(): string
2641    {
2642        return $this->browser_repository->browserTime();
2643    }
2644
2645    /**
2646     * @return string
2647     */
2648    public function browserTimezone(): string
2649    {
2650        return $this->browser_repository->browserTimezone();
2651    }
2652
2653    /**
2654     * @param string $page_parameter
2655     *
2656     * @return string
2657     */
2658    public function hitCount(string $page_parameter = ''): string
2659    {
2660        return $this->hit_count_repository->hitCount($page_parameter);
2661    }
2662
2663    /**
2664     * @param string $page_parameter
2665     *
2666     * @return string
2667     */
2668    public function hitCountUser(string $page_parameter = ''): string
2669    {
2670        return $this->hit_count_repository->hitCountUser($page_parameter);
2671    }
2672
2673    /**
2674     * @param string $page_parameter
2675     *
2676     * @return string
2677     */
2678    public function hitCountIndi(string $page_parameter = ''): string
2679    {
2680        return $this->hit_count_repository->hitCountIndi($page_parameter);
2681    }
2682
2683    /**
2684     * @param string $page_parameter
2685     *
2686     * @return string
2687     */
2688    public function hitCountFam(string $page_parameter = ''): string
2689    {
2690        return $this->hit_count_repository->hitCountFam($page_parameter);
2691    }
2692
2693    /**
2694     * @param string $page_parameter
2695     *
2696     * @return string
2697     */
2698    public function hitCountSour(string $page_parameter = ''): string
2699    {
2700        return $this->hit_count_repository->hitCountSour($page_parameter);
2701    }
2702
2703    /**
2704     * @param string $page_parameter
2705     *
2706     * @return string
2707     */
2708    public function hitCountRepo(string $page_parameter = ''): string
2709    {
2710        return $this->hit_count_repository->hitCountRepo($page_parameter);
2711    }
2712
2713    /**
2714     * @param string $page_parameter
2715     *
2716     * @return string
2717     */
2718    public function hitCountNote(string $page_parameter = ''): string
2719    {
2720        return $this->hit_count_repository->hitCountNote($page_parameter);
2721    }
2722
2723    /**
2724     * @param string $page_parameter
2725     *
2726     * @return string
2727     */
2728    public function hitCountObje(string $page_parameter = ''): string
2729    {
2730        return $this->hit_count_repository->hitCountObje($page_parameter);
2731    }
2732
2733    /**
2734     * @return string
2735     */
2736    public function gedcomFavorites(): string
2737    {
2738        return $this->favorites_repository->gedcomFavorites();
2739    }
2740
2741    /**
2742     * @return string
2743     */
2744    public function userFavorites(): string
2745    {
2746        return $this->favorites_repository->userFavorites();
2747    }
2748
2749    /**
2750     * @return string
2751     */
2752    public function totalGedcomFavorites(): string
2753    {
2754        return $this->favorites_repository->totalGedcomFavorites();
2755    }
2756
2757    /**
2758     * @return string
2759     */
2760    public function totalUserFavorites(): string
2761    {
2762        return $this->favorites_repository->totalUserFavorites();
2763    }
2764
2765    /**
2766     * @return string
2767     */
2768    public function totalUserMessages(): string
2769    {
2770        return $this->message_repository->totalUserMessages();
2771    }
2772
2773    /**
2774     * @return string
2775     */
2776    public function totalUserJournal(): string
2777    {
2778        return $this->news_repository->totalUserJournal();
2779    }
2780
2781    /**
2782     * @return string
2783     */
2784    public function totalGedcomNews(): string
2785    {
2786        return $this->news_repository->totalGedcomNews();
2787    }
2788
2789    /**
2790     * Create any of the other blocks.
2791     * Use as #callBlock:block_name#
2792     *
2793     * @param string $block
2794     * @param string ...$params
2795     *
2796     * @return string|null
2797     */
2798    public function callBlock(string $block = '', ...$params): string|null
2799    {
2800        /** @var ModuleBlockInterface|null $module */
2801        $module = $this->module_service
2802            ->findByComponent(ModuleBlockInterface::class, $this->tree, Auth::user())
2803            ->first(static fn (ModuleInterface $module): bool => $module->name() === $block && $module->name() !== 'html');
2804
2805        if ($module === null) {
2806            return '';
2807        }
2808
2809        // Build the config array
2810        $cfg = [];
2811        foreach ($params as $config) {
2812            $bits = explode('=', $config);
2813
2814            if (count($bits) < 2) {
2815                continue;
2816            }
2817
2818            $v       = array_shift($bits);
2819            $cfg[$v] = implode('=', $bits);
2820        }
2821
2822        return $module->getBlock($this->tree, 0, ModuleBlockInterface::CONTEXT_EMBED, $cfg);
2823    }
2824
2825    /**
2826     * What is the current version of webtrees.
2827     *
2828     * @return string
2829     */
2830    public function webtreesVersion(): string
2831    {
2832        return Webtrees::VERSION;
2833    }
2834
2835    /**
2836     * Get tags and their parsed results.
2837     *
2838     * @param string $text
2839     *
2840     * @return array<string>
2841     */
2842    private function getTags(string $text): array
2843    {
2844        $tags    = [];
2845        $matches = [];
2846
2847        preg_match_all('/#([^#\n]+)(?=#)/', $text, $matches, PREG_SET_ORDER);
2848
2849        foreach ($matches as $match) {
2850            $params = explode(':', $match[1]);
2851            $method = array_shift($params);
2852
2853            if (method_exists($this, $method)) {
2854                $tags[$match[0] . '#'] = $this->$method(...$params);
2855            }
2856        }
2857
2858        return $tags;
2859    }
2860}
2861