13763c3f2SGreg Roach<?php 23763c3f2SGreg Roach/** 33763c3f2SGreg Roach * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team 53763c3f2SGreg Roach * This program is free software: you can redistribute it and/or modify 63763c3f2SGreg Roach * it under the terms of the GNU General Public License as published by 73763c3f2SGreg Roach * the Free Software Foundation, either version 3 of the License, or 83763c3f2SGreg Roach * (at your option) any later version. 93763c3f2SGreg Roach * This program is distributed in the hope that it will be useful, 103763c3f2SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 113763c3f2SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 123763c3f2SGreg Roach * GNU General Public License for more details. 133763c3f2SGreg Roach * You should have received a copy of the GNU General Public License 143763c3f2SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 153763c3f2SGreg Roach */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 1876692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module; 1976692c8bSGreg Roach 2063276d8fSGreg Roachuse Fisharebest\Webtrees\Auth; 210e62c4b8SGreg Roachuse Fisharebest\Webtrees\Date; 220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Fact; 230e62c4b8SGreg Roachuse Fisharebest\Webtrees\Family; 248d0ebef0SGreg Roachuse Fisharebest\Webtrees\Gedcom; 250e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 260e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual; 272adcbd9aSGreg Roachuse Fisharebest\Webtrees\Services\ClipboardService; 284ca7e03cSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 2917c50b57SGreg Roachuse Illuminate\Support\Collection; 303763c3f2SGreg Roach 313763c3f2SGreg Roach/** 323763c3f2SGreg Roach * Class IndividualFactsTabModule 333763c3f2SGreg Roach */ 3437eb8894SGreg Roachclass IndividualFactsTabModule extends AbstractModule implements ModuleTabInterface 35c1010edaSGreg Roach{ 3649a243cbSGreg Roach use ModuleTabTrait; 3749a243cbSGreg Roach 382adcbd9aSGreg Roach /** @var ModuleService */ 394ca7e03cSGreg Roach private $module_service; 404ca7e03cSGreg Roach 412adcbd9aSGreg Roach /** @var ClipboardService */ 422adcbd9aSGreg Roach private $clipboard_service; 432adcbd9aSGreg Roach 444ca7e03cSGreg Roach /** 454ca7e03cSGreg Roach * UserWelcomeModule constructor. 464ca7e03cSGreg Roach * 474ca7e03cSGreg Roach * @param ModuleService $module_service 482adcbd9aSGreg Roach * @param ClipboardService $clipboard_service 494ca7e03cSGreg Roach */ 502adcbd9aSGreg Roach public function __construct(ModuleService $module_service, ClipboardService $clipboard_service) 515bdbe281SGreg Roach { 524ca7e03cSGreg Roach $this->module_service = $module_service; 532adcbd9aSGreg Roach $this->clipboard_service = $clipboard_service; 544ca7e03cSGreg Roach } 554ca7e03cSGreg Roach 564ca7e03cSGreg Roach /** 57961ec755SGreg Roach * How should this module be labelled on tabs, menus, etc.? 58961ec755SGreg Roach * 59961ec755SGreg Roach * @return string 60961ec755SGreg Roach */ 6149a243cbSGreg Roach public function title(): string 62c1010edaSGreg Roach { 63bbb76c12SGreg Roach /* I18N: Name of a module/tab on the individual page. */ 64bbb76c12SGreg Roach return I18N::translate('Facts and events'); 653763c3f2SGreg Roach } 663763c3f2SGreg Roach 67961ec755SGreg Roach /** 68961ec755SGreg Roach * A sentence describing what this module does. 69961ec755SGreg Roach * 70961ec755SGreg Roach * @return string 71961ec755SGreg Roach */ 7249a243cbSGreg Roach public function description(): string 73c1010edaSGreg Roach { 74bbb76c12SGreg Roach /* I18N: Description of the “Facts and events” module */ 75bbb76c12SGreg Roach return I18N::translate('A tab showing the facts and events of an individual.'); 763763c3f2SGreg Roach } 773763c3f2SGreg Roach 7849a243cbSGreg Roach /** 7949a243cbSGreg Roach * The default position for this tab. It can be changed in the control panel. 8049a243cbSGreg Roach * 8149a243cbSGreg Roach * @return int 8249a243cbSGreg Roach */ 83cbf4b7faSGreg Roach public function defaultTabOrder(): int 84cbf4b7faSGreg Roach { 85*fb7a0427SGreg Roach return 1; 863763c3f2SGreg Roach } 873763c3f2SGreg Roach 883763c3f2SGreg Roach /** {@inheritdoc} */ 898f53f488SRico Sonntag public function isGrayedOut(Individual $individual): bool 90c1010edaSGreg Roach { 913763c3f2SGreg Roach return false; 923763c3f2SGreg Roach } 933763c3f2SGreg Roach 943763c3f2SGreg Roach /** {@inheritdoc} */ 959b34404bSGreg Roach public function getTabContent(Individual $individual): string 96c1010edaSGreg Roach { 97ee727175SGreg Roach // Only include events of close relatives that are between birth and death 98ee727175SGreg Roach $min_date = $individual->getEstimatedBirthDate(); 99ee727175SGreg Roach $max_date = $individual->getEstimatedDeathDate(); 100ee727175SGreg Roach 1018eaf8709SGreg Roach // Which facts and events are handled by other modules? 1028eaf8709SGreg Roach $sidebar_facts = $this->module_service 10387cca37cSGreg Roach ->findByComponent(ModuleSidebarInterface::class, $individual->tree(), Auth::user()) 1048eaf8709SGreg Roach ->map(function (ModuleSidebarInterface $sidebar): Collection { 1058eaf8709SGreg Roach return $sidebar->supportedFacts(); 1068eaf8709SGreg Roach }); 1078eaf8709SGreg Roach 1088eaf8709SGreg Roach $tab_facts = $this->module_service 10987cca37cSGreg Roach ->findByComponent(ModuleTabInterface::class, $individual->tree(), Auth::user()) 1108eaf8709SGreg Roach ->map(function (ModuleTabInterface $sidebar): Collection { 1118eaf8709SGreg Roach return $sidebar->supportedFacts(); 1128eaf8709SGreg Roach }); 1138eaf8709SGreg Roach 1148eaf8709SGreg Roach $exclude_facts = $sidebar_facts->merge($tab_facts)->flatten(); 1158eaf8709SGreg Roach 1168eaf8709SGreg Roach 1173763c3f2SGreg Roach // The individual’s own facts 11839ca88baSGreg Roach $indifacts = $individual->facts() 11939ca88baSGreg Roach ->filter(function (Fact $fact) use ($exclude_facts): bool { 12039ca88baSGreg Roach return !$exclude_facts->contains($fact->getTag()); 12139ca88baSGreg Roach }); 1223763c3f2SGreg Roach 1233763c3f2SGreg Roach // Add spouse-family facts 12439ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 12530158ae7SGreg Roach foreach ($family->facts() as $fact) { 1268eaf8709SGreg Roach if (!$exclude_facts->contains($fact->getTag()) && $fact->getTag() !== 'CHAN') { 12739ca88baSGreg Roach $indifacts->push($fact); 1283763c3f2SGreg Roach } 1293763c3f2SGreg Roach } 130ee727175SGreg Roach 13139ca88baSGreg Roach $spouse = $family->spouse($individual); 132ee727175SGreg Roach 133ee727175SGreg Roach if ($spouse instanceof Individual) { 1348b9cfadbSGreg Roach $spouse_facts = $this->spouseFacts($individual, $spouse, $min_date, $max_date); 13539ca88baSGreg Roach $indifacts = $indifacts->merge($spouse_facts); 1363763c3f2SGreg Roach } 1373763c3f2SGreg Roach 1388b9cfadbSGreg Roach $child_facts = $this->childFacts($individual, $family, '_CHIL', '', $min_date, $max_date); 13939ca88baSGreg Roach $indifacts = $indifacts->merge($child_facts); 1403763c3f2SGreg Roach } 141225e381fSGreg Roach 1428b9cfadbSGreg Roach $parent_facts = $this->parentFacts($individual, 1, $min_date, $max_date); 1438b9cfadbSGreg Roach $associate_facts = $this->associateFacts($individual); 1448b9cfadbSGreg Roach $historical_facts = $this->historicalFacts($individual); 145225e381fSGreg Roach 14639ca88baSGreg Roach $indifacts = $indifacts 14739ca88baSGreg Roach ->merge($parent_facts) 14839ca88baSGreg Roach ->merge($associate_facts) 14939ca88baSGreg Roach ->merge($historical_facts); 1503763c3f2SGreg Roach 151580a4d11SGreg Roach $indifacts = Fact::sortFacts($indifacts); 1523763c3f2SGreg Roach 153a8cd57e1SGreg Roach return view('modules/personal_facts/tab', [ 154225e381fSGreg Roach 'can_edit' => $individual->canEdit(), 1552adcbd9aSGreg Roach 'clipboard_facts' => $this->clipboard_service->pastableFacts($individual, $exclude_facts), 156ee727175SGreg Roach 'has_historical_facts' => !empty($historical_facts), 157225e381fSGreg Roach 'individual' => $individual, 158225e381fSGreg Roach 'facts' => $indifacts, 159225e381fSGreg Roach ]); 1603763c3f2SGreg Roach } 1613763c3f2SGreg Roach 162ee727175SGreg Roach /** 163ee727175SGreg Roach * Does a relative event occur within a date range (i.e. the individual's lifetime)? 164ee727175SGreg Roach * 165ee727175SGreg Roach * @param Fact $fact 166ee727175SGreg Roach * @param Date $min_date 167ee727175SGreg Roach * @param Date $max_date 168ee727175SGreg Roach * 169ee727175SGreg Roach * @return bool 170ee727175SGreg Roach */ 1718b9cfadbSGreg Roach private function includeFact(Fact $fact, Date $min_date, Date $max_date): bool 172b3b1d905SGreg Roach { 1732decada7SGreg Roach $fact_date = $fact->date(); 174ee727175SGreg Roach 175ee727175SGreg Roach return $fact_date->isOK() && Date::compare($min_date, $fact_date) <= 0 && Date::compare($fact_date, $max_date) <= 0; 176ee727175SGreg Roach } 177ee727175SGreg Roach 1783763c3f2SGreg Roach /** {@inheritdoc} */ 1798f53f488SRico Sonntag public function hasTabContent(Individual $individual): bool 180c1010edaSGreg Roach { 1813763c3f2SGreg Roach return true; 1823763c3f2SGreg Roach } 1833763c3f2SGreg Roach 1843763c3f2SGreg Roach /** {@inheritdoc} */ 1858f53f488SRico Sonntag public function canLoadAjax(): bool 186c1010edaSGreg Roach { 18715d603e7SGreg Roach return false; 1883763c3f2SGreg Roach } 1893763c3f2SGreg Roach 1903763c3f2SGreg Roach /** 1913763c3f2SGreg Roach * Spouse facts that are shown on an individual’s page. 1923763c3f2SGreg Roach * 1933763c3f2SGreg Roach * @param Individual $individual Show events that occured during the lifetime of this individual 1943763c3f2SGreg Roach * @param Individual $spouse Show events of this individual 195ee727175SGreg Roach * @param Date $min_date 196ee727175SGreg Roach * @param Date $max_date 1973763c3f2SGreg Roach * 1983763c3f2SGreg Roach * @return Fact[] 1993763c3f2SGreg Roach */ 2008b9cfadbSGreg Roach private function spouseFacts(Individual $individual, Individual $spouse, Date $min_date, Date $max_date): array 201c1010edaSGreg Roach { 202f4afa648SGreg Roach $SHOW_RELATIVES_EVENTS = $individual->tree()->getPreference('SHOW_RELATIVES_EVENTS'); 2033763c3f2SGreg Roach 20413abd6f3SGreg Roach $facts = []; 2053763c3f2SGreg Roach if (strstr($SHOW_RELATIVES_EVENTS, '_DEAT_SPOU')) { 2068d0ebef0SGreg Roach foreach ($spouse->facts(Gedcom::DEATH_EVENTS) as $fact) { 2078b9cfadbSGreg Roach if ($this->includeFact($fact, $min_date, $max_date)) { 2083763c3f2SGreg Roach // Convert the event to a close relatives event. 2093763c3f2SGreg Roach $rela_fact = clone($fact); 2103763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_SPOU'); 2113763c3f2SGreg Roach $facts[] = $rela_fact; 2123763c3f2SGreg Roach } 2133763c3f2SGreg Roach } 2143763c3f2SGreg Roach } 2153763c3f2SGreg Roach 2163763c3f2SGreg Roach return $facts; 2173763c3f2SGreg Roach } 2183763c3f2SGreg Roach 2193763c3f2SGreg Roach /** 2203763c3f2SGreg Roach * Get the events of children and grandchildren. 2213763c3f2SGreg Roach * 2223763c3f2SGreg Roach * @param Individual $person 2233763c3f2SGreg Roach * @param Family $family 2243763c3f2SGreg Roach * @param string $option 2253763c3f2SGreg Roach * @param string $relation 226ee727175SGreg Roach * @param Date $min_date 227ee727175SGreg Roach * @param Date $max_date 2283763c3f2SGreg Roach * 2293763c3f2SGreg Roach * @return Fact[] 2303763c3f2SGreg Roach */ 2318b9cfadbSGreg Roach private function childFacts(Individual $person, Family $family, $option, $relation, Date $min_date, Date $max_date): array 232c1010edaSGreg Roach { 233f4afa648SGreg Roach $SHOW_RELATIVES_EVENTS = $person->tree()->getPreference('SHOW_RELATIVES_EVENTS'); 2343763c3f2SGreg Roach 23513abd6f3SGreg Roach $facts = []; 2363763c3f2SGreg Roach 2373763c3f2SGreg Roach // Deal with recursion. 2383763c3f2SGreg Roach switch ($option) { 2393763c3f2SGreg Roach case '_CHIL': 2403763c3f2SGreg Roach // Add grandchildren 24139ca88baSGreg Roach foreach ($family->children() as $child) { 24239ca88baSGreg Roach foreach ($child->spouseFamilies() as $cfamily) { 24339ca88baSGreg Roach switch ($child->sex()) { 2443763c3f2SGreg Roach case 'M': 2458b9cfadbSGreg Roach foreach ($this->childFacts($person, $cfamily, '_GCHI', 'son', $min_date, $max_date) as $fact) { 2463763c3f2SGreg Roach $facts[] = $fact; 2473763c3f2SGreg Roach } 2483763c3f2SGreg Roach break; 2493763c3f2SGreg Roach case 'F': 2508b9cfadbSGreg Roach foreach ($this->childFacts($person, $cfamily, '_GCHI', 'dau', $min_date, $max_date) as $fact) { 2513763c3f2SGreg Roach $facts[] = $fact; 2523763c3f2SGreg Roach } 2533763c3f2SGreg Roach break; 2543763c3f2SGreg Roach default: 2558b9cfadbSGreg Roach foreach ($this->childFacts($person, $cfamily, '_GCHI', 'chi', $min_date, $max_date) as $fact) { 2563763c3f2SGreg Roach $facts[] = $fact; 2573763c3f2SGreg Roach } 2583763c3f2SGreg Roach break; 2593763c3f2SGreg Roach } 2603763c3f2SGreg Roach } 2613763c3f2SGreg Roach } 2623763c3f2SGreg Roach break; 2633763c3f2SGreg Roach } 2643763c3f2SGreg Roach 2653763c3f2SGreg Roach // For each child in the family 26639ca88baSGreg Roach foreach ($family->children() as $child) { 267c0935879SGreg Roach if ($child->xref() == $person->xref()) { 2683763c3f2SGreg Roach // We are not our own sibling! 2693763c3f2SGreg Roach continue; 2703763c3f2SGreg Roach } 2713763c3f2SGreg Roach // add child’s birth 2723763c3f2SGreg Roach if (strpos($SHOW_RELATIVES_EVENTS, '_BIRT' . str_replace('_HSIB', '_SIBL', $option)) !== false) { 2738d0ebef0SGreg Roach foreach ($child->facts(Gedcom::BIRTH_EVENTS) as $fact) { 2743763c3f2SGreg Roach // Always show _BIRT_CHIL, even if the dates are not known 2758b9cfadbSGreg Roach if ($option == '_CHIL' || $this->includeFact($fact, $min_date, $max_date)) { 2763763c3f2SGreg Roach if ($option == '_GCHI' && $relation == 'dau') { 2773763c3f2SGreg Roach // Convert the event to a close relatives event. 2783763c3f2SGreg Roach $rela_fact = clone($fact); 2793763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_GCH1'); 2803763c3f2SGreg Roach $facts[] = $rela_fact; 2813763c3f2SGreg Roach } elseif ($option == '_GCHI' && $relation == 'son') { 2823763c3f2SGreg Roach // Convert the event to a close relatives event. 2833763c3f2SGreg Roach $rela_fact = clone($fact); 2843763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_GCH2'); 2853763c3f2SGreg Roach $facts[] = $rela_fact; 2863763c3f2SGreg Roach } else { 2873763c3f2SGreg Roach // Convert the event to a close relatives event. 2883763c3f2SGreg Roach $rela_fact = clone($fact); 2893763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . $option); 2903763c3f2SGreg Roach $facts[] = $rela_fact; 2913763c3f2SGreg Roach } 2923763c3f2SGreg Roach } 2933763c3f2SGreg Roach } 2943763c3f2SGreg Roach } 2953763c3f2SGreg Roach // add child’s death 2963763c3f2SGreg Roach if (strpos($SHOW_RELATIVES_EVENTS, '_DEAT' . str_replace('_HSIB', '_SIBL', $option)) !== false) { 2978d0ebef0SGreg Roach foreach ($child->facts(Gedcom::DEATH_EVENTS) as $fact) { 2988b9cfadbSGreg Roach if ($this->includeFact($fact, $min_date, $max_date)) { 2993763c3f2SGreg Roach if ($option == '_GCHI' && $relation == 'dau') { 3003763c3f2SGreg Roach // Convert the event to a close relatives event. 3013763c3f2SGreg Roach $rela_fact = clone($fact); 3023763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_GCH1'); 3033763c3f2SGreg Roach $facts[] = $rela_fact; 3043763c3f2SGreg Roach } elseif ($option == '_GCHI' && $relation == 'son') { 3053763c3f2SGreg Roach // Convert the event to a close relatives event. 3063763c3f2SGreg Roach $rela_fact = clone($fact); 3073763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_GCH2'); 3083763c3f2SGreg Roach $facts[] = $rela_fact; 3093763c3f2SGreg Roach } else { 3103763c3f2SGreg Roach // Convert the event to a close relatives event. 3113763c3f2SGreg Roach $rela_fact = clone($fact); 3123763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . $option); 3133763c3f2SGreg Roach $facts[] = $rela_fact; 3143763c3f2SGreg Roach } 3153763c3f2SGreg Roach } 3163763c3f2SGreg Roach } 3173763c3f2SGreg Roach } 3183763c3f2SGreg Roach // add child’s marriage 3193763c3f2SGreg Roach if (strstr($SHOW_RELATIVES_EVENTS, '_MARR' . str_replace('_HSIB', '_SIBL', $option))) { 32039ca88baSGreg Roach foreach ($child->spouseFamilies() as $sfamily) { 3218d0ebef0SGreg Roach foreach ($sfamily->facts(['MARR']) as $fact) { 3228b9cfadbSGreg Roach if ($this->includeFact($fact, $min_date, $max_date)) { 3233763c3f2SGreg Roach if ($option == '_GCHI' && $relation == 'dau') { 3243763c3f2SGreg Roach // Convert the event to a close relatives event. 3253763c3f2SGreg Roach $rela_fact = clone($fact); 3263763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_GCH1'); 3273763c3f2SGreg Roach $facts[] = $rela_fact; 3283763c3f2SGreg Roach } elseif ($option == '_GCHI' && $relation == 'son') { 3293763c3f2SGreg Roach // Convert the event to a close relatives event. 3303763c3f2SGreg Roach $rela_fact = clone($fact); 3313763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_GCH2'); 3323763c3f2SGreg Roach $facts[] = $rela_fact; 3333763c3f2SGreg Roach } else { 3343763c3f2SGreg Roach // Convert the event to a close relatives event. 3353763c3f2SGreg Roach $rela_fact = clone($fact); 3363763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . $option); 3373763c3f2SGreg Roach $facts[] = $rela_fact; 3383763c3f2SGreg Roach } 3393763c3f2SGreg Roach } 3403763c3f2SGreg Roach } 3413763c3f2SGreg Roach } 3423763c3f2SGreg Roach } 3433763c3f2SGreg Roach } 3443763c3f2SGreg Roach 3453763c3f2SGreg Roach return $facts; 3463763c3f2SGreg Roach } 3473763c3f2SGreg Roach 3483763c3f2SGreg Roach /** 3493763c3f2SGreg Roach * Get the events of parents and grandparents. 3503763c3f2SGreg Roach * 3513763c3f2SGreg Roach * @param Individual $person 352cbc1590aSGreg Roach * @param int $sosa 353ee727175SGreg Roach * @param Date $min_date 354ee727175SGreg Roach * @param Date $max_date 3553763c3f2SGreg Roach * 3563763c3f2SGreg Roach * @return Fact[] 3573763c3f2SGreg Roach */ 3588b9cfadbSGreg Roach private function parentFacts(Individual $person, $sosa, Date $min_date, Date $max_date): array 359c1010edaSGreg Roach { 360f4afa648SGreg Roach $SHOW_RELATIVES_EVENTS = $person->tree()->getPreference('SHOW_RELATIVES_EVENTS'); 3613763c3f2SGreg Roach 36213abd6f3SGreg Roach $facts = []; 3633763c3f2SGreg Roach 3643763c3f2SGreg Roach if ($sosa == 1) { 36539ca88baSGreg Roach foreach ($person->childFamilies() as $family) { 3663763c3f2SGreg Roach // Add siblings 3678b9cfadbSGreg Roach foreach ($this->childFacts($person, $family, '_SIBL', '', $min_date, $max_date) as $fact) { 3683763c3f2SGreg Roach $facts[] = $fact; 3693763c3f2SGreg Roach } 37039ca88baSGreg Roach foreach ($family->spouses() as $spouse) { 37139ca88baSGreg Roach foreach ($spouse->spouseFamilies() as $sfamily) { 3723763c3f2SGreg Roach if ($family !== $sfamily) { 3733763c3f2SGreg Roach // Add half-siblings 3748b9cfadbSGreg Roach foreach ($this->childFacts($person, $sfamily, '_HSIB', '', $min_date, $max_date) as $fact) { 3753763c3f2SGreg Roach $facts[] = $fact; 3763763c3f2SGreg Roach } 3773763c3f2SGreg Roach } 3783763c3f2SGreg Roach } 3793763c3f2SGreg Roach // Add grandparents 38039ca88baSGreg Roach foreach ($this->parentFacts($spouse, $spouse->sex() == 'F' ? 3 : 2, $min_date, $max_date) as $fact) { 3813763c3f2SGreg Roach $facts[] = $fact; 3823763c3f2SGreg Roach } 3833763c3f2SGreg Roach } 3843763c3f2SGreg Roach } 3853763c3f2SGreg Roach 3863763c3f2SGreg Roach if (strstr($SHOW_RELATIVES_EVENTS, '_MARR_PARE')) { 3873763c3f2SGreg Roach // add father/mother marriages 38839ca88baSGreg Roach foreach ($person->childFamilies() as $sfamily) { 3898d0ebef0SGreg Roach foreach ($sfamily->facts(['MARR']) as $fact) { 3908b9cfadbSGreg Roach if ($this->includeFact($fact, $min_date, $max_date)) { 3913763c3f2SGreg Roach // marriage of parents (to each other) 3923763c3f2SGreg Roach $rela_fact = clone($fact); 3933763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_FAMC'); 3943763c3f2SGreg Roach $facts[] = $rela_fact; 3953763c3f2SGreg Roach } 3963763c3f2SGreg Roach } 3973763c3f2SGreg Roach } 39839ca88baSGreg Roach foreach ($person->childStepFamilies() as $sfamily) { 3998d0ebef0SGreg Roach foreach ($sfamily->facts(['MARR']) as $fact) { 4008b9cfadbSGreg Roach if ($this->includeFact($fact, $min_date, $max_date)) { 4013763c3f2SGreg Roach // marriage of a parent (to another spouse) 4023763c3f2SGreg Roach // Convert the event to a close relatives event 4033763c3f2SGreg Roach $rela_fact = clone($fact); 4043763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_PARE'); 4053763c3f2SGreg Roach $facts[] = $rela_fact; 4063763c3f2SGreg Roach } 4073763c3f2SGreg Roach } 4083763c3f2SGreg Roach } 4093763c3f2SGreg Roach } 4103763c3f2SGreg Roach } 4113763c3f2SGreg Roach 41239ca88baSGreg Roach foreach ($person->childFamilies() as $family) { 41339ca88baSGreg Roach foreach ($family->spouses() as $parent) { 4143763c3f2SGreg Roach if (strstr($SHOW_RELATIVES_EVENTS, '_DEAT' . ($sosa == 1 ? '_PARE' : '_GPAR'))) { 4158d0ebef0SGreg Roach foreach ($parent->facts(Gedcom::DEATH_EVENTS) as $fact) { 4168b9cfadbSGreg Roach if ($this->includeFact($fact, $min_date, $max_date)) { 4173763c3f2SGreg Roach switch ($sosa) { 4183763c3f2SGreg Roach case 1: 4193763c3f2SGreg Roach // Convert the event to a close relatives event. 4203763c3f2SGreg Roach $rela_fact = clone($fact); 4213763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_PARE'); 4223763c3f2SGreg Roach $facts[] = $rela_fact; 4233763c3f2SGreg Roach break; 4243763c3f2SGreg Roach case 2: 4253763c3f2SGreg Roach // Convert the event to a close relatives event 4263763c3f2SGreg Roach $rela_fact = clone($fact); 4273763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_GPA1'); 4283763c3f2SGreg Roach $facts[] = $rela_fact; 4293763c3f2SGreg Roach break; 4303763c3f2SGreg Roach case 3: 4313763c3f2SGreg Roach // Convert the event to a close relatives event 4323763c3f2SGreg Roach $rela_fact = clone($fact); 4333763c3f2SGreg Roach $rela_fact->setTag('_' . $fact->getTag() . '_GPA2'); 4343763c3f2SGreg Roach $facts[] = $rela_fact; 4353763c3f2SGreg Roach break; 4363763c3f2SGreg Roach } 4373763c3f2SGreg Roach } 4383763c3f2SGreg Roach } 4393763c3f2SGreg Roach } 4403763c3f2SGreg Roach } 4413763c3f2SGreg Roach } 4423763c3f2SGreg Roach 4433763c3f2SGreg Roach return $facts; 4443763c3f2SGreg Roach } 4453763c3f2SGreg Roach 4463763c3f2SGreg Roach /** 4473763c3f2SGreg Roach * Get any historical events. 4483763c3f2SGreg Roach * 44917c50b57SGreg Roach * @param Individual $individual 4503763c3f2SGreg Roach * 4513763c3f2SGreg Roach * @return Fact[] 4523763c3f2SGreg Roach */ 4534ca7e03cSGreg Roach private function historicalFacts(Individual $individual): array 454c1010edaSGreg Roach { 4554ca7e03cSGreg Roach return $this->module_service->findByInterface(ModuleHistoricEventsInterface::class) 45617c50b57SGreg Roach ->map(function (ModuleHistoricEventsInterface $module) use ($individual): Collection { 45717c50b57SGreg Roach return $module->historicEventsForIndividual($individual); 45817c50b57SGreg Roach }) 45917c50b57SGreg Roach ->flatten() 46017c50b57SGreg Roach ->all(); 4613763c3f2SGreg Roach } 4623763c3f2SGreg Roach 4633763c3f2SGreg Roach /** 4643763c3f2SGreg Roach * Get the events of associates. 4653763c3f2SGreg Roach * 4663763c3f2SGreg Roach * @param Individual $person 4673763c3f2SGreg Roach * 4683763c3f2SGreg Roach * @return Fact[] 4693763c3f2SGreg Roach */ 4708b9cfadbSGreg Roach private function associateFacts(Individual $person): array 471c1010edaSGreg Roach { 47213abd6f3SGreg Roach $facts = []; 4733763c3f2SGreg Roach 474ee727175SGreg Roach /** @var Individual[] $associates */ 4753763c3f2SGreg Roach $associates = array_merge( 4763763c3f2SGreg Roach $person->linkedIndividuals('ASSO'), 4773763c3f2SGreg Roach $person->linkedIndividuals('_ASSO'), 4783763c3f2SGreg Roach $person->linkedFamilies('ASSO'), 4793763c3f2SGreg Roach $person->linkedFamilies('_ASSO') 4803763c3f2SGreg Roach ); 4813763c3f2SGreg Roach foreach ($associates as $associate) { 48230158ae7SGreg Roach foreach ($associate->facts() as $fact) { 4833425616eSGreg Roach $arec = $fact->attribute('_ASSO'); 4843763c3f2SGreg Roach if (!$arec) { 4853425616eSGreg Roach $arec = $fact->attribute('ASSO'); 4863763c3f2SGreg Roach } 487c0935879SGreg Roach if ($arec && trim($arec, '@') === $person->xref()) { 4883763c3f2SGreg Roach // Extract the important details from the fact 4893763c3f2SGreg Roach $factrec = '1 ' . $fact->getTag(); 490138ca96cSGreg Roach if (preg_match('/\n2 DATE .*/', $fact->gedcom(), $match)) { 4913763c3f2SGreg Roach $factrec .= $match[0]; 4923763c3f2SGreg Roach } 493138ca96cSGreg Roach if (preg_match('/\n2 PLAC .*/', $fact->gedcom(), $match)) { 4943763c3f2SGreg Roach $factrec .= $match[0]; 4953763c3f2SGreg Roach } 4963763c3f2SGreg Roach if ($associate instanceof Family) { 49739ca88baSGreg Roach foreach ($associate->spouses() as $spouse) { 498c0935879SGreg Roach $factrec .= "\n2 _ASSO @" . $spouse->xref() . '@'; 4993763c3f2SGreg Roach } 5003763c3f2SGreg Roach } else { 501c0935879SGreg Roach $factrec .= "\n2 _ASSO @" . $associate->xref() . '@'; 5023763c3f2SGreg Roach } 5033763c3f2SGreg Roach $facts[] = new Fact($factrec, $associate, 'asso'); 5043763c3f2SGreg Roach } 5053763c3f2SGreg Roach } 5063763c3f2SGreg Roach } 5073763c3f2SGreg Roach 5083763c3f2SGreg Roach return $facts; 5093763c3f2SGreg Roach } 5108eaf8709SGreg Roach 5118eaf8709SGreg Roach /** 5128eaf8709SGreg Roach * This module handles the following facts - so don't show them on the "Facts and events" tab. 5138eaf8709SGreg Roach * 5148eaf8709SGreg Roach * @return Collection|string[] 5158eaf8709SGreg Roach */ 5168eaf8709SGreg Roach public function supportedFacts(): Collection 5178eaf8709SGreg Roach { 5188eaf8709SGreg Roach // We don't actually displaye these facts, but they are displayed 5198eaf8709SGreg Roach // outside the tabs/sidebar systems. This just forces them to be excluded here. 5208eaf8709SGreg Roach return new Collection(['NAME', 'SEX']); 5218eaf8709SGreg Roach } 5223763c3f2SGreg Roach} 523