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