18add1155SRico Sonntag<?php 28add1155SRico Sonntag/** 38add1155SRico Sonntag * webtrees: online genealogy 4242a7862SGreg Roach * Copyright (C) 2019 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\Date; 21*820b62dfSGreg Roachuse Fisharebest\Webtrees\Fact; 228add1155SRico Sonntaguse Fisharebest\Webtrees\Functions\FunctionsPrint; 238add1155SRico Sonntaguse Fisharebest\Webtrees\GedcomRecord; 248add1155SRico Sonntaguse Fisharebest\Webtrees\I18N; 258add1155SRico Sonntaguse Fisharebest\Webtrees\Statistics\Repository\Interfaces\FamilyDatesRepositoryInterface; 268add1155SRico Sonntaguse Fisharebest\Webtrees\Tree; 278add1155SRico Sonntaguse Illuminate\Database\Capsule\Manager as DB; 288add1155SRico Sonntaguse Illuminate\Database\Eloquent\Model; 298add1155SRico Sonntaguse Illuminate\Database\Query\Builder; 308add1155SRico Sonntag 318add1155SRico Sonntag/** 328add1155SRico Sonntag * A repository providing methods for family dates related statistics (birth, death, marriage, divorce). 338add1155SRico Sonntag */ 348add1155SRico Sonntagclass FamilyDatesRepository implements FamilyDatesRepositoryInterface 358add1155SRico Sonntag{ 368add1155SRico Sonntag /** 378add1155SRico Sonntag * Sorting directions. 388add1155SRico Sonntag */ 398add1155SRico Sonntag private const SORT_MIN = 'MIN'; 408add1155SRico Sonntag private const SORT_MAX = 'MAX'; 418add1155SRico Sonntag 428add1155SRico Sonntag /** 438add1155SRico Sonntag * Event facts. 448add1155SRico Sonntag */ 458add1155SRico Sonntag private const EVENT_BIRTH = 'BIRT'; 468add1155SRico Sonntag private const EVENT_DEATH = 'DEAT'; 478add1155SRico Sonntag private const EVENT_MARRIAGE = 'MARR'; 488add1155SRico Sonntag private const EVENT_DIVORCE = 'DIV'; 498add1155SRico Sonntag 508add1155SRico Sonntag /** 518add1155SRico Sonntag * @var Tree 528add1155SRico Sonntag */ 538add1155SRico Sonntag private $tree; 548add1155SRico Sonntag 558add1155SRico Sonntag /** 568add1155SRico Sonntag * Constructor. 578add1155SRico Sonntag * 588add1155SRico Sonntag * @param Tree $tree 598add1155SRico Sonntag */ 608add1155SRico Sonntag public function __construct(Tree $tree) 618add1155SRico Sonntag { 628add1155SRico Sonntag $this->tree = $tree; 638add1155SRico Sonntag } 648add1155SRico Sonntag 658add1155SRico Sonntag /** 668add1155SRico Sonntag * Returns the first/last event record for the given event fact. 678add1155SRico Sonntag * 688add1155SRico Sonntag * @param string $fact 698add1155SRico Sonntag * @param string $operation 708add1155SRico Sonntag * 718add1155SRico Sonntag * @return Model|object|static|null 728add1155SRico Sonntag */ 738add1155SRico Sonntag private function eventQuery(string $fact, string $operation) 748add1155SRico Sonntag { 758add1155SRico Sonntag return DB::table('dates') 768add1155SRico Sonntag ->select(['d_gid as id', 'd_year as year', 'd_fact AS fact', 'd_type AS type']) 778add1155SRico Sonntag ->where('d_file', '=', $this->tree->id()) 788add1155SRico Sonntag ->where('d_fact', '=', $fact) 798add1155SRico Sonntag ->where('d_julianday1', '=', function (Builder $query) use ($operation, $fact) { 808add1155SRico Sonntag $query->selectRaw($operation . '(d_julianday1)') 818add1155SRico Sonntag ->from('dates') 828add1155SRico Sonntag ->where('d_file', '=', $this->tree->id()) 838add1155SRico Sonntag ->where('d_fact', '=', $fact) 848add1155SRico Sonntag ->where('d_julianday1', '<>', 0); 858add1155SRico Sonntag }) 868add1155SRico Sonntag ->first(); 878add1155SRico Sonntag } 888add1155SRico Sonntag 898add1155SRico Sonntag /** 908add1155SRico Sonntag * Returns the formatted year of the first/last occuring event. 918add1155SRico Sonntag * 928add1155SRico Sonntag * @param string $type The fact to query 938add1155SRico Sonntag * @param string $operation The sorting operation 948add1155SRico Sonntag * 958add1155SRico Sonntag * @return string 968add1155SRico Sonntag */ 978add1155SRico Sonntag private function getFirstLastEvent(string $type, string $operation): string 988add1155SRico Sonntag { 998add1155SRico Sonntag $row = $this->eventQuery($type, $operation); 100dd7dd2a1SRico Sonntag $result = I18N::translate('This information is not available.'); 1018add1155SRico Sonntag 1028add1155SRico Sonntag if ($row) { 1038add1155SRico Sonntag $record = GedcomRecord::getInstance($row->id, $this->tree); 1048add1155SRico Sonntag 1058add1155SRico Sonntag if ($record && $record->canShow()) { 1068add1155SRico Sonntag $result = $record->formatList(); 1078add1155SRico Sonntag } else { 1088add1155SRico Sonntag $result = I18N::translate('This information is private and cannot be shown.'); 1098add1155SRico Sonntag } 1108add1155SRico Sonntag } 1118add1155SRico Sonntag 1128add1155SRico Sonntag return $result; 1138add1155SRico Sonntag } 1148add1155SRico Sonntag 1158add1155SRico Sonntag /** 1168add1155SRico Sonntag * @inheritDoc 1178add1155SRico Sonntag */ 1188add1155SRico Sonntag public function firstBirth(): string 1198add1155SRico Sonntag { 1208add1155SRico Sonntag return $this->getFirstLastEvent(self::EVENT_BIRTH, self::SORT_MIN); 1218add1155SRico Sonntag } 1228add1155SRico Sonntag 1238add1155SRico Sonntag /** 1248add1155SRico Sonntag * @inheritDoc 1258add1155SRico Sonntag */ 1268add1155SRico Sonntag public function lastBirth(): string 1278add1155SRico Sonntag { 1288add1155SRico Sonntag return $this->getFirstLastEvent(self::EVENT_BIRTH, self::SORT_MAX); 1298add1155SRico Sonntag } 1308add1155SRico Sonntag 1318add1155SRico Sonntag /** 1328add1155SRico Sonntag * @inheritDoc 1338add1155SRico Sonntag */ 1348add1155SRico Sonntag public function firstDeath(): string 1358add1155SRico Sonntag { 1368add1155SRico Sonntag return $this->getFirstLastEvent(self::EVENT_DEATH, self::SORT_MIN); 1378add1155SRico Sonntag } 1388add1155SRico Sonntag 1398add1155SRico Sonntag /** 1408add1155SRico Sonntag * @inheritDoc 1418add1155SRico Sonntag */ 1428add1155SRico Sonntag public function lastDeath(): string 1438add1155SRico Sonntag { 1448add1155SRico Sonntag return $this->getFirstLastEvent(self::EVENT_DEATH, self::SORT_MAX); 1458add1155SRico Sonntag } 1468add1155SRico Sonntag 1478add1155SRico Sonntag /** 1488add1155SRico Sonntag * @inheritDoc 1498add1155SRico Sonntag */ 1508add1155SRico Sonntag public function firstMarriage(): string 1518add1155SRico Sonntag { 1528add1155SRico Sonntag return $this->getFirstLastEvent(self::EVENT_MARRIAGE, self::SORT_MIN); 1538add1155SRico Sonntag } 1548add1155SRico Sonntag 1558add1155SRico Sonntag /** 1568add1155SRico Sonntag * @inheritDoc 1578add1155SRico Sonntag */ 1588add1155SRico Sonntag public function lastMarriage(): string 1598add1155SRico Sonntag { 1608add1155SRico Sonntag return $this->getFirstLastEvent(self::EVENT_MARRIAGE, self::SORT_MAX); 1618add1155SRico Sonntag } 1628add1155SRico Sonntag 1638add1155SRico Sonntag /** 1648add1155SRico Sonntag * @inheritDoc 1658add1155SRico Sonntag */ 1668add1155SRico Sonntag public function firstDivorce(): string 1678add1155SRico Sonntag { 1688add1155SRico Sonntag return $this->getFirstLastEvent(self::EVENT_DIVORCE, self::SORT_MIN); 1698add1155SRico Sonntag } 1708add1155SRico Sonntag 1718add1155SRico Sonntag /** 1728add1155SRico Sonntag * @inheritDoc 1738add1155SRico Sonntag */ 1748add1155SRico Sonntag public function lastDivorce(): string 1758add1155SRico Sonntag { 1768add1155SRico Sonntag return $this->getFirstLastEvent(self::EVENT_DIVORCE, self::SORT_MAX); 1778add1155SRico Sonntag } 1788add1155SRico Sonntag 1798add1155SRico Sonntag /** 1808add1155SRico Sonntag * Returns the formatted year of the first/last occuring event. 1818add1155SRico Sonntag * 1828add1155SRico Sonntag * @param string $type The fact to query 1838add1155SRico Sonntag * @param string $operation The sorting operation 1848add1155SRico Sonntag * 1858add1155SRico Sonntag * @return string 1868add1155SRico Sonntag */ 1878add1155SRico Sonntag private function getFirstLastEventYear(string $type, string $operation): string 1888add1155SRico Sonntag { 1898add1155SRico Sonntag $row = $this->eventQuery($type, $operation); 1908add1155SRico Sonntag 1918add1155SRico Sonntag if (!$row) { 1928add1155SRico Sonntag return ''; 1938add1155SRico Sonntag } 1948add1155SRico Sonntag 1958add1155SRico Sonntag if ($row->year < 0) { 1968add1155SRico Sonntag $row->year = abs($row->year) . ' B.C.'; 1978add1155SRico Sonntag } 1988add1155SRico Sonntag 1998add1155SRico Sonntag return (new Date($row->type . ' ' . $row->year)) 2008add1155SRico Sonntag ->display(); 2018add1155SRico Sonntag } 2028add1155SRico Sonntag 2038add1155SRico Sonntag /** 2048add1155SRico Sonntag * @inheritDoc 2058add1155SRico Sonntag */ 2068add1155SRico Sonntag public function firstBirthYear(): string 2078add1155SRico Sonntag { 2088add1155SRico Sonntag return $this->getFirstLastEventYear(self::EVENT_BIRTH, self::SORT_MIN); 2098add1155SRico Sonntag } 2108add1155SRico Sonntag 2118add1155SRico Sonntag /** 2128add1155SRico Sonntag * @inheritDoc 2138add1155SRico Sonntag */ 2148add1155SRico Sonntag public function lastBirthYear(): string 2158add1155SRico Sonntag { 2168add1155SRico Sonntag return $this->getFirstLastEventYear(self::EVENT_BIRTH, self::SORT_MAX); 2178add1155SRico Sonntag } 2188add1155SRico Sonntag 2198add1155SRico Sonntag /** 2208add1155SRico Sonntag * @inheritDoc 2218add1155SRico Sonntag */ 2228add1155SRico Sonntag public function firstDeathYear(): string 2238add1155SRico Sonntag { 2248add1155SRico Sonntag return $this->getFirstLastEventYear(self::EVENT_DEATH, self::SORT_MIN); 2258add1155SRico Sonntag } 2268add1155SRico Sonntag 2278add1155SRico Sonntag /** 2288add1155SRico Sonntag * @inheritDoc 2298add1155SRico Sonntag */ 2308add1155SRico Sonntag public function lastDeathYear(): string 2318add1155SRico Sonntag { 2328add1155SRico Sonntag return $this->getFirstLastEventYear(self::EVENT_DEATH, self::SORT_MAX); 2338add1155SRico Sonntag } 2348add1155SRico Sonntag 2358add1155SRico Sonntag /** 2368add1155SRico Sonntag * @inheritDoc 2378add1155SRico Sonntag */ 2388add1155SRico Sonntag public function firstMarriageYear(): string 2398add1155SRico Sonntag { 2408add1155SRico Sonntag return $this->getFirstLastEventYear(self::EVENT_MARRIAGE, self::SORT_MIN); 2418add1155SRico Sonntag } 2428add1155SRico Sonntag 2438add1155SRico Sonntag /** 2448add1155SRico Sonntag * @inheritDoc 2458add1155SRico Sonntag */ 2468add1155SRico Sonntag public function lastMarriageYear(): string 2478add1155SRico Sonntag { 2488add1155SRico Sonntag return $this->getFirstLastEventYear(self::EVENT_MARRIAGE, self::SORT_MAX); 2498add1155SRico Sonntag } 2508add1155SRico Sonntag 2518add1155SRico Sonntag /** 2528add1155SRico Sonntag * @inheritDoc 2538add1155SRico Sonntag */ 2548add1155SRico Sonntag public function firstDivorceYear(): string 2558add1155SRico Sonntag { 2568add1155SRico Sonntag return $this->getFirstLastEventYear(self::EVENT_DIVORCE, self::SORT_MIN); 2578add1155SRico Sonntag } 2588add1155SRico Sonntag 2598add1155SRico Sonntag /** 2608add1155SRico Sonntag * @inheritDoc 2618add1155SRico Sonntag */ 2628add1155SRico Sonntag public function lastDivorceYear(): string 2638add1155SRico Sonntag { 2648add1155SRico Sonntag return $this->getFirstLastEventYear(self::EVENT_DIVORCE, self::SORT_MAX); 2658add1155SRico Sonntag } 2668add1155SRico Sonntag 2678add1155SRico Sonntag /** 2688add1155SRico Sonntag * Returns the formatted name of the first/last occuring event. 2698add1155SRico Sonntag * 2708add1155SRico Sonntag * @param string $type The fact to query 2718add1155SRico Sonntag * @param string $operation The sorting operation 2728add1155SRico Sonntag * 2738add1155SRico Sonntag * @return string 2748add1155SRico Sonntag */ 2758add1155SRico Sonntag private function getFirstLastEventName(string $type, string $operation): string 2768add1155SRico Sonntag { 2778add1155SRico Sonntag $row = $this->eventQuery($type, $operation); 2788add1155SRico Sonntag 2798add1155SRico Sonntag if ($row) { 2808add1155SRico Sonntag $record = GedcomRecord::getInstance($row->id, $this->tree); 2818add1155SRico Sonntag 2828add1155SRico Sonntag if ($record) { 28339ca88baSGreg Roach return '<a href="' . e($record->url()) . '">' . $record->fullName() . '</a>'; 2848add1155SRico Sonntag } 2858add1155SRico Sonntag } 2868add1155SRico Sonntag 2878add1155SRico Sonntag return ''; 2888add1155SRico Sonntag } 2898add1155SRico Sonntag 2908add1155SRico Sonntag /** 2918add1155SRico Sonntag * @inheritDoc 2928add1155SRico Sonntag */ 2938add1155SRico Sonntag public function firstBirthName(): string 2948add1155SRico Sonntag { 2958add1155SRico Sonntag return $this->getFirstLastEventName(self::EVENT_BIRTH, self::SORT_MIN); 2968add1155SRico Sonntag } 2978add1155SRico Sonntag 2988add1155SRico Sonntag /** 2998add1155SRico Sonntag * @inheritDoc 3008add1155SRico Sonntag */ 3018add1155SRico Sonntag public function lastBirthName(): string 3028add1155SRico Sonntag { 3038add1155SRico Sonntag return $this->getFirstLastEventName(self::EVENT_BIRTH, self::SORT_MAX); 3048add1155SRico Sonntag } 3058add1155SRico Sonntag 3068add1155SRico Sonntag /** 3078add1155SRico Sonntag * @inheritDoc 3088add1155SRico Sonntag */ 3098add1155SRico Sonntag public function firstDeathName(): string 3108add1155SRico Sonntag { 3118add1155SRico Sonntag return $this->getFirstLastEventName(self::EVENT_DEATH, self::SORT_MIN); 3128add1155SRico Sonntag } 3138add1155SRico Sonntag 3148add1155SRico Sonntag /** 3158add1155SRico Sonntag * @inheritDoc 3168add1155SRico Sonntag */ 3178add1155SRico Sonntag public function lastDeathName(): string 3188add1155SRico Sonntag { 3198add1155SRico Sonntag return $this->getFirstLastEventName(self::EVENT_DEATH, self::SORT_MAX); 3208add1155SRico Sonntag } 3218add1155SRico Sonntag 3228add1155SRico Sonntag /** 3238add1155SRico Sonntag * @inheritDoc 3248add1155SRico Sonntag */ 3258add1155SRico Sonntag public function firstMarriageName(): string 3268add1155SRico Sonntag { 3278add1155SRico Sonntag return $this->getFirstLastEventName(self::EVENT_MARRIAGE, self::SORT_MIN); 3288add1155SRico Sonntag } 3298add1155SRico Sonntag 3308add1155SRico Sonntag /** 3318add1155SRico Sonntag * @inheritDoc 3328add1155SRico Sonntag */ 3338add1155SRico Sonntag public function lastMarriageName(): string 3348add1155SRico Sonntag { 3358add1155SRico Sonntag return $this->getFirstLastEventName(self::EVENT_MARRIAGE, self::SORT_MAX); 3368add1155SRico Sonntag } 3378add1155SRico Sonntag 3388add1155SRico Sonntag /** 3398add1155SRico Sonntag * @inheritDoc 3408add1155SRico Sonntag */ 3418add1155SRico Sonntag public function firstDivorceName(): string 3428add1155SRico Sonntag { 3438add1155SRico Sonntag return $this->getFirstLastEventName(self::EVENT_DIVORCE, self::SORT_MIN); 3448add1155SRico Sonntag } 3458add1155SRico Sonntag 3468add1155SRico Sonntag /** 3478add1155SRico Sonntag * @inheritDoc 3488add1155SRico Sonntag */ 3498add1155SRico Sonntag public function lastDivorceName(): string 3508add1155SRico Sonntag { 3518add1155SRico Sonntag return $this->getFirstLastEventName(self::EVENT_DIVORCE, self::SORT_MAX); 3528add1155SRico Sonntag } 3538add1155SRico Sonntag 3548add1155SRico Sonntag /** 3558add1155SRico Sonntag * Returns the formatted place of the first/last occuring event. 3568add1155SRico Sonntag * 3578add1155SRico Sonntag * @param string $type The fact to query 3588add1155SRico Sonntag * @param string $operation The sorting operation 3598add1155SRico Sonntag * 3608add1155SRico Sonntag * @return string 3618add1155SRico Sonntag */ 3628add1155SRico Sonntag private function getFirstLastEventPlace(string $type, string $operation): string 3638add1155SRico Sonntag { 3648add1155SRico Sonntag $row = $this->eventQuery($type, $operation); 3658add1155SRico Sonntag 3668add1155SRico Sonntag if ($row) { 3678add1155SRico Sonntag $record = GedcomRecord::getInstance($row->id, $this->tree); 3688add1155SRico Sonntag $fact = null; 3698add1155SRico Sonntag 3708add1155SRico Sonntag if ($record) { 371*820b62dfSGreg Roach $fact = $record->facts([$row->fact])->first(); 3728add1155SRico Sonntag } 3738add1155SRico Sonntag 374*820b62dfSGreg Roach if ($fact instanceof Fact) { 3758add1155SRico Sonntag return FunctionsPrint::formatFactPlace($fact, true, true, true); 3768add1155SRico Sonntag } 3778add1155SRico Sonntag } 3788add1155SRico Sonntag 379dd7dd2a1SRico Sonntag return I18N::translate('This information is private and cannot be shown.'); 3808add1155SRico Sonntag } 3818add1155SRico Sonntag 3828add1155SRico Sonntag /** 3838add1155SRico Sonntag * @inheritDoc 3848add1155SRico Sonntag */ 3858add1155SRico Sonntag public function firstBirthPlace(): string 3868add1155SRico Sonntag { 3878add1155SRico Sonntag return $this->getFirstLastEventPlace(self::EVENT_BIRTH, self::SORT_MIN); 3888add1155SRico Sonntag } 3898add1155SRico Sonntag 3908add1155SRico Sonntag /** 3918add1155SRico Sonntag * @inheritDoc 3928add1155SRico Sonntag */ 3938add1155SRico Sonntag public function lastBirthPlace(): string 3948add1155SRico Sonntag { 3958add1155SRico Sonntag return $this->getFirstLastEventPlace(self::EVENT_BIRTH, self::SORT_MAX); 3968add1155SRico Sonntag } 3978add1155SRico Sonntag 3988add1155SRico Sonntag /** 3998add1155SRico Sonntag * @inheritDoc 4008add1155SRico Sonntag */ 4018add1155SRico Sonntag public function firstDeathPlace(): string 4028add1155SRico Sonntag { 4038add1155SRico Sonntag return $this->getFirstLastEventPlace(self::EVENT_DEATH, self::SORT_MIN); 4048add1155SRico Sonntag } 4058add1155SRico Sonntag 4068add1155SRico Sonntag /** 4078add1155SRico Sonntag * @inheritDoc 4088add1155SRico Sonntag */ 4098add1155SRico Sonntag public function lastDeathPlace(): string 4108add1155SRico Sonntag { 4118add1155SRico Sonntag return $this->getFirstLastEventPlace(self::EVENT_DEATH, self::SORT_MAX); 4128add1155SRico Sonntag } 4138add1155SRico Sonntag 4148add1155SRico Sonntag /** 4158add1155SRico Sonntag * @inheritDoc 4168add1155SRico Sonntag */ 4178add1155SRico Sonntag public function firstMarriagePlace(): string 4188add1155SRico Sonntag { 4198add1155SRico Sonntag return $this->getFirstLastEventPlace(self::EVENT_MARRIAGE, self::SORT_MIN); 4208add1155SRico Sonntag } 4218add1155SRico Sonntag 4228add1155SRico Sonntag /** 4238add1155SRico Sonntag * @inheritDoc 4248add1155SRico Sonntag */ 4258add1155SRico Sonntag public function lastMarriagePlace(): string 4268add1155SRico Sonntag { 4278add1155SRico Sonntag return $this->getFirstLastEventPlace(self::EVENT_MARRIAGE, self::SORT_MAX); 4288add1155SRico Sonntag } 4298add1155SRico Sonntag 4308add1155SRico Sonntag /** 4318add1155SRico Sonntag * @inheritDoc 4328add1155SRico Sonntag */ 4338add1155SRico Sonntag public function firstDivorcePlace(): string 4348add1155SRico Sonntag { 4358add1155SRico Sonntag return $this->getFirstLastEventPlace(self::EVENT_DIVORCE, self::SORT_MIN); 4368add1155SRico Sonntag } 4378add1155SRico Sonntag 4388add1155SRico Sonntag /** 4398add1155SRico Sonntag * @inheritDoc 4408add1155SRico Sonntag */ 4418add1155SRico Sonntag public function lastDivorcePlace(): string 4428add1155SRico Sonntag { 4438add1155SRico Sonntag return $this->getFirstLastEventPlace(self::EVENT_DIVORCE, self::SORT_MAX); 4448add1155SRico Sonntag } 4458add1155SRico Sonntag} 446