18add1155SRico Sonntag<?php 28add1155SRico Sonntag/** 38add1155SRico Sonntag * webtrees: online genealogy 48add1155SRico Sonntag * Copyright (C) 2018 webtrees development team 58add1155SRico Sonntag * This program is free software: you can redistribute it and/or modify 68add1155SRico Sonntag * it under the terms of the GNU General Public License as published by 78add1155SRico Sonntag * the Free Software Foundation, either version 3 of the License, or 88add1155SRico Sonntag * (at your option) any later version. 98add1155SRico Sonntag * This program is distributed in the hope that it will be useful, 108add1155SRico Sonntag * but WITHOUT ANY WARRANTY; without even the implied warranty of 118add1155SRico Sonntag * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 128add1155SRico Sonntag * GNU General Public License for more details. 138add1155SRico Sonntag * You should have received a copy of the GNU General Public License 148add1155SRico Sonntag * along with this program. If not, see <http://www.gnu.org/licenses/>. 158add1155SRico Sonntag */ 168add1155SRico Sonntagdeclare(strict_types=1); 178add1155SRico Sonntag 188add1155SRico Sonntagnamespace Fisharebest\Webtrees\Statistics\Repository; 198add1155SRico Sonntag 208add1155SRico Sonntaguse Fisharebest\Webtrees\Auth; 218add1155SRico Sonntaguse Fisharebest\Webtrees\Database; 228add1155SRico Sonntaguse Fisharebest\Webtrees\Functions\FunctionsDate; 238add1155SRico Sonntaguse Fisharebest\Webtrees\Functions\FunctionsPrintLists; 248add1155SRico Sonntaguse Fisharebest\Webtrees\Gedcom; 258add1155SRico Sonntaguse Fisharebest\Webtrees\I18N; 268add1155SRico Sonntaguse Fisharebest\Webtrees\Individual; 278add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartAge; 288add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartBirth; 298add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartCommonGiven; 308add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartCommonSurname; 318add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartDeath; 328add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartFamilyWithSources; 338add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartIndividual; 348add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartMortality; 358add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Google\ChartSex; 368add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Helper\Sql; 378add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Repository\Interfaces\IndividualRepositoryInterface; 388add1155SRico Sonntaguse Fisharebest\Webtrees\Tree; 398add1155SRico Sonntaguse Illuminate\Database\Capsule\Manager as DB; 403dc8167dSGreg Roachuse Illuminate\Database\Query\Builder; 418add1155SRico Sonntaguse Illuminate\Database\Query\JoinClause; 428add1155SRico Sonntag 438add1155SRico Sonntag/** 448add1155SRico Sonntag * 458add1155SRico Sonntag */ 468add1155SRico Sonntagclass IndividualRepository implements IndividualRepositoryInterface 478add1155SRico Sonntag{ 488add1155SRico Sonntag /** 498add1155SRico Sonntag * @var Tree 508add1155SRico Sonntag */ 518add1155SRico Sonntag private $tree; 528add1155SRico Sonntag 538add1155SRico Sonntag /** 548add1155SRico Sonntag * Constructor. 558add1155SRico Sonntag * 568add1155SRico Sonntag * @param Tree $tree 578add1155SRico Sonntag */ 588add1155SRico Sonntag public function __construct(Tree $tree) 598add1155SRico Sonntag { 608add1155SRico Sonntag $this->tree = $tree; 618add1155SRico Sonntag } 628add1155SRico Sonntag 638add1155SRico Sonntag /** 648add1155SRico Sonntag * Run an SQL query and cache the result. 658add1155SRico Sonntag * 668add1155SRico Sonntag * @param string $sql 678add1155SRico Sonntag * 688add1155SRico Sonntag * @return \stdClass[] 698add1155SRico Sonntag */ 708add1155SRico Sonntag private function runSql(string $sql): array 718add1155SRico Sonntag { 728add1155SRico Sonntag return Sql::runSql($sql); 738add1155SRico Sonntag } 748add1155SRico Sonntag 758add1155SRico Sonntag /** 768add1155SRico Sonntag * Find common given names. 778add1155SRico Sonntag * 788add1155SRico Sonntag * @param string $sex 798add1155SRico Sonntag * @param string $type 808add1155SRico Sonntag * @param bool $show_tot 818add1155SRico Sonntag * @param int $threshold 828add1155SRico Sonntag * @param int $maxtoshow 838add1155SRico Sonntag * 848add1155SRico Sonntag * @return string|int[] 858add1155SRico Sonntag */ 868add1155SRico Sonntag private function commonGivenQuery(string $sex, string $type, bool $show_tot, int $threshold, int $maxtoshow) 878add1155SRico Sonntag { 888add1155SRico Sonntag switch ($sex) { 898add1155SRico Sonntag case 'M': 908add1155SRico Sonntag $sex_sql = "i_sex='M'"; 918add1155SRico Sonntag break; 928add1155SRico Sonntag case 'F': 938add1155SRico Sonntag $sex_sql = "i_sex='F'"; 948add1155SRico Sonntag break; 958add1155SRico Sonntag case 'U': 968add1155SRico Sonntag $sex_sql = "i_sex='U'"; 978add1155SRico Sonntag break; 988add1155SRico Sonntag case 'B': 998add1155SRico Sonntag default: 1008add1155SRico Sonntag $sex_sql = "i_sex<>'U'"; 1018add1155SRico Sonntag break; 1028add1155SRico Sonntag } 1038add1155SRico Sonntag 1048add1155SRico Sonntag $ged_id = $this->tree->id(); 1058add1155SRico Sonntag 1068add1155SRico Sonntag $rows = Database::prepare("SELECT n_givn, COUNT(*) AS num FROM `##name` JOIN `##individuals` ON (n_id=i_id AND n_file=i_file) WHERE n_file={$ged_id} AND n_type<>'_MARNM' AND n_givn NOT IN ('@P.N.', '') AND LENGTH(n_givn)>1 AND {$sex_sql} GROUP BY n_id, n_givn") 1078add1155SRico Sonntag ->fetchAll(); 1088add1155SRico Sonntag 1098add1155SRico Sonntag $nameList = []; 1108add1155SRico Sonntag foreach ($rows as $row) { 1118add1155SRico Sonntag $row->num = (int) $row->num; 1128add1155SRico Sonntag 1138add1155SRico Sonntag // Split “John Thomas” into “John” and “Thomas” and count against both totals 1148add1155SRico Sonntag foreach (explode(' ', $row->n_givn) as $given) { 1158add1155SRico Sonntag // Exclude initials and particles. 1168add1155SRico Sonntag if (!preg_match('/^([A-Z]|[a-z]{1,3})$/', $given)) { 1178add1155SRico Sonntag if (\array_key_exists($given, $nameList)) { 1188add1155SRico Sonntag $nameList[$given] += (int) $row->num; 1198add1155SRico Sonntag } else { 1208add1155SRico Sonntag $nameList[$given] = (int) $row->num; 1218add1155SRico Sonntag } 1228add1155SRico Sonntag } 1238add1155SRico Sonntag } 1248add1155SRico Sonntag } 1258add1155SRico Sonntag arsort($nameList); 1268add1155SRico Sonntag $nameList = \array_slice($nameList, 0, $maxtoshow); 1278add1155SRico Sonntag 1288add1155SRico Sonntag foreach ($nameList as $given => $total) { 1298add1155SRico Sonntag if ($total < $threshold) { 1308add1155SRico Sonntag unset($nameList[$given]); 1318add1155SRico Sonntag } 1328add1155SRico Sonntag } 1338add1155SRico Sonntag 1348add1155SRico Sonntag switch ($type) { 1358add1155SRico Sonntag case 'chart': 1368add1155SRico Sonntag return $nameList; 1378add1155SRico Sonntag 1388add1155SRico Sonntag case 'table': 1398add1155SRico Sonntag return view('lists/given-names-table', [ 1408add1155SRico Sonntag 'given_names' => $nameList, 1418add1155SRico Sonntag ]); 1428add1155SRico Sonntag 1438add1155SRico Sonntag case 'list': 1448add1155SRico Sonntag return view('lists/given-names-list', [ 1458add1155SRico Sonntag 'given_names' => $nameList, 1468add1155SRico Sonntag 'show_totals' => $show_tot, 1478add1155SRico Sonntag ]); 1488add1155SRico Sonntag 1498add1155SRico Sonntag case 'nolist': 1508add1155SRico Sonntag default: 1518add1155SRico Sonntag array_walk($nameList, function (int &$value, string $key) use ($show_tot): void { 1528add1155SRico Sonntag if ($show_tot) { 1538add1155SRico Sonntag $value = '<span dir="auto">' . e($key); 1548add1155SRico Sonntag } else { 1558add1155SRico Sonntag $value = '<span dir="auto">' . e($key) . ' (' . I18N::number($value) . ')'; 1568add1155SRico Sonntag } 1578add1155SRico Sonntag }); 1588add1155SRico Sonntag 1598add1155SRico Sonntag return implode(I18N::$list_separator, $nameList); 1608add1155SRico Sonntag } 1618add1155SRico Sonntag } 1628add1155SRico Sonntag 1638add1155SRico Sonntag /** 1648add1155SRico Sonntag * Find common give names. 1658add1155SRico Sonntag * 1668add1155SRico Sonntag * @param int $threshold 1678add1155SRico Sonntag * @param int $maxtoshow 1688add1155SRico Sonntag * 1698add1155SRico Sonntag * @return string 1708add1155SRico Sonntag */ 1718add1155SRico Sonntag public function commonGiven(int $threshold = 1, int $maxtoshow = 10): string 1728add1155SRico Sonntag { 1738add1155SRico Sonntag return $this->commonGivenQuery('B', 'nolist', false, $threshold, $maxtoshow); 1748add1155SRico Sonntag } 1758add1155SRico Sonntag 1768add1155SRico Sonntag /** 1778add1155SRico Sonntag * Find common give names. 1788add1155SRico Sonntag * 1798add1155SRico Sonntag * @param int $threshold 1808add1155SRico Sonntag * @param int $maxtoshow 1818add1155SRico Sonntag * 1828add1155SRico Sonntag * @return string 1838add1155SRico Sonntag */ 1848add1155SRico Sonntag public function commonGivenTotals(int $threshold = 1, int $maxtoshow = 10): string 1858add1155SRico Sonntag { 1868add1155SRico Sonntag return $this->commonGivenQuery('B', 'nolist', true, $threshold, $maxtoshow); 1878add1155SRico Sonntag } 1888add1155SRico Sonntag 1898add1155SRico Sonntag /** 1908add1155SRico Sonntag * Find common give names. 1918add1155SRico Sonntag * 1928add1155SRico Sonntag * @param int $threshold 1938add1155SRico Sonntag * @param int $maxtoshow 1948add1155SRico Sonntag * 1958add1155SRico Sonntag * @return string 1968add1155SRico Sonntag */ 1978add1155SRico Sonntag public function commonGivenList(int $threshold = 1, int $maxtoshow = 10): string 1988add1155SRico Sonntag { 1998add1155SRico Sonntag return $this->commonGivenQuery('B', 'list', false, $threshold, $maxtoshow); 2008add1155SRico Sonntag } 2018add1155SRico Sonntag 2028add1155SRico Sonntag /** 2038add1155SRico Sonntag * Find common give names. 2048add1155SRico Sonntag * 2058add1155SRico Sonntag * @param int $threshold 2068add1155SRico Sonntag * @param int $maxtoshow 2078add1155SRico Sonntag * 2088add1155SRico Sonntag * @return string 2098add1155SRico Sonntag */ 2108add1155SRico Sonntag public function commonGivenListTotals(int $threshold = 1, int $maxtoshow = 10): string 2118add1155SRico Sonntag { 2128add1155SRico Sonntag return $this->commonGivenQuery('B', 'list', true, $threshold, $maxtoshow); 2138add1155SRico Sonntag } 2148add1155SRico Sonntag 2158add1155SRico Sonntag /** 2168add1155SRico Sonntag * Find common give names. 2178add1155SRico Sonntag * 2188add1155SRico Sonntag * @param int $threshold 2198add1155SRico Sonntag * @param int $maxtoshow 2208add1155SRico Sonntag * 2218add1155SRico Sonntag * @return string 2228add1155SRico Sonntag */ 2238add1155SRico Sonntag public function commonGivenTable(int $threshold = 1, int $maxtoshow = 10): string 2248add1155SRico Sonntag { 2258add1155SRico Sonntag return $this->commonGivenQuery('B', 'table', false, $threshold, $maxtoshow); 2268add1155SRico Sonntag } 2278add1155SRico Sonntag 2288add1155SRico Sonntag /** 2298add1155SRico Sonntag * Find common give names of females. 2308add1155SRico Sonntag * 2318add1155SRico Sonntag * @param int $threshold 2328add1155SRico Sonntag * @param int $maxtoshow 2338add1155SRico Sonntag * 2348add1155SRico Sonntag * @return string 2358add1155SRico Sonntag */ 2368add1155SRico Sonntag public function commonGivenFemale(int $threshold = 1, int $maxtoshow = 10): string 2378add1155SRico Sonntag { 2388add1155SRico Sonntag return $this->commonGivenQuery('F', 'nolist', false, $threshold, $maxtoshow); 2398add1155SRico Sonntag } 2408add1155SRico Sonntag 2418add1155SRico Sonntag /** 2428add1155SRico Sonntag * Find common give names of females. 2438add1155SRico Sonntag * 2448add1155SRico Sonntag * @param int $threshold 2458add1155SRico Sonntag * @param int $maxtoshow 2468add1155SRico Sonntag * 2478add1155SRico Sonntag * @return string 2488add1155SRico Sonntag */ 2498add1155SRico Sonntag public function commonGivenFemaleTotals(int $threshold = 1, int $maxtoshow = 10): string 2508add1155SRico Sonntag { 2518add1155SRico Sonntag return $this->commonGivenQuery('F', 'nolist', true, $threshold, $maxtoshow); 2528add1155SRico Sonntag } 2538add1155SRico Sonntag 2548add1155SRico Sonntag /** 2558add1155SRico Sonntag * Find common give names of females. 2568add1155SRico Sonntag * 2578add1155SRico Sonntag * @param int $threshold 2588add1155SRico Sonntag * @param int $maxtoshow 2598add1155SRico Sonntag * 2608add1155SRico Sonntag * @return string 2618add1155SRico Sonntag */ 2628add1155SRico Sonntag public function commonGivenFemaleList(int $threshold = 1, int $maxtoshow = 10): string 2638add1155SRico Sonntag { 2648add1155SRico Sonntag return $this->commonGivenQuery('F', 'list', false, $threshold, $maxtoshow); 2658add1155SRico Sonntag } 2668add1155SRico Sonntag 2678add1155SRico Sonntag /** 2688add1155SRico Sonntag * Find common give names of females. 2698add1155SRico Sonntag * 2708add1155SRico Sonntag * @param int $threshold 2718add1155SRico Sonntag * @param int $maxtoshow 2728add1155SRico Sonntag * 2738add1155SRico Sonntag * @return string 2748add1155SRico Sonntag */ 2758add1155SRico Sonntag public function commonGivenFemaleListTotals(int $threshold = 1, int $maxtoshow = 10): string 2768add1155SRico Sonntag { 2778add1155SRico Sonntag return $this->commonGivenQuery('F', 'list', true, $threshold, $maxtoshow); 2788add1155SRico Sonntag } 2798add1155SRico Sonntag 2808add1155SRico Sonntag /** 2818add1155SRico Sonntag * Find common give names of females. 2828add1155SRico Sonntag * 2838add1155SRico Sonntag * @param int $threshold 2848add1155SRico Sonntag * @param int $maxtoshow 2858add1155SRico Sonntag * 2868add1155SRico Sonntag * @return string 2878add1155SRico Sonntag */ 2888add1155SRico Sonntag public function commonGivenFemaleTable(int $threshold = 1, int $maxtoshow = 10): string 2898add1155SRico Sonntag { 2908add1155SRico Sonntag return $this->commonGivenQuery('F', 'table', false, $threshold, $maxtoshow); 2918add1155SRico Sonntag } 2928add1155SRico Sonntag 2938add1155SRico Sonntag /** 2948add1155SRico Sonntag * Find common give names of males. 2958add1155SRico Sonntag * 2968add1155SRico Sonntag * @param int $threshold 2978add1155SRico Sonntag * @param int $maxtoshow 2988add1155SRico Sonntag * 2998add1155SRico Sonntag * @return string 3008add1155SRico Sonntag */ 3018add1155SRico Sonntag public function commonGivenMale(int $threshold = 1, int $maxtoshow = 10): string 3028add1155SRico Sonntag { 3038add1155SRico Sonntag return $this->commonGivenQuery('M', 'nolist', false, $threshold, $maxtoshow); 3048add1155SRico Sonntag } 3058add1155SRico Sonntag 3068add1155SRico Sonntag /** 3078add1155SRico Sonntag * Find common give names of males. 3088add1155SRico Sonntag * 3098add1155SRico Sonntag * @param int $threshold 3108add1155SRico Sonntag * @param int $maxtoshow 3118add1155SRico Sonntag * 3128add1155SRico Sonntag * @return string 3138add1155SRico Sonntag */ 3148add1155SRico Sonntag public function commonGivenMaleTotals(int $threshold = 1, int $maxtoshow = 10): string 3158add1155SRico Sonntag { 3168add1155SRico Sonntag return $this->commonGivenQuery('M', 'nolist', true, $threshold, $maxtoshow); 3178add1155SRico Sonntag } 3188add1155SRico Sonntag 3198add1155SRico Sonntag /** 3208add1155SRico Sonntag * Find common give names of males. 3218add1155SRico Sonntag * 3228add1155SRico Sonntag * @param int $threshold 3238add1155SRico Sonntag * @param int $maxtoshow 3248add1155SRico Sonntag * 3258add1155SRico Sonntag * @return string 3268add1155SRico Sonntag */ 3278add1155SRico Sonntag public function commonGivenMaleList(int $threshold = 1, int $maxtoshow = 10): string 3288add1155SRico Sonntag { 3298add1155SRico Sonntag return $this->commonGivenQuery('M', 'list', false, $threshold, $maxtoshow); 3308add1155SRico Sonntag } 3318add1155SRico Sonntag 3328add1155SRico Sonntag /** 3338add1155SRico Sonntag * Find common give names of males. 3348add1155SRico Sonntag * 3358add1155SRico Sonntag * @param int $threshold 3368add1155SRico Sonntag * @param int $maxtoshow 3378add1155SRico Sonntag * 3388add1155SRico Sonntag * @return string 3398add1155SRico Sonntag */ 3408add1155SRico Sonntag public function commonGivenMaleListTotals(int $threshold = 1, int $maxtoshow = 10): string 3418add1155SRico Sonntag { 3428add1155SRico Sonntag return $this->commonGivenQuery('M', 'list', true, $threshold, $maxtoshow); 3438add1155SRico Sonntag } 3448add1155SRico Sonntag 3458add1155SRico Sonntag /** 3468add1155SRico Sonntag * Find common give names of males. 3478add1155SRico Sonntag * 3488add1155SRico Sonntag * @param int $threshold 3498add1155SRico Sonntag * @param int $maxtoshow 3508add1155SRico Sonntag * 3518add1155SRico Sonntag * @return string 3528add1155SRico Sonntag */ 3538add1155SRico Sonntag public function commonGivenMaleTable(int $threshold = 1, int $maxtoshow = 10): string 3548add1155SRico Sonntag { 3558add1155SRico Sonntag return $this->commonGivenQuery('M', 'table', false, $threshold, $maxtoshow); 3568add1155SRico Sonntag } 3578add1155SRico Sonntag 3588add1155SRico Sonntag /** 3598add1155SRico Sonntag * Find common give names of unknown sexes. 3608add1155SRico Sonntag * 3618add1155SRico Sonntag * @param int $threshold 3628add1155SRico Sonntag * @param int $maxtoshow 3638add1155SRico Sonntag * 3648add1155SRico Sonntag * @return string 3658add1155SRico Sonntag */ 3668add1155SRico Sonntag public function commonGivenUnknown(int $threshold = 1, int $maxtoshow = 10): string 3678add1155SRico Sonntag { 3688add1155SRico Sonntag return $this->commonGivenQuery('U', 'nolist', false, $threshold, $maxtoshow); 3698add1155SRico Sonntag } 3708add1155SRico Sonntag 3718add1155SRico Sonntag /** 3728add1155SRico Sonntag * Find common give names of unknown sexes. 3738add1155SRico Sonntag * 3748add1155SRico Sonntag * @param int $threshold 3758add1155SRico Sonntag * @param int $maxtoshow 3768add1155SRico Sonntag * 3778add1155SRico Sonntag * @return string 3788add1155SRico Sonntag */ 3798add1155SRico Sonntag public function commonGivenUnknownTotals(int $threshold = 1, int $maxtoshow = 10): string 3808add1155SRico Sonntag { 3818add1155SRico Sonntag return $this->commonGivenQuery('U', 'nolist', true, $threshold, $maxtoshow); 3828add1155SRico Sonntag } 3838add1155SRico Sonntag 3848add1155SRico Sonntag /** 3858add1155SRico Sonntag * Find common give names of unknown sexes. 3868add1155SRico Sonntag * 3878add1155SRico Sonntag * @param int $threshold 3888add1155SRico Sonntag * @param int $maxtoshow 3898add1155SRico Sonntag * 3908add1155SRico Sonntag * @return string 3918add1155SRico Sonntag */ 3928add1155SRico Sonntag public function commonGivenUnknownList(int $threshold = 1, int $maxtoshow = 10): string 3938add1155SRico Sonntag { 3948add1155SRico Sonntag return $this->commonGivenQuery('U', 'list', false, $threshold, $maxtoshow); 3958add1155SRico Sonntag } 3968add1155SRico Sonntag 3978add1155SRico Sonntag /** 3988add1155SRico Sonntag * Find common give names of unknown sexes. 3998add1155SRico Sonntag * 4008add1155SRico Sonntag * @param int $threshold 4018add1155SRico Sonntag * @param int $maxtoshow 4028add1155SRico Sonntag * 4038add1155SRico Sonntag * @return string 4048add1155SRico Sonntag */ 4058add1155SRico Sonntag public function commonGivenUnknownListTotals(int $threshold = 1, int $maxtoshow = 10): string 4068add1155SRico Sonntag { 4078add1155SRico Sonntag return $this->commonGivenQuery('U', 'list', true, $threshold, $maxtoshow); 4088add1155SRico Sonntag } 4098add1155SRico Sonntag 4108add1155SRico Sonntag /** 4118add1155SRico Sonntag * Find common give names of unknown sexes. 4128add1155SRico Sonntag * 4138add1155SRico Sonntag * @param int $threshold 4148add1155SRico Sonntag * @param int $maxtoshow 4158add1155SRico Sonntag * 4168add1155SRico Sonntag * @return string 4178add1155SRico Sonntag */ 4188add1155SRico Sonntag public function commonGivenUnknownTable(int $threshold = 1, int $maxtoshow = 10): string 4198add1155SRico Sonntag { 4208add1155SRico Sonntag return $this->commonGivenQuery('U', 'table', false, $threshold, $maxtoshow); 4218add1155SRico Sonntag } 4228add1155SRico Sonntag 4238add1155SRico Sonntag /** 4243dc8167dSGreg Roach * Count the number of distinct given names (or the number of occurences of specific given names). 4258add1155SRico Sonntag * 4263dc8167dSGreg Roach * @param string[] ...$params 4278add1155SRico Sonntag * 4288add1155SRico Sonntag * @return string 4298add1155SRico Sonntag */ 4308add1155SRico Sonntag public function totalGivennames(...$params): string 4318add1155SRico Sonntag { 4323dc8167dSGreg Roach $query = DB::table('name') 4333dc8167dSGreg Roach ->where('n_file', '=', $this->tree->id()); 4343dc8167dSGreg Roach 4353dc8167dSGreg Roach if (empty($params)) { 436c09e99bfSRico Sonntag // Count number of distinct given names. 4373dc8167dSGreg Roach $query 438c09e99bfSRico Sonntag ->distinct() 439*2ccd1f0bSGreg Roach ->where('n_givn', '<>', '@P.N.') 440c09e99bfSRico Sonntag ->whereNotNull('n_givn'); 4418add1155SRico Sonntag } else { 442c09e99bfSRico Sonntag // Count number of occurences of specific given names. 44344cdc21eSGreg Roach $query->whereIn('n_givn', $params); 4448add1155SRico Sonntag } 4458add1155SRico Sonntag 446c09e99bfSRico Sonntag $count = $query->count('n_givn'); 4473dc8167dSGreg Roach 4483dc8167dSGreg Roach return I18N::number($count); 4498add1155SRico Sonntag } 4508add1155SRico Sonntag 4518add1155SRico Sonntag /** 452c09e99bfSRico Sonntag * Count the number of distinct surnames (or the number of occurences of specific surnames). 4538add1155SRico Sonntag * 4543dc8167dSGreg Roach * @param string[] ...$params 4558add1155SRico Sonntag * 4568add1155SRico Sonntag * @return string 4578add1155SRico Sonntag */ 4588add1155SRico Sonntag public function totalSurnames(...$params): string 4598add1155SRico Sonntag { 4603dc8167dSGreg Roach $query = DB::table('name') 4613dc8167dSGreg Roach ->where('n_file', '=', $this->tree->id()); 4623dc8167dSGreg Roach 4633dc8167dSGreg Roach if (empty($params)) { 4643dc8167dSGreg Roach // Count number of distinct surnames 465c09e99bfSRico Sonntag $query->distinct() 466c09e99bfSRico Sonntag ->whereNotNull('n_surn'); 4678add1155SRico Sonntag } else { 4683dc8167dSGreg Roach // Count number of occurences of specific surnames. 4693dc8167dSGreg Roach $query->whereIn('n_surn', $params); 4708add1155SRico Sonntag } 4718add1155SRico Sonntag 472c09e99bfSRico Sonntag $count = $query->count('n_surn'); 4738add1155SRico Sonntag 4743dc8167dSGreg Roach return I18N::number($count); 4758add1155SRico Sonntag } 4768add1155SRico Sonntag 4778add1155SRico Sonntag /** 4788add1155SRico Sonntag * @param int $number_of_surnames 4798add1155SRico Sonntag * @param int $threshold 4808add1155SRico Sonntag * 4818add1155SRico Sonntag * @return \stdClass[] 4828add1155SRico Sonntag */ 4838add1155SRico Sonntag private function topSurnames(int $number_of_surnames, int $threshold): array 4848add1155SRico Sonntag { 4858add1155SRico Sonntag // Use the count of base surnames. 4868add1155SRico Sonntag $top_surnames = Database::prepare( 4878add1155SRico Sonntag "SELECT n_surn FROM `##name`" . 4888add1155SRico Sonntag " WHERE n_file = :tree_id AND n_type != '_MARNM' AND n_surn NOT IN ('@N.N.', '')" . 4898add1155SRico Sonntag " GROUP BY n_surn" . 4908add1155SRico Sonntag " ORDER BY COUNT(n_surn) DESC" . 4918add1155SRico Sonntag " LIMIT :limit" 4928add1155SRico Sonntag )->execute([ 4938add1155SRico Sonntag 'tree_id' => $this->tree->id(), 4948add1155SRico Sonntag 'limit' => $number_of_surnames, 4958add1155SRico Sonntag ])->fetchOneColumn(); 4968add1155SRico Sonntag 4978add1155SRico Sonntag $surnames = []; 4988add1155SRico Sonntag foreach ($top_surnames as $top_surname) { 4998add1155SRico Sonntag $variants = Database::prepare( 5008add1155SRico Sonntag "SELECT n_surname COLLATE utf8_bin, COUNT(*) FROM `##name` WHERE n_file = :tree_id AND n_surn COLLATE :collate = :surname GROUP BY 1" 5018add1155SRico Sonntag )->execute([ 5028add1155SRico Sonntag 'collate' => I18N::collation(), 5038add1155SRico Sonntag 'surname' => $top_surname, 5048add1155SRico Sonntag 'tree_id' => $this->tree->id(), 5058add1155SRico Sonntag ])->fetchAssoc(); 5068add1155SRico Sonntag 5078add1155SRico Sonntag if (array_sum($variants) > $threshold) { 5088add1155SRico Sonntag $surnames[$top_surname] = $variants; 5098add1155SRico Sonntag } 5108add1155SRico Sonntag } 5118add1155SRico Sonntag 5128add1155SRico Sonntag return $surnames; 5138add1155SRico Sonntag } 5148add1155SRico Sonntag 5158add1155SRico Sonntag /** 5168add1155SRico Sonntag * Find common surnames. 5178add1155SRico Sonntag * 5188add1155SRico Sonntag * @return string 5198add1155SRico Sonntag */ 5208add1155SRico Sonntag public function getCommonSurname(): string 5218add1155SRico Sonntag { 5228add1155SRico Sonntag $top_surname = $this->topSurnames(1, 0); 5238add1155SRico Sonntag return implode(', ', array_keys(array_shift($top_surname)) ?? []); 5248add1155SRico Sonntag } 5258add1155SRico Sonntag 5268add1155SRico Sonntag /** 5278add1155SRico Sonntag * Find common surnames. 5288add1155SRico Sonntag * 5298add1155SRico Sonntag * @param string $type 5308add1155SRico Sonntag * @param bool $show_tot 5318add1155SRico Sonntag * @param int $threshold 5328add1155SRico Sonntag * @param int $number_of_surnames 5338add1155SRico Sonntag * @param string $sorting 5348add1155SRico Sonntag * 5358add1155SRico Sonntag * @return string 5368add1155SRico Sonntag */ 5378add1155SRico Sonntag private function commonSurnamesQuery( 5388add1155SRico Sonntag string $type, 5398add1155SRico Sonntag bool $show_tot, 5408add1155SRico Sonntag int $threshold, 5418add1155SRico Sonntag int $number_of_surnames, 5428add1155SRico Sonntag string $sorting 5438add1155SRico Sonntag ): string { 5448add1155SRico Sonntag $surnames = $this->topSurnames($number_of_surnames, $threshold); 5458add1155SRico Sonntag 5468add1155SRico Sonntag switch ($sorting) { 5478add1155SRico Sonntag default: 5488add1155SRico Sonntag case 'alpha': 5498add1155SRico Sonntag uksort($surnames, [I18N::class, 'strcasecmp']); 5508add1155SRico Sonntag break; 5518add1155SRico Sonntag case 'count': 5528add1155SRico Sonntag break; 5538add1155SRico Sonntag case 'rcount': 5548add1155SRico Sonntag $surnames = array_reverse($surnames, true); 5558add1155SRico Sonntag break; 5568add1155SRico Sonntag } 5578add1155SRico Sonntag 5588add1155SRico Sonntag return FunctionsPrintLists::surnameList( 5598add1155SRico Sonntag $surnames, 5608add1155SRico Sonntag ($type === 'list' ? 1 : 2), 5618add1155SRico Sonntag $show_tot, 5628add1155SRico Sonntag 'individual-list', 5638add1155SRico Sonntag $this->tree 5648add1155SRico Sonntag ); 5658add1155SRico Sonntag } 5668add1155SRico Sonntag 5678add1155SRico Sonntag /** 5688add1155SRico Sonntag * Find common surnames. 5698add1155SRico Sonntag * 5708add1155SRico Sonntag * @param int $threshold 5718add1155SRico Sonntag * @param int $number_of_surnames 5728add1155SRico Sonntag * @param string $sorting 5738add1155SRico Sonntag * 5748add1155SRico Sonntag * @return string 5758add1155SRico Sonntag */ 5768add1155SRico Sonntag public function commonSurnames( 5778add1155SRico Sonntag int $threshold = 1, 5788add1155SRico Sonntag int $number_of_surnames = 10, 5798add1155SRico Sonntag string $sorting = 'alpha' 5808add1155SRico Sonntag ): string { 5818add1155SRico Sonntag return $this->commonSurnamesQuery('nolist', false, $threshold, $number_of_surnames, $sorting); 5828add1155SRico Sonntag } 5838add1155SRico Sonntag 5848add1155SRico Sonntag /** 5858add1155SRico Sonntag * Find common surnames. 5868add1155SRico Sonntag * 5878add1155SRico Sonntag * @param int $threshold 5888add1155SRico Sonntag * @param int $number_of_surnames 5898add1155SRico Sonntag * @param string $sorting 5908add1155SRico Sonntag * 5918add1155SRico Sonntag * @return string 5928add1155SRico Sonntag */ 5938add1155SRico Sonntag public function commonSurnamesTotals( 5948add1155SRico Sonntag int $threshold = 1, 5958add1155SRico Sonntag int $number_of_surnames = 10, 5968add1155SRico Sonntag string $sorting = 'rcount' 5978add1155SRico Sonntag ): string { 5988add1155SRico Sonntag return $this->commonSurnamesQuery('nolist', true, $threshold, $number_of_surnames, $sorting); 5998add1155SRico Sonntag } 6008add1155SRico Sonntag 6018add1155SRico Sonntag /** 6028add1155SRico Sonntag * Find common surnames. 6038add1155SRico Sonntag * 6048add1155SRico Sonntag * @param int $threshold 6058add1155SRico Sonntag * @param int $number_of_surnames 6068add1155SRico Sonntag * @param string $sorting 6078add1155SRico Sonntag * 6088add1155SRico Sonntag * @return string 6098add1155SRico Sonntag */ 6108add1155SRico Sonntag public function commonSurnamesList( 6118add1155SRico Sonntag int $threshold = 1, 6128add1155SRico Sonntag int $number_of_surnames = 10, 6138add1155SRico Sonntag string $sorting = 'alpha' 6148add1155SRico Sonntag ): string { 6158add1155SRico Sonntag return $this->commonSurnamesQuery('list', false, $threshold, $number_of_surnames, $sorting); 6168add1155SRico Sonntag } 6178add1155SRico Sonntag 6188add1155SRico Sonntag /** 6198add1155SRico Sonntag * Find common surnames. 6208add1155SRico Sonntag * 6218add1155SRico Sonntag * @param int $threshold 6228add1155SRico Sonntag * @param int $number_of_surnames 6238add1155SRico Sonntag * @param string $sorting 6248add1155SRico Sonntag * 6258add1155SRico Sonntag * @return string 6268add1155SRico Sonntag */ 6278add1155SRico Sonntag public function commonSurnamesListTotals( 6288add1155SRico Sonntag int $threshold = 1, 6298add1155SRico Sonntag int $number_of_surnames = 10, 6308add1155SRico Sonntag string $sorting = 'rcount' 6318add1155SRico Sonntag ): string { 6328add1155SRico Sonntag return $this->commonSurnamesQuery('list', true, $threshold, $number_of_surnames, $sorting); 6338add1155SRico Sonntag } 6348add1155SRico Sonntag 6358add1155SRico Sonntag /** 6368add1155SRico Sonntag * Get a list of birth dates. 6378add1155SRico Sonntag * 6388add1155SRico Sonntag * @param bool $sex 6398add1155SRico Sonntag * @param int $year1 6408add1155SRico Sonntag * @param int $year2 6418add1155SRico Sonntag * 6428add1155SRico Sonntag * @return array 6438add1155SRico Sonntag */ 6448add1155SRico Sonntag public function statsBirthQuery(bool $sex = false, int $year1 = -1, int $year2 = -1): array 6458add1155SRico Sonntag { 6468add1155SRico Sonntag if ($sex) { 6478add1155SRico Sonntag $sql = 6488add1155SRico Sonntag "SELECT d_month, i_sex, COUNT(*) AS total FROM `##dates` " . 6498add1155SRico Sonntag "JOIN `##individuals` ON d_file = i_file AND d_gid = i_id " . 6508add1155SRico Sonntag "WHERE " . 6518add1155SRico Sonntag "d_file={$this->tree->id()} AND " . 6528add1155SRico Sonntag "d_fact='BIRT' AND " . 6538add1155SRico Sonntag "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')"; 6548add1155SRico Sonntag } else { 6558add1155SRico Sonntag $sql = 6568add1155SRico Sonntag "SELECT d_month, COUNT(*) AS total FROM `##dates` " . 6578add1155SRico Sonntag "WHERE " . 6588add1155SRico Sonntag "d_file={$this->tree->id()} AND " . 6598add1155SRico Sonntag "d_fact='BIRT' AND " . 6608add1155SRico Sonntag "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')"; 6618add1155SRico Sonntag } 6628add1155SRico Sonntag 6638add1155SRico Sonntag if ($year1 >= 0 && $year2 >= 0) { 6648add1155SRico Sonntag $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'"; 6658add1155SRico Sonntag } 6668add1155SRico Sonntag 6678add1155SRico Sonntag $sql .= " GROUP BY d_month"; 6688add1155SRico Sonntag 6698add1155SRico Sonntag if ($sex) { 6708add1155SRico Sonntag $sql .= ", i_sex"; 6718add1155SRico Sonntag } 6728add1155SRico Sonntag 6738add1155SRico Sonntag return $this->runSql($sql); 6748add1155SRico Sonntag } 6758add1155SRico Sonntag 6768add1155SRico Sonntag /** 6778add1155SRico Sonntag * General query on births. 6788add1155SRico Sonntag * 6798add1155SRico Sonntag * @param string|null $size 6808add1155SRico Sonntag * @param string|null $color_from 6818add1155SRico Sonntag * @param string|null $color_to 6828add1155SRico Sonntag * 6838add1155SRico Sonntag * @return string 6848add1155SRico Sonntag */ 6858add1155SRico Sonntag public function statsBirth(string $size = null, string $color_from = null, string $color_to = null): string 6868add1155SRico Sonntag { 6878add1155SRico Sonntag return (new ChartBirth($this->tree)) 6888add1155SRico Sonntag ->chartBirth($size, $color_from, $color_to); 6898add1155SRico Sonntag } 6908add1155SRico Sonntag 6918add1155SRico Sonntag /** 6928add1155SRico Sonntag * Get a list of death dates. 6938add1155SRico Sonntag * 6948add1155SRico Sonntag * @param bool $sex 6958add1155SRico Sonntag * @param int $year1 6968add1155SRico Sonntag * @param int $year2 6978add1155SRico Sonntag * 6988add1155SRico Sonntag * @return array 6998add1155SRico Sonntag */ 7008add1155SRico Sonntag public function statsDeathQuery(bool $sex = false, int $year1 = -1, int $year2 = -1): array 7018add1155SRico Sonntag { 7028add1155SRico Sonntag if ($sex) { 7038add1155SRico Sonntag $sql = 7048add1155SRico Sonntag "SELECT d_month, i_sex, COUNT(*) AS total FROM `##dates` " . 7058add1155SRico Sonntag "JOIN `##individuals` ON d_file = i_file AND d_gid = i_id " . 7068add1155SRico Sonntag "WHERE " . 7078add1155SRico Sonntag "d_file={$this->tree->id()} AND " . 7088add1155SRico Sonntag "d_fact='DEAT' AND " . 7098add1155SRico Sonntag "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')"; 7108add1155SRico Sonntag } else { 7118add1155SRico Sonntag $sql = 7128add1155SRico Sonntag "SELECT d_month, COUNT(*) AS total FROM `##dates` " . 7138add1155SRico Sonntag "WHERE " . 7148add1155SRico Sonntag "d_file={$this->tree->id()} AND " . 7158add1155SRico Sonntag "d_fact='DEAT' AND " . 7168add1155SRico Sonntag "d_type IN ('@#DGREGORIAN@', '@#DJULIAN@')"; 7178add1155SRico Sonntag } 7188add1155SRico Sonntag 7198add1155SRico Sonntag if ($year1 >= 0 && $year2 >= 0) { 7208add1155SRico Sonntag $sql .= " AND d_year BETWEEN '{$year1}' AND '{$year2}'"; 7218add1155SRico Sonntag } 7228add1155SRico Sonntag 7238add1155SRico Sonntag $sql .= " GROUP BY d_month"; 7248add1155SRico Sonntag 7258add1155SRico Sonntag if ($sex) { 7268add1155SRico Sonntag $sql .= ", i_sex"; 7278add1155SRico Sonntag } 7288add1155SRico Sonntag 7298add1155SRico Sonntag return $this->runSql($sql); 7308add1155SRico Sonntag } 7318add1155SRico Sonntag 7328add1155SRico Sonntag /** 7338add1155SRico Sonntag * General query on deaths. 7348add1155SRico Sonntag * 7358add1155SRico Sonntag * @param string|null $size 7368add1155SRico Sonntag * @param string|null $color_from 7378add1155SRico Sonntag * @param string|null $color_to 7388add1155SRico Sonntag * 7398add1155SRico Sonntag * @return string 7408add1155SRico Sonntag */ 7418add1155SRico Sonntag public function statsDeath(string $size = null, string $color_from = null, string $color_to = null): string 7428add1155SRico Sonntag { 7438add1155SRico Sonntag return (new ChartDeath($this->tree)) 7448add1155SRico Sonntag ->chartDeath($size, $color_from, $color_to); 7458add1155SRico Sonntag } 7468add1155SRico Sonntag 7478add1155SRico Sonntag /** 7488add1155SRico Sonntag * General query on ages. 7498add1155SRico Sonntag * 7508add1155SRico Sonntag * @param string $related 7518add1155SRico Sonntag * @param string $sex 7528add1155SRico Sonntag * @param int $year1 7538add1155SRico Sonntag * @param int $year2 7548add1155SRico Sonntag * 7558add1155SRico Sonntag * @return array|string 7568add1155SRico Sonntag */ 7578add1155SRico Sonntag public function statsAgeQuery(string $related = 'BIRT', string $sex = 'BOTH', int $year1 = -1, int $year2 = -1) 7588add1155SRico Sonntag { 75944cdc21eSGreg Roach $prefix = DB::connection()->getTablePrefix(); 7608add1155SRico Sonntag 76144cdc21eSGreg Roach $query = $this->birthAndDeathQuery($sex); 7628add1155SRico Sonntag 7638add1155SRico Sonntag if ($year1 >= 0 && $year2 >= 0) { 76444cdc21eSGreg Roach $query 76544cdc21eSGreg Roach ->whereIn('birth.d_type', ['@#DGREGORIAN@', '@#DJULIAN@']) 76644cdc21eSGreg Roach ->whereIn('death.d_type', ['@#DGREGORIAN@', '@#DJULIAN@']); 76744cdc21eSGreg Roach 7688add1155SRico Sonntag if ($related === 'BIRT') { 76944cdc21eSGreg Roach $query->whereBetween('birth.d_year', [$year1, $year2]); 7708add1155SRico Sonntag } elseif ($related === 'DEAT') { 77144cdc21eSGreg Roach $query->whereBetween('death.d_year', [$year1, $year2]); 7728add1155SRico Sonntag } 7738add1155SRico Sonntag } 7748add1155SRico Sonntag 77544cdc21eSGreg Roach return $query 77644cdc21eSGreg Roach ->select(DB::raw($prefix . 'death.d_julianday2 - ' . $prefix . 'birth.d_julianday1 AS days')) 777c8c87812SRico Sonntag ->orderBy('days', 'desc') 77844cdc21eSGreg Roach ->get() 77944cdc21eSGreg Roach ->all(); 7808add1155SRico Sonntag } 7818add1155SRico Sonntag 7828add1155SRico Sonntag /** 7838add1155SRico Sonntag * General query on ages. 7848add1155SRico Sonntag * 7858add1155SRico Sonntag * @param string $size 7868add1155SRico Sonntag * 7878add1155SRico Sonntag * @return string 7888add1155SRico Sonntag */ 7898add1155SRico Sonntag public function statsAge(string $size = '230x250'): string 7908add1155SRico Sonntag { 7918add1155SRico Sonntag return (new ChartAge($this->tree))->chartAge($size); 7928add1155SRico Sonntag } 7938add1155SRico Sonntag 7948add1155SRico Sonntag /** 7958add1155SRico Sonntag * Lifespan 7968add1155SRico Sonntag * 7978add1155SRico Sonntag * @param string $type 7988add1155SRico Sonntag * @param string $sex 7998add1155SRico Sonntag * 8008add1155SRico Sonntag * @return string 8018add1155SRico Sonntag */ 8028add1155SRico Sonntag private function longlifeQuery(string $type, string $sex): string 8038add1155SRico Sonntag { 80444cdc21eSGreg Roach $prefix = DB::connection()->getTablePrefix(); 8058add1155SRico Sonntag 80644cdc21eSGreg Roach $row = $this->birthAndDeathQuery($sex) 80744cdc21eSGreg Roach ->orderBy('days', 'desc') 80844cdc21eSGreg Roach ->select(['individuals.*', DB::raw($prefix . 'death.d_julianday2 - ' . $prefix . 'birth.d_julianday1 AS days')]) 80944cdc21eSGreg Roach ->first(); 81044cdc21eSGreg Roach 81144cdc21eSGreg Roach if ($row === null) { 8128add1155SRico Sonntag return ''; 8138add1155SRico Sonntag } 81444cdc21eSGreg Roach 81544cdc21eSGreg Roach /** @var Individual $individual */ 81644cdc21eSGreg Roach $individual = Individual::rowMapper()($row); 81744cdc21eSGreg Roach 81844cdc21eSGreg Roach if (!$individual->canShow()) { 81944cdc21eSGreg Roach return I18N::translate('This information is private and cannot be shown.'); 82044cdc21eSGreg Roach } 82144cdc21eSGreg Roach 8228add1155SRico Sonntag switch ($type) { 8238add1155SRico Sonntag default: 8248add1155SRico Sonntag case 'full': 82544cdc21eSGreg Roach return $individual->formatList(); 8268add1155SRico Sonntag 82744cdc21eSGreg Roach case 'age': 82844cdc21eSGreg Roach return I18N::number((int) ($row->days / 365.25)); 82944cdc21eSGreg Roach 83044cdc21eSGreg Roach case 'name': 83144cdc21eSGreg Roach return '<a href="' . e($individual->url()) . '">' . $individual->getFullName() . '</a>'; 83244cdc21eSGreg Roach } 8338add1155SRico Sonntag } 8348add1155SRico Sonntag 8358add1155SRico Sonntag /** 8368add1155SRico Sonntag * Find the longest lived individual. 8378add1155SRico Sonntag * 8388add1155SRico Sonntag * @return string 8398add1155SRico Sonntag */ 8408add1155SRico Sonntag public function longestLife(): string 8418add1155SRico Sonntag { 8428add1155SRico Sonntag return $this->longlifeQuery('full', 'BOTH'); 8438add1155SRico Sonntag } 8448add1155SRico Sonntag 8458add1155SRico Sonntag /** 8468add1155SRico Sonntag * Find the age of the longest lived individual. 8478add1155SRico Sonntag * 8488add1155SRico Sonntag * @return string 8498add1155SRico Sonntag */ 8508add1155SRico Sonntag public function longestLifeAge(): string 8518add1155SRico Sonntag { 8528add1155SRico Sonntag return $this->longlifeQuery('age', 'BOTH'); 8538add1155SRico Sonntag } 8548add1155SRico Sonntag 8558add1155SRico Sonntag /** 8568add1155SRico Sonntag * Find the name of the longest lived individual. 8578add1155SRico Sonntag * 8588add1155SRico Sonntag * @return string 8598add1155SRico Sonntag */ 8608add1155SRico Sonntag public function longestLifeName(): string 8618add1155SRico Sonntag { 8628add1155SRico Sonntag return $this->longlifeQuery('name', 'BOTH'); 8638add1155SRico Sonntag } 8648add1155SRico Sonntag 8658add1155SRico Sonntag /** 8668add1155SRico Sonntag * Find the longest lived female. 8678add1155SRico Sonntag * 8688add1155SRico Sonntag * @return string 8698add1155SRico Sonntag */ 8708add1155SRico Sonntag public function longestLifeFemale(): string 8718add1155SRico Sonntag { 8728add1155SRico Sonntag return $this->longlifeQuery('full', 'F'); 8738add1155SRico Sonntag } 8748add1155SRico Sonntag 8758add1155SRico Sonntag /** 8768add1155SRico Sonntag * Find the age of the longest lived female. 8778add1155SRico Sonntag * 8788add1155SRico Sonntag * @return string 8798add1155SRico Sonntag */ 8808add1155SRico Sonntag public function longestLifeFemaleAge(): string 8818add1155SRico Sonntag { 8828add1155SRico Sonntag return $this->longlifeQuery('age', 'F'); 8838add1155SRico Sonntag } 8848add1155SRico Sonntag 8858add1155SRico Sonntag /** 8868add1155SRico Sonntag * Find the name of the longest lived female. 8878add1155SRico Sonntag * 8888add1155SRico Sonntag * @return string 8898add1155SRico Sonntag */ 8908add1155SRico Sonntag public function longestLifeFemaleName(): string 8918add1155SRico Sonntag { 8928add1155SRico Sonntag return $this->longlifeQuery('name', 'F'); 8938add1155SRico Sonntag } 8948add1155SRico Sonntag 8958add1155SRico Sonntag /** 8968add1155SRico Sonntag * Find the longest lived male. 8978add1155SRico Sonntag * 8988add1155SRico Sonntag * @return string 8998add1155SRico Sonntag */ 9008add1155SRico Sonntag public function longestLifeMale(): string 9018add1155SRico Sonntag { 9028add1155SRico Sonntag return $this->longlifeQuery('full', 'M'); 9038add1155SRico Sonntag } 9048add1155SRico Sonntag 9058add1155SRico Sonntag /** 9068add1155SRico Sonntag * Find the age of the longest lived male. 9078add1155SRico Sonntag * 9088add1155SRico Sonntag * @return string 9098add1155SRico Sonntag */ 9108add1155SRico Sonntag public function longestLifeMaleAge(): string 9118add1155SRico Sonntag { 9128add1155SRico Sonntag return $this->longlifeQuery('age', 'M'); 9138add1155SRico Sonntag } 9148add1155SRico Sonntag 9158add1155SRico Sonntag /** 9168add1155SRico Sonntag * Find the name of the longest lived male. 9178add1155SRico Sonntag * 9188add1155SRico Sonntag * @return string 9198add1155SRico Sonntag */ 9208add1155SRico Sonntag public function longestLifeMaleName(): string 9218add1155SRico Sonntag { 9228add1155SRico Sonntag return $this->longlifeQuery('name', 'M'); 9238add1155SRico Sonntag } 9248add1155SRico Sonntag 9258add1155SRico Sonntag /** 9268add1155SRico Sonntag * Returns the calculated age the time of event. 9278add1155SRico Sonntag * 9288add1155SRico Sonntag * @param int $age The age from the database record 9298add1155SRico Sonntag * 9308add1155SRico Sonntag * @return string 9318add1155SRico Sonntag */ 9328add1155SRico Sonntag private function calculateAge(int $age): string 9338add1155SRico Sonntag { 9348add1155SRico Sonntag if ((int) ($age / 365.25) > 0) { 9358add1155SRico Sonntag $result = (int) ($age / 365.25) . 'y'; 9368add1155SRico Sonntag } elseif ((int) ($age / 30.4375) > 0) { 9378add1155SRico Sonntag $result = (int) ($age / 30.4375) . 'm'; 9388add1155SRico Sonntag } else { 9398add1155SRico Sonntag $result = $age . 'd'; 9408add1155SRico Sonntag } 9418add1155SRico Sonntag 9428add1155SRico Sonntag return FunctionsDate::getAgeAtEvent($result); 9438add1155SRico Sonntag } 9448add1155SRico Sonntag 9458add1155SRico Sonntag /** 9468add1155SRico Sonntag * Find the oldest individuals. 9478add1155SRico Sonntag * 9488add1155SRico Sonntag * @param string $sex 9498add1155SRico Sonntag * @param int $total 9508add1155SRico Sonntag * 9518add1155SRico Sonntag * @return array 9528add1155SRico Sonntag */ 9538add1155SRico Sonntag private function topTenOldestQuery(string $sex, int $total): array 9548add1155SRico Sonntag { 95544cdc21eSGreg Roach $prefix = DB::connection()->getTablePrefix(); 9568add1155SRico Sonntag 95744cdc21eSGreg Roach $rows = $this->birthAndDeathQuery($sex) 95844cdc21eSGreg Roach ->groupBy(['i_id', 'i_file']) 95944cdc21eSGreg Roach ->orderBy('days', 'desc') 96044cdc21eSGreg Roach ->select(['individuals.*', DB::raw('MAX(' . $prefix . 'death.d_julianday2 - ' . $prefix . 'birth.d_julianday1) AS days')]) 96144cdc21eSGreg Roach ->take($total) 96244cdc21eSGreg Roach ->get(); 9638add1155SRico Sonntag 9648add1155SRico Sonntag $top10 = []; 9658add1155SRico Sonntag foreach ($rows as $row) { 96644cdc21eSGreg Roach /** @var Individual $individual */ 96744cdc21eSGreg Roach $individual = Individual::rowMapper()($row); 9688add1155SRico Sonntag 96944cdc21eSGreg Roach if ($individual->canShow()) { 9708add1155SRico Sonntag $top10[] = [ 97144cdc21eSGreg Roach 'person' => $individual, 97244cdc21eSGreg Roach 'age' => $this->calculateAge((int) $row->days), 9738add1155SRico Sonntag ]; 9748add1155SRico Sonntag } 9758add1155SRico Sonntag } 9768add1155SRico Sonntag 9778add1155SRico Sonntag return $top10; 9788add1155SRico Sonntag } 9798add1155SRico Sonntag 9808add1155SRico Sonntag /** 9818add1155SRico Sonntag * Find the oldest individuals. 9828add1155SRico Sonntag * 9838add1155SRico Sonntag * @param int $total 9848add1155SRico Sonntag * 9858add1155SRico Sonntag * @return string 9868add1155SRico Sonntag */ 9878add1155SRico Sonntag public function topTenOldest(int $total = 10): string 9888add1155SRico Sonntag { 9898add1155SRico Sonntag $records = $this->topTenOldestQuery('BOTH', $total); 9908add1155SRico Sonntag 9918add1155SRico Sonntag return view( 9928add1155SRico Sonntag 'statistics/individuals/top10-nolist', 9938add1155SRico Sonntag [ 9948add1155SRico Sonntag 'records' => $records, 9958add1155SRico Sonntag ] 9968add1155SRico Sonntag ); 9978add1155SRico Sonntag } 9988add1155SRico Sonntag 9998add1155SRico Sonntag /** 10008add1155SRico Sonntag * Find the oldest living individuals. 10018add1155SRico Sonntag * 10028add1155SRico Sonntag * @param int $total 10038add1155SRico Sonntag * 10048add1155SRico Sonntag * @return string 10058add1155SRico Sonntag */ 10068add1155SRico Sonntag public function topTenOldestList(int $total = 10): string 10078add1155SRico Sonntag { 10088add1155SRico Sonntag $records = $this->topTenOldestQuery('BOTH', $total); 10098add1155SRico Sonntag 10108add1155SRico Sonntag return view( 10118add1155SRico Sonntag 'statistics/individuals/top10-list', 10128add1155SRico Sonntag [ 10138add1155SRico Sonntag 'records' => $records, 10148add1155SRico Sonntag ] 10158add1155SRico Sonntag ); 10168add1155SRico Sonntag } 10178add1155SRico Sonntag 10188add1155SRico Sonntag /** 10198add1155SRico Sonntag * Find the oldest females. 10208add1155SRico Sonntag * 10218add1155SRico Sonntag * @param int $total 10228add1155SRico Sonntag * 10238add1155SRico Sonntag * @return string 10248add1155SRico Sonntag */ 10258add1155SRico Sonntag public function topTenOldestFemale(int $total = 10): string 10268add1155SRico Sonntag { 10278add1155SRico Sonntag $records = $this->topTenOldestQuery('F', $total); 10288add1155SRico Sonntag 10298add1155SRico Sonntag return view( 10308add1155SRico Sonntag 'statistics/individuals/top10-nolist', 10318add1155SRico Sonntag [ 10328add1155SRico Sonntag 'records' => $records, 10338add1155SRico Sonntag ] 10348add1155SRico Sonntag ); 10358add1155SRico Sonntag } 10368add1155SRico Sonntag 10378add1155SRico Sonntag /** 10388add1155SRico Sonntag * Find the oldest living females. 10398add1155SRico Sonntag * 10408add1155SRico Sonntag * @param int $total 10418add1155SRico Sonntag * 10428add1155SRico Sonntag * @return string 10438add1155SRico Sonntag */ 10448add1155SRico Sonntag public function topTenOldestFemaleList(int $total = 10): string 10458add1155SRico Sonntag { 10468add1155SRico Sonntag $records = $this->topTenOldestQuery('F', $total); 10478add1155SRico Sonntag 10488add1155SRico Sonntag return view( 10498add1155SRico Sonntag 'statistics/individuals/top10-list', 10508add1155SRico Sonntag [ 10518add1155SRico Sonntag 'records' => $records, 10528add1155SRico Sonntag ] 10538add1155SRico Sonntag ); 10548add1155SRico Sonntag } 10558add1155SRico Sonntag 10568add1155SRico Sonntag /** 10578add1155SRico Sonntag * Find the longest lived males. 10588add1155SRico Sonntag * 10598add1155SRico Sonntag * @param int $total 10608add1155SRico Sonntag * 10618add1155SRico Sonntag * @return string 10628add1155SRico Sonntag */ 10638add1155SRico Sonntag public function topTenOldestMale(int $total = 10): string 10648add1155SRico Sonntag { 10658add1155SRico Sonntag $records = $this->topTenOldestQuery('M', $total); 10668add1155SRico Sonntag 10678add1155SRico Sonntag return view( 10688add1155SRico Sonntag 'statistics/individuals/top10-nolist', 10698add1155SRico Sonntag [ 10708add1155SRico Sonntag 'records' => $records, 10718add1155SRico Sonntag ] 10728add1155SRico Sonntag ); 10738add1155SRico Sonntag } 10748add1155SRico Sonntag 10758add1155SRico Sonntag /** 10768add1155SRico Sonntag * Find the longest lived males. 10778add1155SRico Sonntag * 10788add1155SRico Sonntag * @param int $total 10798add1155SRico Sonntag * 10808add1155SRico Sonntag * @return string 10818add1155SRico Sonntag */ 10828add1155SRico Sonntag public function topTenOldestMaleList(int $total = 10): string 10838add1155SRico Sonntag { 10848add1155SRico Sonntag $records = $this->topTenOldestQuery('M', $total); 10858add1155SRico Sonntag 10868add1155SRico Sonntag return view( 10878add1155SRico Sonntag 'statistics/individuals/top10-list', 10888add1155SRico Sonntag [ 10898add1155SRico Sonntag 'records' => $records, 10908add1155SRico Sonntag ] 10918add1155SRico Sonntag ); 10928add1155SRico Sonntag } 10938add1155SRico Sonntag 10948add1155SRico Sonntag /** 10958add1155SRico Sonntag * Find the oldest living individuals. 10968add1155SRico Sonntag * 10978add1155SRico Sonntag * @param string $sex 10988add1155SRico Sonntag * @param int $total 10998add1155SRico Sonntag * 11008add1155SRico Sonntag * @return array 11018add1155SRico Sonntag */ 11028add1155SRico Sonntag private function topTenOldestAliveQuery(string $sex = 'BOTH', int $total = 10): array 11038add1155SRico Sonntag { 11048add1155SRico Sonntag if ($sex === 'F') { 11058add1155SRico Sonntag $sex_search = " AND i_sex='F'"; 11068add1155SRico Sonntag } elseif ($sex === 'M') { 11078add1155SRico Sonntag $sex_search = " AND i_sex='M'"; 11088add1155SRico Sonntag } else { 11098add1155SRico Sonntag $sex_search = ''; 11108add1155SRico Sonntag } 11118add1155SRico Sonntag 11128add1155SRico Sonntag $rows = $this->runSql( 11138add1155SRico Sonntag "SELECT" . 11148add1155SRico Sonntag " birth.d_gid AS id," . 11158add1155SRico Sonntag " MIN(birth.d_julianday1) AS age" . 11168add1155SRico Sonntag " FROM" . 11178add1155SRico Sonntag " `##dates` AS birth," . 11188add1155SRico Sonntag " `##individuals` AS indi" . 11198add1155SRico Sonntag " WHERE" . 11208add1155SRico Sonntag " indi.i_id=birth.d_gid AND" . 11218add1155SRico Sonntag " indi.i_gedcom NOT REGEXP '\\n1 (" . implode('|', Gedcom::DEATH_EVENTS) . ")' AND" . 11228add1155SRico Sonntag " birth.d_file={$this->tree->id()} AND" . 11238add1155SRico Sonntag " birth.d_fact='BIRT' AND" . 11248add1155SRico Sonntag " birth.d_file=indi.i_file AND" . 11258add1155SRico Sonntag " birth.d_julianday1<>0" . 11268add1155SRico Sonntag $sex_search . 11278add1155SRico Sonntag " GROUP BY id" . 11288add1155SRico Sonntag " ORDER BY age" . 11298add1155SRico Sonntag " ASC LIMIT " . $total 11308add1155SRico Sonntag ); 11318add1155SRico Sonntag 11328add1155SRico Sonntag $top10 = []; 11338add1155SRico Sonntag 11348add1155SRico Sonntag foreach ($rows as $row) { 11358add1155SRico Sonntag $person = Individual::getInstance($row->id, $this->tree); 11368add1155SRico Sonntag 11378add1155SRico Sonntag $top10[] = [ 11388add1155SRico Sonntag 'person' => $person, 11398add1155SRico Sonntag 'age' => $this->calculateAge(WT_CLIENT_JD - ((int) $row->age)), 11408add1155SRico Sonntag ]; 11418add1155SRico Sonntag } 11428add1155SRico Sonntag 11438add1155SRico Sonntag return $top10; 11448add1155SRico Sonntag } 11458add1155SRico Sonntag 11468add1155SRico Sonntag /** 11478add1155SRico Sonntag * Find the oldest living individuals. 11488add1155SRico Sonntag * 11498add1155SRico Sonntag * @param int $total 11508add1155SRico Sonntag * 11518add1155SRico Sonntag * @return string 11528add1155SRico Sonntag */ 11538add1155SRico Sonntag public function topTenOldestAlive(int $total = 10): string 11548add1155SRico Sonntag { 11558add1155SRico Sonntag if (!Auth::isMember($this->tree)) { 11568add1155SRico Sonntag return I18N::translate('This information is private and cannot be shown.'); 11578add1155SRico Sonntag } 11588add1155SRico Sonntag 11598add1155SRico Sonntag $records = $this->topTenOldestAliveQuery('BOTH', $total); 11608add1155SRico Sonntag 11618add1155SRico Sonntag return view( 11628add1155SRico Sonntag 'statistics/individuals/top10-nolist', 11638add1155SRico Sonntag [ 11648add1155SRico Sonntag 'records' => $records, 11658add1155SRico Sonntag ] 11668add1155SRico Sonntag ); 11678add1155SRico Sonntag } 11688add1155SRico Sonntag 11698add1155SRico Sonntag /** 11708add1155SRico Sonntag * Find the oldest living individuals. 11718add1155SRico Sonntag * 11728add1155SRico Sonntag * @param int $total 11738add1155SRico Sonntag * 11748add1155SRico Sonntag * @return string 11758add1155SRico Sonntag */ 11768add1155SRico Sonntag public function topTenOldestListAlive(int $total = 10): string 11778add1155SRico Sonntag { 11788add1155SRico Sonntag if (!Auth::isMember($this->tree)) { 11798add1155SRico Sonntag return I18N::translate('This information is private and cannot be shown.'); 11808add1155SRico Sonntag } 11818add1155SRico Sonntag 11828add1155SRico Sonntag $records = $this->topTenOldestAliveQuery('BOTH', $total); 11838add1155SRico Sonntag 11848add1155SRico Sonntag return view( 11858add1155SRico Sonntag 'statistics/individuals/top10-list', 11868add1155SRico Sonntag [ 11878add1155SRico Sonntag 'records' => $records, 11888add1155SRico Sonntag ] 11898add1155SRico Sonntag ); 11908add1155SRico Sonntag } 11918add1155SRico Sonntag 11928add1155SRico Sonntag /** 11938add1155SRico Sonntag * Find the oldest living females. 11948add1155SRico Sonntag * 11958add1155SRico Sonntag * @param int $total 11968add1155SRico Sonntag * 11978add1155SRico Sonntag * @return string 11988add1155SRico Sonntag */ 11998add1155SRico Sonntag public function topTenOldestFemaleAlive(int $total = 10): string 12008add1155SRico Sonntag { 12018add1155SRico Sonntag if (!Auth::isMember($this->tree)) { 12028add1155SRico Sonntag return I18N::translate('This information is private and cannot be shown.'); 12038add1155SRico Sonntag } 12048add1155SRico Sonntag 12058add1155SRico Sonntag $records = $this->topTenOldestAliveQuery('F', $total); 12068add1155SRico Sonntag 12078add1155SRico Sonntag return view( 12088add1155SRico Sonntag 'statistics/individuals/top10-nolist', 12098add1155SRico Sonntag [ 12108add1155SRico Sonntag 'records' => $records, 12118add1155SRico Sonntag ] 12128add1155SRico Sonntag ); 12138add1155SRico Sonntag } 12148add1155SRico Sonntag 12158add1155SRico Sonntag /** 12168add1155SRico Sonntag * Find the oldest living females. 12178add1155SRico Sonntag * 12188add1155SRico Sonntag * @param int $total 12198add1155SRico Sonntag * 12208add1155SRico Sonntag * @return string 12218add1155SRico Sonntag */ 12228add1155SRico Sonntag public function topTenOldestFemaleListAlive(int $total = 10): string 12238add1155SRico Sonntag { 12248add1155SRico Sonntag if (!Auth::isMember($this->tree)) { 12258add1155SRico Sonntag return I18N::translate('This information is private and cannot be shown.'); 12268add1155SRico Sonntag } 12278add1155SRico Sonntag 12288add1155SRico Sonntag $records = $this->topTenOldestAliveQuery('F', $total); 12298add1155SRico Sonntag 12308add1155SRico Sonntag return view( 12318add1155SRico Sonntag 'statistics/individuals/top10-list', 12328add1155SRico Sonntag [ 12338add1155SRico Sonntag 'records' => $records, 12348add1155SRico Sonntag ] 12358add1155SRico Sonntag ); 12368add1155SRico Sonntag } 12378add1155SRico Sonntag 12388add1155SRico Sonntag /** 12398add1155SRico Sonntag * Find the longest lived living males. 12408add1155SRico Sonntag * 12418add1155SRico Sonntag * @param int $total 12428add1155SRico Sonntag * 12438add1155SRico Sonntag * @return string 12448add1155SRico Sonntag */ 12458add1155SRico Sonntag public function topTenOldestMaleAlive(int $total = 10): string 12468add1155SRico Sonntag { 12478add1155SRico Sonntag if (!Auth::isMember($this->tree)) { 12488add1155SRico Sonntag return I18N::translate('This information is private and cannot be shown.'); 12498add1155SRico Sonntag } 12508add1155SRico Sonntag 12518add1155SRico Sonntag $records = $this->topTenOldestAliveQuery('M', $total); 12528add1155SRico Sonntag 12538add1155SRico Sonntag return view( 12548add1155SRico Sonntag 'statistics/individuals/top10-nolist', 12558add1155SRico Sonntag [ 12568add1155SRico Sonntag 'records' => $records, 12578add1155SRico Sonntag ] 12588add1155SRico Sonntag ); 12598add1155SRico Sonntag } 12608add1155SRico Sonntag 12618add1155SRico Sonntag /** 12628add1155SRico Sonntag * Find the longest lived living males. 12638add1155SRico Sonntag * 12648add1155SRico Sonntag * @param int $total 12658add1155SRico Sonntag * 12668add1155SRico Sonntag * @return string 12678add1155SRico Sonntag */ 12688add1155SRico Sonntag public function topTenOldestMaleListAlive(int $total = 10): string 12698add1155SRico Sonntag { 12708add1155SRico Sonntag if (!Auth::isMember($this->tree)) { 12718add1155SRico Sonntag return I18N::translate('This information is private and cannot be shown.'); 12728add1155SRico Sonntag } 12738add1155SRico Sonntag 12748add1155SRico Sonntag $records = $this->topTenOldestAliveQuery('M', $total); 12758add1155SRico Sonntag 12768add1155SRico Sonntag return view( 12778add1155SRico Sonntag 'statistics/individuals/top10-list', 12788add1155SRico Sonntag [ 12798add1155SRico Sonntag 'records' => $records, 12808add1155SRico Sonntag ] 12818add1155SRico Sonntag ); 12828add1155SRico Sonntag } 12838add1155SRico Sonntag 12848add1155SRico Sonntag /** 12858add1155SRico Sonntag * Find the average lifespan. 12868add1155SRico Sonntag * 12878add1155SRico Sonntag * @param string $sex 12888add1155SRico Sonntag * @param bool $show_years 12898add1155SRico Sonntag * 12908add1155SRico Sonntag * @return string 12918add1155SRico Sonntag */ 12928add1155SRico Sonntag private function averageLifespanQuery(string $sex = 'BOTH', bool $show_years = false): string 12938add1155SRico Sonntag { 129444cdc21eSGreg Roach $prefix = DB::connection()->getTablePrefix(); 12958add1155SRico Sonntag 129644cdc21eSGreg Roach $days = (int) $this->birthAndDeathQuery($sex) 1297e4235cb4SRico Sonntag ->select(DB::raw('AVG(' . $prefix . 'death.d_julianday2 - ' . $prefix . 'birth.d_julianday1) AS days')) 129844cdc21eSGreg Roach ->value('days'); 12998add1155SRico Sonntag 13008add1155SRico Sonntag if ($show_years) { 130144cdc21eSGreg Roach return $this->calculateAge($days); 13028add1155SRico Sonntag } 13038add1155SRico Sonntag 130444cdc21eSGreg Roach return I18N::number((int) ($days / 365.25)); 13058add1155SRico Sonntag } 13068add1155SRico Sonntag 13078add1155SRico Sonntag /** 13088add1155SRico Sonntag * Find the average lifespan. 13098add1155SRico Sonntag * 13108add1155SRico Sonntag * @param bool $show_years 13118add1155SRico Sonntag * 13128add1155SRico Sonntag * @return string 13138add1155SRico Sonntag */ 13148add1155SRico Sonntag public function averageLifespan($show_years = false): string 13158add1155SRico Sonntag { 13168add1155SRico Sonntag return $this->averageLifespanQuery('BOTH', $show_years); 13178add1155SRico Sonntag } 13188add1155SRico Sonntag 13198add1155SRico Sonntag /** 13208add1155SRico Sonntag * Find the average lifespan of females. 13218add1155SRico Sonntag * 13228add1155SRico Sonntag * @param bool $show_years 13238add1155SRico Sonntag * 13248add1155SRico Sonntag * @return string 13258add1155SRico Sonntag */ 13268add1155SRico Sonntag public function averageLifespanFemale($show_years = false): string 13278add1155SRico Sonntag { 13288add1155SRico Sonntag return $this->averageLifespanQuery('F', $show_years); 13298add1155SRico Sonntag } 13308add1155SRico Sonntag 13318add1155SRico Sonntag /** 13328add1155SRico Sonntag * Find the average male lifespan. 13338add1155SRico Sonntag * 13348add1155SRico Sonntag * @param bool $show_years 13358add1155SRico Sonntag * 13368add1155SRico Sonntag * @return string 13378add1155SRico Sonntag */ 13388add1155SRico Sonntag public function averageLifespanMale($show_years = false): string 13398add1155SRico Sonntag { 13408add1155SRico Sonntag return $this->averageLifespanQuery('M', $show_years); 13418add1155SRico Sonntag } 13428add1155SRico Sonntag 13438add1155SRico Sonntag /** 13448add1155SRico Sonntag * Convert totals into percentages. 13458add1155SRico Sonntag * 13468add1155SRico Sonntag * @param int $count 13478add1155SRico Sonntag * @param int $total 13488add1155SRico Sonntag * 13498add1155SRico Sonntag * @return string 13508add1155SRico Sonntag */ 13518add1155SRico Sonntag private function getPercentage(int $count, int $total): string 13528add1155SRico Sonntag { 13538add1155SRico Sonntag return I18N::percentage($count / $total, 1); 13548add1155SRico Sonntag } 13558add1155SRico Sonntag 13568add1155SRico Sonntag /** 13578add1155SRico Sonntag * Returns how many individuals exist in the tree. 13588add1155SRico Sonntag * 13598add1155SRico Sonntag * @return int 13608add1155SRico Sonntag */ 13618add1155SRico Sonntag private function totalIndividualsQuery(): int 13628add1155SRico Sonntag { 13638add1155SRico Sonntag return DB::table('individuals') 13648add1155SRico Sonntag ->where('i_file', '=', $this->tree->id()) 13658add1155SRico Sonntag ->count(); 13668add1155SRico Sonntag } 13678add1155SRico Sonntag 13688add1155SRico Sonntag /** 13698add1155SRico Sonntag * Count the number of living individuals. 13708add1155SRico Sonntag * 13718add1155SRico Sonntag * The totalLiving/totalDeceased queries assume that every dead person will 13728add1155SRico Sonntag * have a DEAT record. It will not include individuals who were born more 13738add1155SRico Sonntag * than MAX_ALIVE_AGE years ago, and who have no DEAT record. 13748add1155SRico Sonntag * A good reason to run the “Add missing DEAT records” batch-update! 13758add1155SRico Sonntag * 13768add1155SRico Sonntag * @return int 13778add1155SRico Sonntag */ 13788add1155SRico Sonntag private function totalLivingQuery(): int 13798add1155SRico Sonntag { 13803dc8167dSGreg Roach $query = DB::table('individuals') 13813dc8167dSGreg Roach ->where('i_file', '=', $this->tree->id()); 13823dc8167dSGreg Roach 13833dc8167dSGreg Roach foreach (Gedcom::DEATH_EVENTS as $death_event) { 138468d9d7c9SRico Sonntag $query->where('i_gedcom', 'NOT LIKE', "%\n1 " . $death_event . '%'); 13853dc8167dSGreg Roach } 13863dc8167dSGreg Roach 13873dc8167dSGreg Roach return $query->count(); 13888add1155SRico Sonntag } 13898add1155SRico Sonntag 13908add1155SRico Sonntag /** 13918add1155SRico Sonntag * Count the number of dead individuals. 13928add1155SRico Sonntag * 13938add1155SRico Sonntag * @return int 13948add1155SRico Sonntag */ 13958add1155SRico Sonntag private function totalDeceasedQuery(): int 13968add1155SRico Sonntag { 13978add1155SRico Sonntag return DB::table('individuals') 13988add1155SRico Sonntag ->where('i_file', '=', $this->tree->id()) 13993dc8167dSGreg Roach ->where(function (Builder $query): void { 14003dc8167dSGreg Roach foreach (Gedcom::DEATH_EVENTS as $death_event) { 140168d9d7c9SRico Sonntag $query->orWhere('i_gedcom', 'LIKE', "%\n1 " . $death_event . '%'); 14023dc8167dSGreg Roach } 14033dc8167dSGreg Roach }) 14048add1155SRico Sonntag ->count(); 14058add1155SRico Sonntag } 14068add1155SRico Sonntag 14078add1155SRico Sonntag /** 14088add1155SRico Sonntag * Returns the total count of a specific sex. 14098add1155SRico Sonntag * 14108add1155SRico Sonntag * @param string $sex The sex to query 14118add1155SRico Sonntag * 14128add1155SRico Sonntag * @return int 14138add1155SRico Sonntag */ 14148add1155SRico Sonntag private function getTotalSexQuery(string $sex): int 14158add1155SRico Sonntag { 14168add1155SRico Sonntag return DB::table('individuals') 14178add1155SRico Sonntag ->where('i_file', '=', $this->tree->id()) 14188add1155SRico Sonntag ->where('i_sex', '=', $sex) 14198add1155SRico Sonntag ->count(); 14208add1155SRico Sonntag } 14218add1155SRico Sonntag 14228add1155SRico Sonntag /** 14238add1155SRico Sonntag * Returns the total number of males. 14248add1155SRico Sonntag * 14258add1155SRico Sonntag * @return int 14268add1155SRico Sonntag */ 14278add1155SRico Sonntag private function totalSexMalesQuery(): int 14288add1155SRico Sonntag { 14298add1155SRico Sonntag return $this->getTotalSexQuery('M'); 14308add1155SRico Sonntag } 14318add1155SRico Sonntag 14328add1155SRico Sonntag /** 14338add1155SRico Sonntag * Returns the total number of females. 14348add1155SRico Sonntag * 14358add1155SRico Sonntag * @return int 14368add1155SRico Sonntag */ 14378add1155SRico Sonntag private function totalSexFemalesQuery(): int 14388add1155SRico Sonntag { 14398add1155SRico Sonntag return $this->getTotalSexQuery('F'); 14408add1155SRico Sonntag } 14418add1155SRico Sonntag 14428add1155SRico Sonntag /** 14438add1155SRico Sonntag * Returns the total number of individuals with unknown sex. 14448add1155SRico Sonntag * 14458add1155SRico Sonntag * @return int 14468add1155SRico Sonntag */ 14478add1155SRico Sonntag private function totalSexUnknownQuery(): int 14488add1155SRico Sonntag { 14498add1155SRico Sonntag return $this->getTotalSexQuery('U'); 14508add1155SRico Sonntag } 14518add1155SRico Sonntag 14528add1155SRico Sonntag /** 14538add1155SRico Sonntag * Count the total families. 14548add1155SRico Sonntag * 14558add1155SRico Sonntag * @return int 14568add1155SRico Sonntag */ 14578add1155SRico Sonntag private function totalFamiliesQuery(): int 14588add1155SRico Sonntag { 14598add1155SRico Sonntag return DB::table('families') 14608add1155SRico Sonntag ->where('f_file', '=', $this->tree->id()) 14618add1155SRico Sonntag ->count(); 14628add1155SRico Sonntag } 14638add1155SRico Sonntag 14648add1155SRico Sonntag /** 14658add1155SRico Sonntag * How many individuals have one or more sources. 14668add1155SRico Sonntag * 14678add1155SRico Sonntag * @return int 14688add1155SRico Sonntag */ 14698add1155SRico Sonntag private function totalIndisWithSourcesQuery(): int 14708add1155SRico Sonntag { 14718add1155SRico Sonntag return DB::table('individuals') 14728add1155SRico Sonntag ->select(['i_id']) 14738add1155SRico Sonntag ->distinct() 14748add1155SRico Sonntag ->join('link', function (JoinClause $join) { 14758add1155SRico Sonntag $join->on('i_id', '=', 'l_from') 14768add1155SRico Sonntag ->on('i_file', '=', 'l_file'); 14778add1155SRico Sonntag }) 14788add1155SRico Sonntag ->where('l_file', '=', $this->tree->id()) 14798add1155SRico Sonntag ->where('l_type', '=', 'SOUR') 14808add1155SRico Sonntag ->count('i_id'); 14818add1155SRico Sonntag } 14828add1155SRico Sonntag 14838add1155SRico Sonntag /** 14848add1155SRico Sonntag * Count the families with source records. 14858add1155SRico Sonntag * 14868add1155SRico Sonntag * @return int 14878add1155SRico Sonntag */ 14888add1155SRico Sonntag private function totalFamsWithSourcesQuery(): int 14898add1155SRico Sonntag { 14908add1155SRico Sonntag return DB::table('families') 14918add1155SRico Sonntag ->select(['f_id']) 14928add1155SRico Sonntag ->distinct() 14938add1155SRico Sonntag ->join('link', function (JoinClause $join) { 14948add1155SRico Sonntag $join->on('f_id', '=', 'l_from') 14958add1155SRico Sonntag ->on('f_file', '=', 'l_file'); 14968add1155SRico Sonntag }) 14978add1155SRico Sonntag ->where('l_file', '=', $this->tree->id()) 14988add1155SRico Sonntag ->where('l_type', '=', 'SOUR') 14998add1155SRico Sonntag ->count('f_id'); 15008add1155SRico Sonntag } 15018add1155SRico Sonntag 15028add1155SRico Sonntag /** 15038add1155SRico Sonntag * Count the number of repositories. 15048add1155SRico Sonntag * 15058add1155SRico Sonntag * @return int 15068add1155SRico Sonntag */ 15078add1155SRico Sonntag private function totalRepositoriesQuery(): int 15088add1155SRico Sonntag { 15098add1155SRico Sonntag return DB::table('other') 15108add1155SRico Sonntag ->where('o_file', '=', $this->tree->id()) 15118add1155SRico Sonntag ->where('o_type', '=', 'REPO') 15128add1155SRico Sonntag ->count(); 15138add1155SRico Sonntag } 15148add1155SRico Sonntag 15158add1155SRico Sonntag /** 15168add1155SRico Sonntag * Count the total number of sources. 15178add1155SRico Sonntag * 15188add1155SRico Sonntag * @return int 15198add1155SRico Sonntag */ 15208add1155SRico Sonntag private function totalSourcesQuery(): int 15218add1155SRico Sonntag { 15228add1155SRico Sonntag return DB::table('sources') 15238add1155SRico Sonntag ->where('s_file', '=', $this->tree->id()) 15248add1155SRico Sonntag ->count(); 15258add1155SRico Sonntag } 15268add1155SRico Sonntag 15278add1155SRico Sonntag /** 15288add1155SRico Sonntag * Count the number of notes. 15298add1155SRico Sonntag * 15308add1155SRico Sonntag * @return int 15318add1155SRico Sonntag */ 15328add1155SRico Sonntag private function totalNotesQuery(): int 15338add1155SRico Sonntag { 15348add1155SRico Sonntag return DB::table('other') 15358add1155SRico Sonntag ->where('o_file', '=', $this->tree->id()) 15368add1155SRico Sonntag ->where('o_type', '=', 'NOTE') 15378add1155SRico Sonntag ->count(); 15388add1155SRico Sonntag } 15398add1155SRico Sonntag 15408add1155SRico Sonntag /** 15418add1155SRico Sonntag * Returns the total number of records. 15428add1155SRico Sonntag * 15438add1155SRico Sonntag * @return int 15448add1155SRico Sonntag */ 15458add1155SRico Sonntag private function totalRecordsQuery(): int 15468add1155SRico Sonntag { 15478add1155SRico Sonntag return $this->totalIndividualsQuery() 15488add1155SRico Sonntag + $this->totalFamiliesQuery() 15498add1155SRico Sonntag + $this->totalNotesQuery() 15508add1155SRico Sonntag + $this->totalRepositoriesQuery() 15518add1155SRico Sonntag + $this->totalSourcesQuery(); 15528add1155SRico Sonntag } 15538add1155SRico Sonntag 15548add1155SRico Sonntag /** 15558add1155SRico Sonntag * @inheritDoc 15568add1155SRico Sonntag */ 15578add1155SRico Sonntag public function totalRecords(): string 15588add1155SRico Sonntag { 15598add1155SRico Sonntag return I18N::number($this->totalRecordsQuery()); 15608add1155SRico Sonntag } 15618add1155SRico Sonntag 15628add1155SRico Sonntag /** 15638add1155SRico Sonntag * @inheritDoc 15648add1155SRico Sonntag */ 15658add1155SRico Sonntag public function totalIndividuals(): string 15668add1155SRico Sonntag { 15678add1155SRico Sonntag return I18N::number($this->totalIndividualsQuery()); 15688add1155SRico Sonntag } 15698add1155SRico Sonntag 15708add1155SRico Sonntag /** 15718add1155SRico Sonntag * Count the number of living individuals. 15728add1155SRico Sonntag * 15738add1155SRico Sonntag * @return string 15748add1155SRico Sonntag */ 15758add1155SRico Sonntag public function totalLiving(): string 15768add1155SRico Sonntag { 15778add1155SRico Sonntag return I18N::number($this->totalLivingQuery()); 15788add1155SRico Sonntag } 15798add1155SRico Sonntag 15808add1155SRico Sonntag /** 15818add1155SRico Sonntag * Count the number of dead individuals. 15828add1155SRico Sonntag * 15838add1155SRico Sonntag * @return string 15848add1155SRico Sonntag */ 15858add1155SRico Sonntag public function totalDeceased(): string 15868add1155SRico Sonntag { 15878add1155SRico Sonntag return I18N::number($this->totalDeceasedQuery()); 15888add1155SRico Sonntag } 15898add1155SRico Sonntag 15908add1155SRico Sonntag /** 15918add1155SRico Sonntag * @inheritDoc 15928add1155SRico Sonntag */ 15938add1155SRico Sonntag public function totalSexMales(): string 15948add1155SRico Sonntag { 15958add1155SRico Sonntag return I18N::number($this->totalSexMalesQuery()); 15968add1155SRico Sonntag } 15978add1155SRico Sonntag 15988add1155SRico Sonntag /** 15998add1155SRico Sonntag * @inheritDoc 16008add1155SRico Sonntag */ 16018add1155SRico Sonntag public function totalSexFemales(): string 16028add1155SRico Sonntag { 16038add1155SRico Sonntag return I18N::number($this->totalSexFemalesQuery()); 16048add1155SRico Sonntag } 16058add1155SRico Sonntag 16068add1155SRico Sonntag /** 16078add1155SRico Sonntag * @inheritDoc 16088add1155SRico Sonntag */ 16098add1155SRico Sonntag public function totalSexUnknown(): string 16108add1155SRico Sonntag { 16118add1155SRico Sonntag return I18N::number($this->totalSexUnknownQuery()); 16128add1155SRico Sonntag } 16138add1155SRico Sonntag 16148add1155SRico Sonntag /** 16158add1155SRico Sonntag * @inheritDoc 16168add1155SRico Sonntag */ 16178add1155SRico Sonntag public function totalFamilies(): string 16188add1155SRico Sonntag { 16198add1155SRico Sonntag return I18N::number($this->totalFamiliesQuery()); 16208add1155SRico Sonntag } 16218add1155SRico Sonntag 16228add1155SRico Sonntag /** 16238add1155SRico Sonntag * How many individuals have one or more sources. 16248add1155SRico Sonntag * 16258add1155SRico Sonntag * @return string 16268add1155SRico Sonntag */ 16278add1155SRico Sonntag public function totalIndisWithSources(): string 16288add1155SRico Sonntag { 16298add1155SRico Sonntag return I18N::number($this->totalIndisWithSourcesQuery()); 16308add1155SRico Sonntag } 16318add1155SRico Sonntag 16328add1155SRico Sonntag /** 16338add1155SRico Sonntag * Count the families with with source records. 16348add1155SRico Sonntag * 16358add1155SRico Sonntag * @return string 16368add1155SRico Sonntag */ 16378add1155SRico Sonntag public function totalFamsWithSources(): string 16388add1155SRico Sonntag { 16398add1155SRico Sonntag return I18N::number($this->totalFamsWithSourcesQuery()); 16408add1155SRico Sonntag } 16418add1155SRico Sonntag 16428add1155SRico Sonntag /** 16438add1155SRico Sonntag * @inheritDoc 16448add1155SRico Sonntag */ 16458add1155SRico Sonntag public function totalRepositories(): string 16468add1155SRico Sonntag { 16478add1155SRico Sonntag return I18N::number($this->totalRepositoriesQuery()); 16488add1155SRico Sonntag } 16498add1155SRico Sonntag 16508add1155SRico Sonntag /** 16518add1155SRico Sonntag * @inheritDoc 16528add1155SRico Sonntag */ 16538add1155SRico Sonntag public function totalSources(): string 16548add1155SRico Sonntag { 16558add1155SRico Sonntag return I18N::number($this->totalSourcesQuery()); 16568add1155SRico Sonntag } 16578add1155SRico Sonntag 16588add1155SRico Sonntag /** 16598add1155SRico Sonntag * @inheritDoc 16608add1155SRico Sonntag */ 16618add1155SRico Sonntag public function totalNotes(): string 16628add1155SRico Sonntag { 16638add1155SRico Sonntag return I18N::number($this->totalNotesQuery()); 16648add1155SRico Sonntag } 16658add1155SRico Sonntag 16668add1155SRico Sonntag /** 16678add1155SRico Sonntag * @inheritDoc 16688add1155SRico Sonntag */ 16698add1155SRico Sonntag public function totalIndividualsPercentage(): string 16708add1155SRico Sonntag { 16718add1155SRico Sonntag return $this->getPercentage( 16728add1155SRico Sonntag $this->totalIndividualsQuery(), 16738add1155SRico Sonntag $this->totalRecordsQuery() 16748add1155SRico Sonntag ); 16758add1155SRico Sonntag } 16768add1155SRico Sonntag 16778add1155SRico Sonntag /** 16788add1155SRico Sonntag * @inheritDoc 16798add1155SRico Sonntag */ 16808add1155SRico Sonntag public function totalFamiliesPercentage(): string 16818add1155SRico Sonntag { 16828add1155SRico Sonntag return $this->getPercentage( 16838add1155SRico Sonntag $this->totalFamiliesQuery(), 16848add1155SRico Sonntag $this->totalRecordsQuery() 16858add1155SRico Sonntag ); 16868add1155SRico Sonntag } 16878add1155SRico Sonntag 16888add1155SRico Sonntag /** 16898add1155SRico Sonntag * @inheritDoc 16908add1155SRico Sonntag */ 16918add1155SRico Sonntag public function totalRepositoriesPercentage(): string 16928add1155SRico Sonntag { 16938add1155SRico Sonntag return $this->getPercentage( 16948add1155SRico Sonntag $this->totalRepositoriesQuery(), 16958add1155SRico Sonntag $this->totalRecordsQuery() 16968add1155SRico Sonntag ); 16978add1155SRico Sonntag } 16988add1155SRico Sonntag 16998add1155SRico Sonntag /** 17008add1155SRico Sonntag * @inheritDoc 17018add1155SRico Sonntag */ 17028add1155SRico Sonntag public function totalSourcesPercentage(): string 17038add1155SRico Sonntag { 17048add1155SRico Sonntag return $this->getPercentage( 17058add1155SRico Sonntag $this->totalSourcesQuery(), 17068add1155SRico Sonntag $this->totalRecordsQuery() 17078add1155SRico Sonntag ); 17088add1155SRico Sonntag } 17098add1155SRico Sonntag 17108add1155SRico Sonntag /** 17118add1155SRico Sonntag * @inheritDoc 17128add1155SRico Sonntag */ 17138add1155SRico Sonntag public function totalNotesPercentage(): string 17148add1155SRico Sonntag { 17158add1155SRico Sonntag return $this->getPercentage( 17168add1155SRico Sonntag $this->totalNotesQuery(), 17178add1155SRico Sonntag $this->totalRecordsQuery() 17188add1155SRico Sonntag ); 17198add1155SRico Sonntag } 17208add1155SRico Sonntag 17218add1155SRico Sonntag /** 17228add1155SRico Sonntag * @inheritDoc 17238add1155SRico Sonntag */ 17248add1155SRico Sonntag public function totalLivingPercentage(): string 17258add1155SRico Sonntag { 17268add1155SRico Sonntag return $this->getPercentage( 17278add1155SRico Sonntag $this->totalLivingQuery(), 17288add1155SRico Sonntag $this->totalIndividualsQuery() 17298add1155SRico Sonntag ); 17308add1155SRico Sonntag } 17318add1155SRico Sonntag 17328add1155SRico Sonntag /** 17338add1155SRico Sonntag * @inheritDoc 17348add1155SRico Sonntag */ 17358add1155SRico Sonntag public function totalDeceasedPercentage(): string 17368add1155SRico Sonntag { 17378add1155SRico Sonntag return $this->getPercentage( 17388add1155SRico Sonntag $this->totalDeceasedQuery(), 17398add1155SRico Sonntag $this->totalIndividualsQuery() 17408add1155SRico Sonntag ); 17418add1155SRico Sonntag } 17428add1155SRico Sonntag 17438add1155SRico Sonntag /** 17448add1155SRico Sonntag * @inheritDoc 17458add1155SRico Sonntag */ 17468add1155SRico Sonntag public function totalSexMalesPercentage(): string 17478add1155SRico Sonntag { 17488add1155SRico Sonntag return $this->getPercentage( 17498add1155SRico Sonntag $this->totalSexMalesQuery(), 17508add1155SRico Sonntag $this->totalIndividualsQuery() 17518add1155SRico Sonntag ); 17528add1155SRico Sonntag } 17538add1155SRico Sonntag 17548add1155SRico Sonntag /** 17558add1155SRico Sonntag * @inheritDoc 17568add1155SRico Sonntag */ 17578add1155SRico Sonntag public function totalSexFemalesPercentage(): string 17588add1155SRico Sonntag { 17598add1155SRico Sonntag return $this->getPercentage( 17608add1155SRico Sonntag $this->totalSexFemalesQuery(), 17618add1155SRico Sonntag $this->totalIndividualsQuery() 17628add1155SRico Sonntag ); 17638add1155SRico Sonntag } 17648add1155SRico Sonntag 17658add1155SRico Sonntag /** 17668add1155SRico Sonntag * @inheritDoc 17678add1155SRico Sonntag */ 17688add1155SRico Sonntag public function totalSexUnknownPercentage(): string 17698add1155SRico Sonntag { 17708add1155SRico Sonntag return $this->getPercentage( 17718add1155SRico Sonntag $this->totalSexUnknownQuery(), 17728add1155SRico Sonntag $this->totalIndividualsQuery() 17738add1155SRico Sonntag ); 17748add1155SRico Sonntag } 17758add1155SRico Sonntag 17768add1155SRico Sonntag /** 17778add1155SRico Sonntag * Create a chart of common given names. 17788add1155SRico Sonntag * 17798add1155SRico Sonntag * @param string|null $size 17808add1155SRico Sonntag * @param string|null $color_from 17818add1155SRico Sonntag * @param string|null $color_to 17828add1155SRico Sonntag * @param int $maxtoshow 17838add1155SRico Sonntag * 17848add1155SRico Sonntag * @return string 17858add1155SRico Sonntag */ 17868add1155SRico Sonntag public function chartCommonGiven( 17878add1155SRico Sonntag string $size = null, 17888add1155SRico Sonntag string $color_from = null, 17898add1155SRico Sonntag string $color_to = null, 17908add1155SRico Sonntag int $maxtoshow = 7 17918add1155SRico Sonntag ): string { 17928add1155SRico Sonntag $tot_indi = $this->totalIndividualsQuery(); 17938add1155SRico Sonntag $given = $this->commonGivenQuery('B', 'chart', false, 1, $maxtoshow); 17948add1155SRico Sonntag 17958add1155SRico Sonntag return (new ChartCommonGiven()) 17968add1155SRico Sonntag ->chartCommonGiven($tot_indi, $given, $size, $color_from, $color_to); 17978add1155SRico Sonntag } 17988add1155SRico Sonntag 17998add1155SRico Sonntag /** 18008add1155SRico Sonntag * Create a chart of common surnames. 18018add1155SRico Sonntag * 18028add1155SRico Sonntag * @param string|null $size 18038add1155SRico Sonntag * @param string|null $color_from 18048add1155SRico Sonntag * @param string|null $color_to 18058add1155SRico Sonntag * @param int $number_of_surnames 18068add1155SRico Sonntag * 18078add1155SRico Sonntag * @return string 18088add1155SRico Sonntag */ 18098add1155SRico Sonntag public function chartCommonSurnames( 18108add1155SRico Sonntag string $size = null, 18118add1155SRico Sonntag string $color_from = null, 18128add1155SRico Sonntag string $color_to = null, 18138add1155SRico Sonntag int $number_of_surnames = 10 18148add1155SRico Sonntag ): string { 18158add1155SRico Sonntag $tot_indi = $this->totalIndividualsQuery(); 18168add1155SRico Sonntag $all_surnames = $this->topSurnames($number_of_surnames, 0); 18178add1155SRico Sonntag 18188add1155SRico Sonntag return (new ChartCommonSurname($this->tree)) 18198add1155SRico Sonntag ->chartCommonSurnames($tot_indi, $all_surnames, $size, $color_from, $color_to); 18208add1155SRico Sonntag } 18218add1155SRico Sonntag 18228add1155SRico Sonntag /** 18238add1155SRico Sonntag * Create a chart showing mortality. 18248add1155SRico Sonntag * 18258add1155SRico Sonntag * @param string|null $size 18268add1155SRico Sonntag * @param string|null $color_living 18278add1155SRico Sonntag * @param string|null $color_dead 18288add1155SRico Sonntag * 18298add1155SRico Sonntag * @return string 18308add1155SRico Sonntag */ 18318add1155SRico Sonntag public function chartMortality(string $size = null, string $color_living = null, string $color_dead = null): string 18328add1155SRico Sonntag { 18338add1155SRico Sonntag $tot_l = $this->totalLivingQuery(); 18348add1155SRico Sonntag $tot_d = $this->totalDeceasedQuery(); 18358add1155SRico Sonntag 18368add1155SRico Sonntag return (new ChartMortality($this->tree)) 18378add1155SRico Sonntag ->chartMortality($tot_l, $tot_d, $size, $color_living, $color_dead); 18388add1155SRico Sonntag } 18398add1155SRico Sonntag 18408add1155SRico Sonntag /** 18418add1155SRico Sonntag * Create a chart showing individuals with/without sources. 18428add1155SRico Sonntag * 18438add1155SRico Sonntag * @param string|null $size 18448add1155SRico Sonntag * @param string|null $color_from 18458add1155SRico Sonntag * @param string|null $color_to 18468add1155SRico Sonntag * 18478add1155SRico Sonntag * @return string 18488add1155SRico Sonntag */ 18498add1155SRico Sonntag public function chartIndisWithSources( 18508add1155SRico Sonntag string $size = null, 18518add1155SRico Sonntag string $color_from = null, 18528add1155SRico Sonntag string $color_to = null 18538add1155SRico Sonntag ): string { 18548add1155SRico Sonntag $tot_indi = $this->totalIndividualsQuery(); 18558add1155SRico Sonntag $tot_indi_source = $this->totalIndisWithSourcesQuery(); 18568add1155SRico Sonntag 18578add1155SRico Sonntag return (new ChartIndividual()) 18588add1155SRico Sonntag ->chartIndisWithSources($tot_indi, $tot_indi_source, $size, $color_from, $color_to); 18598add1155SRico Sonntag } 18608add1155SRico Sonntag 18618add1155SRico Sonntag /** 18628add1155SRico Sonntag * Create a chart of individuals with/without sources. 18638add1155SRico Sonntag * 18648add1155SRico Sonntag * @param string|null $size 18658add1155SRico Sonntag * @param string|null $color_from 18668add1155SRico Sonntag * @param string|null $color_to 18678add1155SRico Sonntag * 18688add1155SRico Sonntag * @return string 18698add1155SRico Sonntag */ 18708add1155SRico Sonntag public function chartFamsWithSources( 18718add1155SRico Sonntag string $size = null, 18728add1155SRico Sonntag string $color_from = null, 18738add1155SRico Sonntag string $color_to = null 18748add1155SRico Sonntag ): string { 18758add1155SRico Sonntag $tot_fam = $this->totalFamiliesQuery(); 18768add1155SRico Sonntag $tot_fam_source = $this->totalFamsWithSourcesQuery(); 18778add1155SRico Sonntag 18788add1155SRico Sonntag return (new ChartFamilyWithSources()) 18798add1155SRico Sonntag ->chartFamsWithSources($tot_fam, $tot_fam_source, $size, $color_from, $color_to); 18808add1155SRico Sonntag } 18818add1155SRico Sonntag 18828add1155SRico Sonntag /** 18838add1155SRico Sonntag * @inheritDoc 18848add1155SRico Sonntag */ 18858add1155SRico Sonntag public function chartSex( 18868add1155SRico Sonntag string $size = null, 18878add1155SRico Sonntag string $color_female = null, 18888add1155SRico Sonntag string $color_male = null, 18898add1155SRico Sonntag string $color_unknown = null 18908add1155SRico Sonntag ): string { 18918add1155SRico Sonntag $tot_m = $this->totalSexMalesQuery(); 18928add1155SRico Sonntag $tot_f = $this->totalSexFemalesQuery(); 18938add1155SRico Sonntag $tot_u = $this->totalSexUnknownQuery(); 18948add1155SRico Sonntag 18958add1155SRico Sonntag return (new ChartSex($this->tree)) 18968add1155SRico Sonntag ->chartSex($tot_m, $tot_f, $tot_u, $size, $color_female, $color_male, $color_unknown); 18978add1155SRico Sonntag } 189844cdc21eSGreg Roach 189944cdc21eSGreg Roach /** 190044cdc21eSGreg Roach * Query individuals, with their births and deaths. 190144cdc21eSGreg Roach * 190244cdc21eSGreg Roach * @param string $sex 190344cdc21eSGreg Roach * 190444cdc21eSGreg Roach * @return Builder 190544cdc21eSGreg Roach */ 1906e2cbf57aSGreg Roach private function birthAndDeathQuery(string $sex): Builder 1907e2cbf57aSGreg Roach { 190844cdc21eSGreg Roach $query = DB::table('individuals') 190944cdc21eSGreg Roach ->where('i_file', '=', $this->tree->id()) 191044cdc21eSGreg Roach ->join('dates AS birth', function (JoinClause $join): void { 191144cdc21eSGreg Roach $join 191244cdc21eSGreg Roach ->on('birth.d_file', '=', 'i_file') 191344cdc21eSGreg Roach ->on('birth.d_gid', '=', 'i_id'); 191444cdc21eSGreg Roach }) 191544cdc21eSGreg Roach ->join('dates AS death', function (JoinClause $join): void { 191644cdc21eSGreg Roach $join 191744cdc21eSGreg Roach ->on('death.d_file', '=', 'i_file') 191844cdc21eSGreg Roach ->on('death.d_gid', '=', 'i_id'); 191944cdc21eSGreg Roach }) 192044cdc21eSGreg Roach ->where('birth.d_fact', '=', 'BIRT') 192144cdc21eSGreg Roach ->where('death.d_fact', '=', 'DEAT') 192244cdc21eSGreg Roach ->whereColumn('death.d_julianday1', '>=', 'birth.d_julianday2') 192344cdc21eSGreg Roach ->where('birth.d_julianday2', '<>', 0); 192444cdc21eSGreg Roach 192544cdc21eSGreg Roach if ($sex === 'M' || $sex === 'F') { 192644cdc21eSGreg Roach $query->where('i_sex', '=', $sex); 192744cdc21eSGreg Roach } 192844cdc21eSGreg Roach 192944cdc21eSGreg Roach return $query; 193044cdc21eSGreg Roach } 19318add1155SRico Sonntag} 1932