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