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