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