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