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