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