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