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