xref: /webtrees/app/Module/IndividualFactsTabModule.php (revision 7bf6ca817338af2948b7380627bed6f566e43f76)
13763c3f2SGreg Roach<?php
23976b470SGreg Roach
33763c3f2SGreg Roach/**
43763c3f2SGreg Roach * webtrees: online genealogy
58fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team
63763c3f2SGreg Roach * This program is free software: you can redistribute it and/or modify
73763c3f2SGreg Roach * it under the terms of the GNU General Public License as published by
83763c3f2SGreg Roach * the Free Software Foundation, either version 3 of the License, or
93763c3f2SGreg Roach * (at your option) any later version.
103763c3f2SGreg Roach * This program is distributed in the hope that it will be useful,
113763c3f2SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
123763c3f2SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
133763c3f2SGreg Roach * GNU General Public License for more details.
143763c3f2SGreg Roach * You should have received a copy of the GNU General Public License
153763c3f2SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
163763c3f2SGreg Roach */
17fcfa147eSGreg Roach
18e7f56f2aSGreg Roachdeclare(strict_types=1);
19e7f56f2aSGreg Roach
2076692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module;
2176692c8bSGreg Roach
2263276d8fSGreg Roachuse Fisharebest\Webtrees\Auth;
230e62c4b8SGreg Roachuse Fisharebest\Webtrees\Date;
240e62c4b8SGreg Roachuse Fisharebest\Webtrees\Fact;
250e62c4b8SGreg Roachuse Fisharebest\Webtrees\Family;
268d0ebef0SGreg Roachuse Fisharebest\Webtrees\Gedcom;
270e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
280e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual;
292adcbd9aSGreg Roachuse Fisharebest\Webtrees\Services\ClipboardService;
304ca7e03cSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService;
3117c50b57SGreg Roachuse Illuminate\Support\Collection;
323763c3f2SGreg Roach
333763c3f2SGreg Roach/**
343763c3f2SGreg Roach * Class IndividualFactsTabModule
353763c3f2SGreg Roach */
3637eb8894SGreg Roachclass IndividualFactsTabModule extends AbstractModule implements ModuleTabInterface
37c1010edaSGreg Roach{
3849a243cbSGreg Roach    use ModuleTabTrait;
3949a243cbSGreg Roach
402adcbd9aSGreg Roach    /** @var ModuleService */
414ca7e03cSGreg Roach    private $module_service;
424ca7e03cSGreg Roach
432adcbd9aSGreg Roach    /** @var ClipboardService */
442adcbd9aSGreg Roach    private $clipboard_service;
452adcbd9aSGreg Roach
464ca7e03cSGreg Roach    /**
474ca7e03cSGreg Roach     * UserWelcomeModule constructor.
484ca7e03cSGreg Roach     *
494ca7e03cSGreg Roach     * @param ModuleService    $module_service
502adcbd9aSGreg Roach     * @param ClipboardService $clipboard_service
514ca7e03cSGreg Roach     */
522adcbd9aSGreg Roach    public function __construct(ModuleService $module_service, ClipboardService $clipboard_service)
535bdbe281SGreg Roach    {
544ca7e03cSGreg Roach        $this->module_service    = $module_service;
552adcbd9aSGreg Roach        $this->clipboard_service = $clipboard_service;
564ca7e03cSGreg Roach    }
574ca7e03cSGreg Roach
584ca7e03cSGreg Roach    /**
590cfd6963SGreg Roach     * How should this module be identified in the control panel, etc.?
60961ec755SGreg Roach     *
61961ec755SGreg Roach     * @return string
62961ec755SGreg Roach     */
6349a243cbSGreg Roach    public function title(): string
64c1010edaSGreg Roach    {
65bbb76c12SGreg Roach        /* I18N: Name of a module/tab on the individual page. */
66bbb76c12SGreg Roach        return I18N::translate('Facts and events');
673763c3f2SGreg Roach    }
683763c3f2SGreg Roach
69961ec755SGreg Roach    /**
70961ec755SGreg Roach     * A sentence describing what this module does.
71961ec755SGreg Roach     *
72961ec755SGreg Roach     * @return string
73961ec755SGreg Roach     */
7449a243cbSGreg Roach    public function description(): string
75c1010edaSGreg Roach    {
76bbb76c12SGreg Roach        /* I18N: Description of the “Facts and events” module */
77bbb76c12SGreg Roach        return I18N::translate('A tab showing the facts and events of an individual.');
783763c3f2SGreg Roach    }
793763c3f2SGreg Roach
8049a243cbSGreg Roach    /**
8149a243cbSGreg Roach     * The default position for this tab.  It can be changed in the control panel.
8249a243cbSGreg Roach     *
8349a243cbSGreg Roach     * @return int
8449a243cbSGreg Roach     */
85cbf4b7faSGreg Roach    public function defaultTabOrder(): int
86cbf4b7faSGreg Roach    {
87fb7a0427SGreg Roach        return 1;
883763c3f2SGreg Roach    }
893763c3f2SGreg Roach
903caaa4d2SGreg Roach    /**
913caaa4d2SGreg Roach     * A greyed out tab has no actual content, but may perhaps have
923caaa4d2SGreg Roach     * options to create content.
933caaa4d2SGreg Roach     *
943caaa4d2SGreg Roach     * @param Individual $individual
953caaa4d2SGreg Roach     *
963caaa4d2SGreg Roach     * @return bool
973caaa4d2SGreg Roach     */
988f53f488SRico Sonntag    public function isGrayedOut(Individual $individual): bool
99c1010edaSGreg Roach    {
1003763c3f2SGreg Roach        return false;
1013763c3f2SGreg Roach    }
1023763c3f2SGreg Roach
1033caaa4d2SGreg Roach    /**
1043caaa4d2SGreg Roach     * Generate the HTML content of this tab.
1053caaa4d2SGreg Roach     *
1063caaa4d2SGreg Roach     * @param Individual $individual
1073caaa4d2SGreg Roach     *
1083caaa4d2SGreg Roach     * @return string
1093caaa4d2SGreg Roach     */
1109b34404bSGreg Roach    public function getTabContent(Individual $individual): string
111c1010edaSGreg Roach    {
112ee727175SGreg Roach        // Only include events of close relatives that are between birth and death
113ee727175SGreg Roach        $min_date = $individual->getEstimatedBirthDate();
114ee727175SGreg Roach        $max_date = $individual->getEstimatedDeathDate();
115ee727175SGreg Roach
1168eaf8709SGreg Roach        // Which facts and events are handled by other modules?
1178eaf8709SGreg Roach        $sidebar_facts = $this->module_service
11887cca37cSGreg Roach            ->findByComponent(ModuleSidebarInterface::class, $individual->tree(), Auth::user())
1190b5fd0a6SGreg Roach            ->map(static function (ModuleSidebarInterface $sidebar): Collection {
1208eaf8709SGreg Roach                return $sidebar->supportedFacts();
1218eaf8709SGreg Roach            });
1228eaf8709SGreg Roach
1238eaf8709SGreg Roach        $tab_facts = $this->module_service
12487cca37cSGreg Roach            ->findByComponent(ModuleTabInterface::class, $individual->tree(), Auth::user())
1250b5fd0a6SGreg Roach            ->map(static function (ModuleTabInterface $sidebar): Collection {
1268eaf8709SGreg Roach                return $sidebar->supportedFacts();
1278eaf8709SGreg Roach            });
1288eaf8709SGreg Roach
1298eaf8709SGreg Roach        $exclude_facts = $sidebar_facts->merge($tab_facts)->flatten();
1308eaf8709SGreg Roach
1318eaf8709SGreg Roach
1323763c3f2SGreg Roach        // The individual’s own facts
13339ca88baSGreg Roach        $indifacts = $individual->facts()
1340b5fd0a6SGreg Roach            ->filter(static function (Fact $fact) use ($exclude_facts): bool {
13539ca88baSGreg Roach                return !$exclude_facts->contains($fact->getTag());
13639ca88baSGreg Roach            });
1373763c3f2SGreg Roach
1383763c3f2SGreg Roach        // Add spouse-family facts
13939ca88baSGreg Roach        foreach ($individual->spouseFamilies() as $family) {
14030158ae7SGreg Roach            foreach ($family->facts() as $fact) {
1418eaf8709SGreg Roach                if (!$exclude_facts->contains($fact->getTag()) && $fact->getTag() !== 'CHAN') {
14239ca88baSGreg Roach                    $indifacts->push($fact);
1433763c3f2SGreg Roach                }
1443763c3f2SGreg Roach            }
145ee727175SGreg Roach
14639ca88baSGreg Roach            $spouse = $family->spouse($individual);
147ee727175SGreg Roach
148ee727175SGreg Roach            if ($spouse instanceof Individual) {
1498b9cfadbSGreg Roach                $spouse_facts = $this->spouseFacts($individual, $spouse, $min_date, $max_date);
15039ca88baSGreg Roach                $indifacts    = $indifacts->merge($spouse_facts);
1513763c3f2SGreg Roach            }
1523763c3f2SGreg Roach
1538b9cfadbSGreg Roach            $child_facts = $this->childFacts($individual, $family, '_CHIL', '', $min_date, $max_date);
15439ca88baSGreg Roach            $indifacts   = $indifacts->merge($child_facts);
1553763c3f2SGreg Roach        }
156225e381fSGreg Roach
1578b9cfadbSGreg Roach        $parent_facts     = $this->parentFacts($individual, 1, $min_date, $max_date);
1588b9cfadbSGreg Roach        $associate_facts  = $this->associateFacts($individual);
1598b9cfadbSGreg Roach        $historical_facts = $this->historicalFacts($individual);
160225e381fSGreg Roach
16139ca88baSGreg Roach        $indifacts = $indifacts
16239ca88baSGreg Roach            ->merge($parent_facts)
16339ca88baSGreg Roach            ->merge($associate_facts)
16439ca88baSGreg Roach            ->merge($historical_facts);
1653763c3f2SGreg Roach
166580a4d11SGreg Roach        $indifacts = Fact::sortFacts($indifacts);
1673763c3f2SGreg Roach
168a8cd57e1SGreg Roach        return view('modules/personal_facts/tab', [
169225e381fSGreg Roach            'can_edit'             => $individual->canEdit(),
1702adcbd9aSGreg Roach            'clipboard_facts'      => $this->clipboard_service->pastableFacts($individual, $exclude_facts),
171ddeb3354SGreg Roach            'has_historical_facts' => $historical_facts !== [],
172225e381fSGreg Roach            'individual'           => $individual,
173225e381fSGreg Roach            'facts'                => $indifacts,
174225e381fSGreg Roach        ]);
1753763c3f2SGreg Roach    }
1763763c3f2SGreg Roach
177ee727175SGreg Roach    /**
178ee727175SGreg Roach     * Does a relative event occur within a date range (i.e. the individual's lifetime)?
179ee727175SGreg Roach     *
180ee727175SGreg Roach     * @param Fact $fact
181ee727175SGreg Roach     * @param Date $min_date
182ee727175SGreg Roach     * @param Date $max_date
183ee727175SGreg Roach     *
184ee727175SGreg Roach     * @return bool
185ee727175SGreg Roach     */
1868b9cfadbSGreg Roach    private function includeFact(Fact $fact, Date $min_date, Date $max_date): bool
187b3b1d905SGreg Roach    {
1882decada7SGreg Roach        $fact_date = $fact->date();
189ee727175SGreg Roach
190ee727175SGreg Roach        return $fact_date->isOK() && Date::compare($min_date, $fact_date) <= 0 && Date::compare($fact_date, $max_date) <= 0;
191ee727175SGreg Roach    }
192ee727175SGreg Roach
1933caaa4d2SGreg Roach    /**
1943caaa4d2SGreg Roach     * Is this tab empty? If so, we don't always need to display it.
1953caaa4d2SGreg Roach     *
1963caaa4d2SGreg Roach     * @param Individual $individual
1973caaa4d2SGreg Roach     *
1983caaa4d2SGreg Roach     * @return bool
1993caaa4d2SGreg Roach     */
2008f53f488SRico Sonntag    public function hasTabContent(Individual $individual): bool
201c1010edaSGreg Roach    {
2023763c3f2SGreg Roach        return true;
2033763c3f2SGreg Roach    }
2043763c3f2SGreg Roach
2053caaa4d2SGreg Roach    /**
2063caaa4d2SGreg Roach     * Can this tab load asynchronously?
2073caaa4d2SGreg Roach     *
2083caaa4d2SGreg Roach     * @return bool
2093caaa4d2SGreg Roach     */
2108f53f488SRico Sonntag    public function canLoadAjax(): bool
211c1010edaSGreg Roach    {
21215d603e7SGreg Roach        return false;
2133763c3f2SGreg Roach    }
2143763c3f2SGreg Roach
2153763c3f2SGreg Roach    /**
216*7bf6ca81SGreg Roach     * Convert an event into a special "event of a close relative".
217*7bf6ca81SGreg Roach     *
218*7bf6ca81SGreg Roach     * @param Fact $fact
219*7bf6ca81SGreg Roach     * @param      $type
220*7bf6ca81SGreg Roach     *
221*7bf6ca81SGreg Roach     * @return Fact
222*7bf6ca81SGreg Roach     */
223*7bf6ca81SGreg Roach    private function convertEvent(Fact $fact, $type): Fact {
224*7bf6ca81SGreg Roach        $gedcom = $fact->gedcom();
225*7bf6ca81SGreg Roach        $gedcom = preg_replace('/\n2 TYPE .*/', '', $gedcom);
226*7bf6ca81SGreg Roach        $gedcom = preg_replace('/^1 .*/', "1 EVEN CLOSE_RELATIVE\n2 TYPE " . $type, $gedcom);
227*7bf6ca81SGreg Roach
228*7bf6ca81SGreg Roach        return new Fact($gedcom, $fact->record(), $fact->id());
229*7bf6ca81SGreg Roach    }
230*7bf6ca81SGreg Roach
231*7bf6ca81SGreg Roach    /**
2323763c3f2SGreg Roach     * Spouse facts that are shown on an individual’s page.
2333763c3f2SGreg Roach     *
2343763c3f2SGreg Roach     * @param Individual $individual Show events that occured during the lifetime of this individual
2353763c3f2SGreg Roach     * @param Individual $spouse     Show events of this individual
236ee727175SGreg Roach     * @param Date       $min_date
237ee727175SGreg Roach     * @param Date       $max_date
2383763c3f2SGreg Roach     *
2393763c3f2SGreg Roach     * @return Fact[]
2403763c3f2SGreg Roach     */
2418b9cfadbSGreg Roach    private function spouseFacts(Individual $individual, Individual $spouse, Date $min_date, Date $max_date): array
242c1010edaSGreg Roach    {
243f4afa648SGreg Roach        $SHOW_RELATIVES_EVENTS = $individual->tree()->getPreference('SHOW_RELATIVES_EVENTS');
2443763c3f2SGreg Roach
245*7bf6ca81SGreg Roach        $death_of_a_spouse = [
246*7bf6ca81SGreg Roach            'DEAT' => [
247*7bf6ca81SGreg Roach                'M' => I18N::translate('Death of a husband'),
248*7bf6ca81SGreg Roach                'F' => I18N::translate('Death of a wife'),
249*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a spouse'),
250*7bf6ca81SGreg Roach            ],
251*7bf6ca81SGreg Roach            'BURI' => [
252*7bf6ca81SGreg Roach                'M' => I18N::translate('Burial of a husband'),
253*7bf6ca81SGreg Roach                'F' => I18N::translate('Burial of a wife'),
254*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a spouse'),
255*7bf6ca81SGreg Roach            ],
256*7bf6ca81SGreg Roach            'CREM' => [
257*7bf6ca81SGreg Roach                'M' => I18N::translate('Cremation of a husband'),
258*7bf6ca81SGreg Roach                'F' => I18N::translate('Cremation of a wife'),
259*7bf6ca81SGreg Roach                'U' => I18N::translate('Cremation of a spouse'),
260*7bf6ca81SGreg Roach            ],
261*7bf6ca81SGreg Roach        ];
262*7bf6ca81SGreg Roach
26313abd6f3SGreg Roach        $facts = [];
264*7bf6ca81SGreg Roach
265*7bf6ca81SGreg Roach        if (strpos($SHOW_RELATIVES_EVENTS, '_DEAT_SPOU') !== false) {
266*7bf6ca81SGreg Roach            foreach ($spouse->facts(['DEAT', 'BURI', 'CREM']) as $fact) {
2678b9cfadbSGreg Roach                if ($this->includeFact($fact, $min_date, $max_date)) {
268*7bf6ca81SGreg Roach                    $facts[] = $this->convertEvent($fact, $death_of_a_spouse[$fact->getTag()][$fact->record()->sex()]);
2693763c3f2SGreg Roach                }
2703763c3f2SGreg Roach            }
2713763c3f2SGreg Roach        }
2723763c3f2SGreg Roach
2733763c3f2SGreg Roach        return $facts;
2743763c3f2SGreg Roach    }
2753763c3f2SGreg Roach
2763763c3f2SGreg Roach    /**
2773763c3f2SGreg Roach     * Get the events of children and grandchildren.
2783763c3f2SGreg Roach     *
2793763c3f2SGreg Roach     * @param Individual $person
2803763c3f2SGreg Roach     * @param Family     $family
2813763c3f2SGreg Roach     * @param string     $option
2823763c3f2SGreg Roach     * @param string     $relation
283ee727175SGreg Roach     * @param Date       $min_date
284ee727175SGreg Roach     * @param Date       $max_date
2853763c3f2SGreg Roach     *
2863763c3f2SGreg Roach     * @return Fact[]
2873763c3f2SGreg Roach     */
2888b9cfadbSGreg Roach    private function childFacts(Individual $person, Family $family, $option, $relation, Date $min_date, Date $max_date): array
289c1010edaSGreg Roach    {
290f4afa648SGreg Roach        $SHOW_RELATIVES_EVENTS = $person->tree()->getPreference('SHOW_RELATIVES_EVENTS');
2913763c3f2SGreg Roach
292*7bf6ca81SGreg Roach        $birth_of_a_child = [
293*7bf6ca81SGreg Roach            'BIRT' => [
294*7bf6ca81SGreg Roach                'M' => I18N::translate('Birth of a son'),
295*7bf6ca81SGreg Roach                'F' => I18N::translate('Birth of a daughter'),
296*7bf6ca81SGreg Roach                'U' => I18N::translate('Birth of a child'),
297*7bf6ca81SGreg Roach            ],
298*7bf6ca81SGreg Roach            'CHR' => [
299*7bf6ca81SGreg Roach                'M' => I18N::translate('Christening of a son'),
300*7bf6ca81SGreg Roach                'F' => I18N::translate('Christening of a daughter'),
301*7bf6ca81SGreg Roach                'U' => I18N::translate('Christening of a child'),
302*7bf6ca81SGreg Roach            ],
303*7bf6ca81SGreg Roach            'BAPM' => [
304*7bf6ca81SGreg Roach                'M' => I18N::translate('Baptism of a son'),
305*7bf6ca81SGreg Roach                'F' => I18N::translate('Baptism of a daughter'),
306*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a child'),
307*7bf6ca81SGreg Roach            ],
308*7bf6ca81SGreg Roach            'ADOP' => [
309*7bf6ca81SGreg Roach                'M' => I18N::translate('Adoption of a son'),
310*7bf6ca81SGreg Roach                'F' => I18N::translate('Adoption of a daughter'),
311*7bf6ca81SGreg Roach                'U' => I18N::translate('Adoption of a child'),
312*7bf6ca81SGreg Roach            ],
313*7bf6ca81SGreg Roach        ];
314*7bf6ca81SGreg Roach
315*7bf6ca81SGreg Roach        $birth_of_a_sibling = [
316*7bf6ca81SGreg Roach            'BIRT' => [
317*7bf6ca81SGreg Roach                'M' => I18N::translate('Birth of a brother'),
318*7bf6ca81SGreg Roach                'F' => I18N::translate('Birth of a sister'),
319*7bf6ca81SGreg Roach                'U' => I18N::translate('Birth of a sibling'),
320*7bf6ca81SGreg Roach            ],
321*7bf6ca81SGreg Roach            'CHR' => [
322*7bf6ca81SGreg Roach                'M' => I18N::translate('Christening of a brother'),
323*7bf6ca81SGreg Roach                'F' => I18N::translate('Christening of a sister'),
324*7bf6ca81SGreg Roach                'U' => I18N::translate('Christening of a sibling'),
325*7bf6ca81SGreg Roach            ],
326*7bf6ca81SGreg Roach            'BAPM' => [
327*7bf6ca81SGreg Roach                'M' => I18N::translate('Baptism of a brother'),
328*7bf6ca81SGreg Roach                'F' => I18N::translate('Baptism of a sister'),
329*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a sibling'),
330*7bf6ca81SGreg Roach            ],
331*7bf6ca81SGreg Roach            'ADOP' => [
332*7bf6ca81SGreg Roach                'M' => I18N::translate('Adoption of a brother'),
333*7bf6ca81SGreg Roach                'F' => I18N::translate('Adoption of a sister'),
334*7bf6ca81SGreg Roach                'U' => I18N::translate('Adoption of a sibling'),
335*7bf6ca81SGreg Roach            ],
336*7bf6ca81SGreg Roach        ];
337*7bf6ca81SGreg Roach
338*7bf6ca81SGreg Roach        $birth_of_a_half_sibling = [
339*7bf6ca81SGreg Roach            'BIRT' => [
340*7bf6ca81SGreg Roach                'M' => I18N::translate('Birth of a half-brother'),
341*7bf6ca81SGreg Roach                'F' => I18N::translate('Birth of a half-sister'),
342*7bf6ca81SGreg Roach                'U' => I18N::translate('Birth of a half-sibling'),
343*7bf6ca81SGreg Roach            ],
344*7bf6ca81SGreg Roach            'CHR' => [
345*7bf6ca81SGreg Roach                'M' => I18N::translate('Christening of a half-brother'),
346*7bf6ca81SGreg Roach                'F' => I18N::translate('Christening of a half-sister'),
347*7bf6ca81SGreg Roach                'U' => I18N::translate('Christening of a half-sibling'),
348*7bf6ca81SGreg Roach            ],
349*7bf6ca81SGreg Roach            'BAPM' => [
350*7bf6ca81SGreg Roach                'M' => I18N::translate('Baptism of a half-brother'),
351*7bf6ca81SGreg Roach                'F' => I18N::translate('Baptism of a half-sister'),
352*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a half-sibling'),
353*7bf6ca81SGreg Roach            ],
354*7bf6ca81SGreg Roach            'ADOP' => [
355*7bf6ca81SGreg Roach                'M' => I18N::translate('Adoption of a half-brother'),
356*7bf6ca81SGreg Roach                'F' => I18N::translate('Adoption of a half-sister'),
357*7bf6ca81SGreg Roach                'U' => I18N::translate('Adoption of a half-sibling'),
358*7bf6ca81SGreg Roach            ],
359*7bf6ca81SGreg Roach        ];
360*7bf6ca81SGreg Roach
361*7bf6ca81SGreg Roach        $birth_of_a_grandchild = [
362*7bf6ca81SGreg Roach            'BIRT' => [
363*7bf6ca81SGreg Roach                'M' => I18N::translate('Birth of a grandson'),
364*7bf6ca81SGreg Roach                'F' => I18N::translate('Birth of a granddaughter'),
365*7bf6ca81SGreg Roach                'U' => I18N::translate('Birth of a grandchild'),
366*7bf6ca81SGreg Roach            ],
367*7bf6ca81SGreg Roach            'CHR' => [
368*7bf6ca81SGreg Roach                'M' => I18N::translate('Christening of a grandson'),
369*7bf6ca81SGreg Roach                'F' => I18N::translate('Christening of a granddaughter'),
370*7bf6ca81SGreg Roach                'U' => I18N::translate('Christening of a grandchild'),
371*7bf6ca81SGreg Roach            ],
372*7bf6ca81SGreg Roach            'BAPM' => [
373*7bf6ca81SGreg Roach                'M' => I18N::translate('Baptism of a grandson'),
374*7bf6ca81SGreg Roach                'F' => I18N::translate('Baptism of a granddaughter'),
375*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a grandchild'),
376*7bf6ca81SGreg Roach            ],
377*7bf6ca81SGreg Roach            'ADOP' => [
378*7bf6ca81SGreg Roach                'M' => I18N::translate('Adoption of a grandson'),
379*7bf6ca81SGreg Roach                'F' => I18N::translate('Adoption of a granddaughter'),
380*7bf6ca81SGreg Roach                'U' => I18N::translate('Adoption of a grandchild'),
381*7bf6ca81SGreg Roach            ],
382*7bf6ca81SGreg Roach        ];
383*7bf6ca81SGreg Roach
384*7bf6ca81SGreg Roach        $birth_of_a_grandchild1 = [
385*7bf6ca81SGreg Roach            'BIRT' => [
386*7bf6ca81SGreg Roach                'M' => I18N::translateContext('daughter’s son', 'Birth of a grandson'),
387*7bf6ca81SGreg Roach                'F' => I18N::translateContext('daughter’s daughter', 'Birth of a granddaughter'),
388*7bf6ca81SGreg Roach                'U' => I18N::translate('Birth of a grandchild'),
389*7bf6ca81SGreg Roach            ],
390*7bf6ca81SGreg Roach            'CHR' => [
391*7bf6ca81SGreg Roach                'M' => I18N::translateContext('daughter’s son', 'Christening of a grandson'),
392*7bf6ca81SGreg Roach                'F' => I18N::translateContext('daughter’s daughter', 'Christening of a granddaughter'),
393*7bf6ca81SGreg Roach                'U' => I18N::translate('Christening of a grandchild'),
394*7bf6ca81SGreg Roach            ],
395*7bf6ca81SGreg Roach            'BAPM' => [
396*7bf6ca81SGreg Roach                'M' => I18N::translateContext('daughter’s son', 'Baptism of a grandson'),
397*7bf6ca81SGreg Roach                'F' => I18N::translateContext('daughter’s daughter', 'Baptism of a granddaughter'),
398*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a grandchild'),
399*7bf6ca81SGreg Roach            ],
400*7bf6ca81SGreg Roach            'ADOP' => [
401*7bf6ca81SGreg Roach                'M' => I18N::translateContext('daughter’s son', 'Adoption of a grandson'),
402*7bf6ca81SGreg Roach                'F' => I18N::translateContext('daughter’s daughter', 'Adoption of a granddaughter'),
403*7bf6ca81SGreg Roach                'U' => I18N::translate('Adoption of a grandchild'),
404*7bf6ca81SGreg Roach            ],
405*7bf6ca81SGreg Roach        ];
406*7bf6ca81SGreg Roach
407*7bf6ca81SGreg Roach        $birth_of_a_grandchild2 = [
408*7bf6ca81SGreg Roach            'BIRT' => [
409*7bf6ca81SGreg Roach                'M' => I18N::translateContext('son‘s son', 'Birth of a grandson'),
410*7bf6ca81SGreg Roach                'F' => I18N::translateContext('son‘s daughter', 'Birth of a granddaughter'),
411*7bf6ca81SGreg Roach                'U' => I18N::translate('Birth of a grandchild'),
412*7bf6ca81SGreg Roach            ],
413*7bf6ca81SGreg Roach            'CHR' => [
414*7bf6ca81SGreg Roach                'M' => I18N::translateContext('son‘s son', 'Christening of a grandson'),
415*7bf6ca81SGreg Roach                'F' => I18N::translateContext('son‘s daughter', 'Christening of a granddaughter'),
416*7bf6ca81SGreg Roach                'U' => I18N::translate('Christening of a grandchild'),
417*7bf6ca81SGreg Roach            ],
418*7bf6ca81SGreg Roach            'BAPM' => [
419*7bf6ca81SGreg Roach                'M' => I18N::translateContext('son‘s son', 'Baptism of a grandson'),
420*7bf6ca81SGreg Roach                'F' => I18N::translateContext('son‘s daughter', 'Baptism of a granddaughter'),
421*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a grandchild'),
422*7bf6ca81SGreg Roach            ],
423*7bf6ca81SGreg Roach            'ADOP' => [
424*7bf6ca81SGreg Roach                'M' => I18N::translateContext('son‘s son', 'Adoption of a grandson'),
425*7bf6ca81SGreg Roach                'F' => I18N::translateContext('son‘s daughter', 'Adoption of a granddaughter'),
426*7bf6ca81SGreg Roach                'U' => I18N::translate('Adoption of a grandchild'),
427*7bf6ca81SGreg Roach            ],
428*7bf6ca81SGreg Roach        ];
429*7bf6ca81SGreg Roach
430*7bf6ca81SGreg Roach        $death_of_a_child = [
431*7bf6ca81SGreg Roach            'DEAT' => [
432*7bf6ca81SGreg Roach                'M' => I18N::translate('Death of a son'),
433*7bf6ca81SGreg Roach                'F' => I18N::translate('Death of a daughter'),
434*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a child'),
435*7bf6ca81SGreg Roach            ],
436*7bf6ca81SGreg Roach            'BURI' => [
437*7bf6ca81SGreg Roach                'M' => I18N::translate('Burial of a son'),
438*7bf6ca81SGreg Roach                'F' => I18N::translate('Burial of a daughter'),
439*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a child'),
440*7bf6ca81SGreg Roach            ],
441*7bf6ca81SGreg Roach            'CREM' => [
442*7bf6ca81SGreg Roach                'M' => I18N::translate('Cremation of a son'),
443*7bf6ca81SGreg Roach                'F' => I18N::translate('Cremation of a daughter'),
444*7bf6ca81SGreg Roach                'U' => I18N::translate('Cremation of a child'),
445*7bf6ca81SGreg Roach            ],
446*7bf6ca81SGreg Roach        ];
447*7bf6ca81SGreg Roach
448*7bf6ca81SGreg Roach        $death_of_a_sibling = [
449*7bf6ca81SGreg Roach            'DEAT' => [
450*7bf6ca81SGreg Roach                'M' => I18N::translate('Death of a brother'),
451*7bf6ca81SGreg Roach                'F' => I18N::translate('Death of a sister'),
452*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a sibling'),
453*7bf6ca81SGreg Roach            ],
454*7bf6ca81SGreg Roach            'BURI' => [
455*7bf6ca81SGreg Roach                'M' => I18N::translate('Burial of a brother'),
456*7bf6ca81SGreg Roach                'F' => I18N::translate('Burial of a sister'),
457*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a sibling'),
458*7bf6ca81SGreg Roach            ],
459*7bf6ca81SGreg Roach            'CREM' => [
460*7bf6ca81SGreg Roach                'M' => I18N::translate('Cremation of a brother'),
461*7bf6ca81SGreg Roach                'F' => I18N::translate('Cremation of a sister'),
462*7bf6ca81SGreg Roach                'U' => I18N::translate('Cremation of a sibling'),
463*7bf6ca81SGreg Roach            ],
464*7bf6ca81SGreg Roach        ];
465*7bf6ca81SGreg Roach
466*7bf6ca81SGreg Roach        $death_of_a_half_sibling = [
467*7bf6ca81SGreg Roach            'DEAT' => [
468*7bf6ca81SGreg Roach                'M' => I18N::translate('Death of a half-brother'),
469*7bf6ca81SGreg Roach                'F' => I18N::translate('Death of a half-sister'),
470*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a half-sibling'),
471*7bf6ca81SGreg Roach            ],
472*7bf6ca81SGreg Roach            'BURI' => [
473*7bf6ca81SGreg Roach                'M' => I18N::translate('Burial of a half-brother'),
474*7bf6ca81SGreg Roach                'F' => I18N::translate('Burial of a half-sister'),
475*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a half-sibling'),
476*7bf6ca81SGreg Roach            ],
477*7bf6ca81SGreg Roach            'CREM' => [
478*7bf6ca81SGreg Roach                'M' => I18N::translate('Cremation of a half-brother'),
479*7bf6ca81SGreg Roach                'F' => I18N::translate('Cremation of a half-sister'),
480*7bf6ca81SGreg Roach                'U' => I18N::translate('Cremation of a half-sibling'),
481*7bf6ca81SGreg Roach            ],
482*7bf6ca81SGreg Roach        ];
483*7bf6ca81SGreg Roach
484*7bf6ca81SGreg Roach        $death_of_a_grandchild = [
485*7bf6ca81SGreg Roach            'DEAT' => [
486*7bf6ca81SGreg Roach                'M' => I18N::translate('Death of a grandson'),
487*7bf6ca81SGreg Roach                'F' => I18N::translate('Death of a granddaughter'),
488*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a grandchild'),
489*7bf6ca81SGreg Roach            ],
490*7bf6ca81SGreg Roach            'BURI' => [
491*7bf6ca81SGreg Roach                'M' => I18N::translate('Burial of a grandson'),
492*7bf6ca81SGreg Roach                'F' => I18N::translate('Burial of a granddaughter'),
493*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a grandchild'),
494*7bf6ca81SGreg Roach            ],
495*7bf6ca81SGreg Roach            'CREM' => [
496*7bf6ca81SGreg Roach                'M' => I18N::translate('Cremation of a grandson'),
497*7bf6ca81SGreg Roach                'F' => I18N::translate('Cremation of a granddaughter'),
498*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a grandchild'),
499*7bf6ca81SGreg Roach            ],
500*7bf6ca81SGreg Roach        ];
501*7bf6ca81SGreg Roach
502*7bf6ca81SGreg Roach        $death_of_a_grandchild1 = [
503*7bf6ca81SGreg Roach            'DEAT' => [
504*7bf6ca81SGreg Roach                'M' => I18N::translateContext('daughter’s son', 'Death of a grandson'),
505*7bf6ca81SGreg Roach                'F' => I18N::translateContext('daughter’s daughter', 'Death of a granddaughter'),
506*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a grandchild'),
507*7bf6ca81SGreg Roach            ],
508*7bf6ca81SGreg Roach            'BURI' => [
509*7bf6ca81SGreg Roach                'M' => I18N::translateContext('daughter’s son', 'Burial of a grandson'),
510*7bf6ca81SGreg Roach                'F' => I18N::translateContext('daughter’s daughter', 'Burial of a granddaughter'),
511*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a grandchild'),
512*7bf6ca81SGreg Roach            ],
513*7bf6ca81SGreg Roach            'CREM' => [
514*7bf6ca81SGreg Roach                'M' => I18N::translateContext('daughter’s son', 'Cremation of a grandson'),
515*7bf6ca81SGreg Roach                'F' => I18N::translateContext('daughter’s daughter', 'Cremation of a granddaughter'),
516*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a grandchild'),
517*7bf6ca81SGreg Roach            ],
518*7bf6ca81SGreg Roach        ];
519*7bf6ca81SGreg Roach
520*7bf6ca81SGreg Roach        $death_of_a_grandchild2 = [
521*7bf6ca81SGreg Roach            'DEAT' => [
522*7bf6ca81SGreg Roach                'M' => I18N::translateContext('son‘s son', 'Death of a grandson'),
523*7bf6ca81SGreg Roach                'F' => I18N::translateContext('son‘s daughter', 'Death of a granddaughter'),
524*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a grandchild'),
525*7bf6ca81SGreg Roach            ],
526*7bf6ca81SGreg Roach            'BURI' => [
527*7bf6ca81SGreg Roach                'M' => I18N::translateContext('son‘s son', 'Burial of a grandson'),
528*7bf6ca81SGreg Roach                'F' => I18N::translateContext('son‘s daughter', 'Burial of a granddaughter'),
529*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a grandchild'),
530*7bf6ca81SGreg Roach            ],
531*7bf6ca81SGreg Roach            'CREM' => [
532*7bf6ca81SGreg Roach                'M' => I18N::translateContext('son‘s son', 'Cremation of a grandson'),
533*7bf6ca81SGreg Roach                'F' => I18N::translateContext('son‘s daughter', 'Cremation of a granddaughter'),
534*7bf6ca81SGreg Roach                'U' => I18N::translate('Cremation of a grandchild'),
535*7bf6ca81SGreg Roach            ],
536*7bf6ca81SGreg Roach        ];
537*7bf6ca81SGreg Roach
538*7bf6ca81SGreg Roach        $marriage_of_a_child = [
539*7bf6ca81SGreg Roach            'M' => I18N::translate('Marriage of a son'),
540*7bf6ca81SGreg Roach            'F' => I18N::translate('Marriage of a daughter'),
541*7bf6ca81SGreg Roach            'U' => I18N::translate('Marriage of a child'),
542*7bf6ca81SGreg Roach        ];
543*7bf6ca81SGreg Roach
544*7bf6ca81SGreg Roach        $marriage_of_a_grandchild = [
545*7bf6ca81SGreg Roach            'M' => I18N::translate('Marriage of a grandson'),
546*7bf6ca81SGreg Roach            'F' => I18N::translate('Marriage of a granddaughter'),
547*7bf6ca81SGreg Roach            'U' => I18N::translate('Marriage of a grandchild'),
548*7bf6ca81SGreg Roach        ];
549*7bf6ca81SGreg Roach
550*7bf6ca81SGreg Roach        $marriage_of_a_grandchild1 = [
551*7bf6ca81SGreg Roach            'M' => I18N::translateContext('daughter’s son', 'Marriage of a grandson'),
552*7bf6ca81SGreg Roach            'F' => I18N::translateContext('daughter’s daughter', 'Marriage of a granddaughter'),
553*7bf6ca81SGreg Roach            'U' => I18N::translate('Marriage of a grandchild'),
554*7bf6ca81SGreg Roach        ];
555*7bf6ca81SGreg Roach
556*7bf6ca81SGreg Roach        $marriage_of_a_grandchild2 = [
557*7bf6ca81SGreg Roach            'M' => I18N::translateContext('son‘s son', 'Marriage of a grandson'),
558*7bf6ca81SGreg Roach            'F' => I18N::translateContext('son‘s daughter', 'Marriage of a granddaughter'),
559*7bf6ca81SGreg Roach            'U' => I18N::translate('Marriage of a grandchild'),
560*7bf6ca81SGreg Roach        ];
561*7bf6ca81SGreg Roach
562*7bf6ca81SGreg Roach        $marriage_of_a_sibling = [
563*7bf6ca81SGreg Roach            'M' => I18N::translate('Marriage of a brother'),
564*7bf6ca81SGreg Roach            'F' => I18N::translate('Marriage of a sister'),
565*7bf6ca81SGreg Roach            'U' => I18N::translate('Marriage of a sibling'),
566*7bf6ca81SGreg Roach        ];
567*7bf6ca81SGreg Roach
568*7bf6ca81SGreg Roach        $marriage_of_a_half_sibling = [
569*7bf6ca81SGreg Roach            'M' => I18N::translate('Marriage of a half-brother'),
570*7bf6ca81SGreg Roach            'F' => I18N::translate('Marriage of a half-sister'),
571*7bf6ca81SGreg Roach            'U' => I18N::translate('Marriage of a half-sibling'),
572*7bf6ca81SGreg Roach        ];
573*7bf6ca81SGreg Roach
57413abd6f3SGreg Roach        $facts = [];
5753763c3f2SGreg Roach
5763763c3f2SGreg Roach        // Deal with recursion.
5773763c3f2SGreg Roach        switch ($option) {
5783763c3f2SGreg Roach            case '_CHIL':
5793763c3f2SGreg Roach                // Add grandchildren
58039ca88baSGreg Roach                foreach ($family->children() as $child) {
58139ca88baSGreg Roach                    foreach ($child->spouseFamilies() as $cfamily) {
58239ca88baSGreg Roach                        switch ($child->sex()) {
5833763c3f2SGreg Roach                            case 'M':
5848b9cfadbSGreg Roach                                foreach ($this->childFacts($person, $cfamily, '_GCHI', 'son', $min_date, $max_date) as $fact) {
5853763c3f2SGreg Roach                                    $facts[] = $fact;
5863763c3f2SGreg Roach                                }
5873763c3f2SGreg Roach                                break;
5883763c3f2SGreg Roach                            case 'F':
5898b9cfadbSGreg Roach                                foreach ($this->childFacts($person, $cfamily, '_GCHI', 'dau', $min_date, $max_date) as $fact) {
5903763c3f2SGreg Roach                                    $facts[] = $fact;
5913763c3f2SGreg Roach                                }
5923763c3f2SGreg Roach                                break;
5933763c3f2SGreg Roach                            default:
5948b9cfadbSGreg Roach                                foreach ($this->childFacts($person, $cfamily, '_GCHI', 'chi', $min_date, $max_date) as $fact) {
5953763c3f2SGreg Roach                                    $facts[] = $fact;
5963763c3f2SGreg Roach                                }
5973763c3f2SGreg Roach                                break;
5983763c3f2SGreg Roach                        }
5993763c3f2SGreg Roach                    }
6003763c3f2SGreg Roach                }
6013763c3f2SGreg Roach                break;
6023763c3f2SGreg Roach        }
6033763c3f2SGreg Roach
6043763c3f2SGreg Roach        // For each child in the family
60539ca88baSGreg Roach        foreach ($family->children() as $child) {
60622d65e5aSGreg Roach            if ($child->xref() === $person->xref()) {
6073763c3f2SGreg Roach                // We are not our own sibling!
6083763c3f2SGreg Roach                continue;
6093763c3f2SGreg Roach            }
6103763c3f2SGreg Roach            // add child’s birth
6113763c3f2SGreg Roach            if (strpos($SHOW_RELATIVES_EVENTS, '_BIRT' . str_replace('_HSIB', '_SIBL', $option)) !== false) {
612*7bf6ca81SGreg Roach                foreach ($child->facts(['BIRT', 'CHR', 'BAPM', 'ADOP']) as $fact) {
6133763c3f2SGreg Roach                    // Always show _BIRT_CHIL, even if the dates are not known
61422d65e5aSGreg Roach                    if ($option === '_CHIL' || $this->includeFact($fact, $min_date, $max_date)) {
615*7bf6ca81SGreg Roach                        switch ($option) {
616*7bf6ca81SGreg Roach                            case '_GCHI':
617*7bf6ca81SGreg Roach                                switch ($relation) {
618*7bf6ca81SGreg Roach                                    case 'dau':
619*7bf6ca81SGreg Roach                                        $facts[] = $this->convertEvent($fact, $birth_of_a_grandchild1[$fact->getTag()][$fact->record()->sex()]);
620*7bf6ca81SGreg Roach                                        break;
621*7bf6ca81SGreg Roach                                    case 'son':
622*7bf6ca81SGreg Roach                                        $facts[] = $this->convertEvent($fact, $birth_of_a_grandchild2[$fact->getTag()][$fact->record()->sex()]);
623*7bf6ca81SGreg Roach                                        break;
624*7bf6ca81SGreg Roach                                    case 'chil':
625*7bf6ca81SGreg Roach                                        $facts[] = $this->convertEvent($fact, $birth_of_a_grandchild[$fact->getTag()][$fact->record()->sex()]);
626*7bf6ca81SGreg Roach                                        break;
627*7bf6ca81SGreg Roach                                }
628*7bf6ca81SGreg Roach                                break;
629*7bf6ca81SGreg Roach                            case '_SIBL':
630*7bf6ca81SGreg Roach                                $facts[] = $this->convertEvent($fact, $birth_of_a_sibling[$fact->getTag()][$fact->record()->sex()]);
631*7bf6ca81SGreg Roach                                break;
632*7bf6ca81SGreg Roach                            case '_HSIB':
633*7bf6ca81SGreg Roach                                $facts[] = $this->convertEvent($fact, $birth_of_a_half_sibling[$fact->getTag()][$fact->record()->sex()]);
634*7bf6ca81SGreg Roach                                break;
635*7bf6ca81SGreg Roach                            case '_CHIL':
636*7bf6ca81SGreg Roach                                $facts[] = $this->convertEvent($fact, $birth_of_a_child[$fact->getTag()][$fact->record()->sex()]);
637*7bf6ca81SGreg Roach                                break;
6383763c3f2SGreg Roach                        }
6393763c3f2SGreg Roach                    }
6403763c3f2SGreg Roach                }
6413763c3f2SGreg Roach            }
6423763c3f2SGreg Roach            // add child’s death
6433763c3f2SGreg Roach            if (strpos($SHOW_RELATIVES_EVENTS, '_DEAT' . str_replace('_HSIB', '_SIBL', $option)) !== false) {
644*7bf6ca81SGreg Roach                foreach ($child->facts(['DEAT', 'BURI', 'CREM']) as $fact) {
6458b9cfadbSGreg Roach                    if ($this->includeFact($fact, $min_date, $max_date)) {
646*7bf6ca81SGreg Roach                        switch ($option) {
647*7bf6ca81SGreg Roach                            case '_GCHI':
648*7bf6ca81SGreg Roach                                switch ($relation) {
649*7bf6ca81SGreg Roach                                    case 'dau':
650*7bf6ca81SGreg Roach                                        $facts[] = $this->convertEvent($fact, $death_of_a_grandchild1[$fact->getTag()][$fact->record()->sex()]);
651*7bf6ca81SGreg Roach                                        break;
652*7bf6ca81SGreg Roach                                    case 'son':
653*7bf6ca81SGreg Roach                                        $facts[] = $this->convertEvent($fact, $death_of_a_grandchild2[$fact->getTag()][$fact->record()->sex()]);
654*7bf6ca81SGreg Roach                                        break;
655*7bf6ca81SGreg Roach                                    case 'chi':
656*7bf6ca81SGreg Roach                                        $facts[] = $this->convertEvent($fact, $death_of_a_grandchild[$fact->getTag()][$fact->record()->sex()]);
657*7bf6ca81SGreg Roach                                        break;
658*7bf6ca81SGreg Roach                                }
659*7bf6ca81SGreg Roach                                break;
660*7bf6ca81SGreg Roach                            case '_SIBL':
661*7bf6ca81SGreg Roach                                $facts[] = $this->convertEvent($fact, $death_of_a_sibling[$fact->getTag()][$fact->record()->sex()]);
662*7bf6ca81SGreg Roach                                break;
663*7bf6ca81SGreg Roach                            case '_HSIB':
664*7bf6ca81SGreg Roach                                $facts[] = $this->convertEvent($fact, $death_of_a_half_sibling[$fact->getTag()][$fact->record()->sex()]);
665*7bf6ca81SGreg Roach                                break;
666*7bf6ca81SGreg Roach                            case 'CHIL':
667*7bf6ca81SGreg Roach                                $facts[] = $this->convertEvent($fact, $death_of_a_child[$fact->getTag()][$fact->record()->sex()]);
668*7bf6ca81SGreg Roach                                break;
6693763c3f2SGreg Roach                        }
6703763c3f2SGreg Roach                    }
6713763c3f2SGreg Roach                }
6723763c3f2SGreg Roach            }
673*7bf6ca81SGreg Roach
6743763c3f2SGreg Roach            // add child’s marriage
675*7bf6ca81SGreg Roach            if (strpos($SHOW_RELATIVES_EVENTS, '_MARR' . str_replace('_HSIB', '_SIBL', $option)) !== false) {
67639ca88baSGreg Roach                foreach ($child->spouseFamilies() as $sfamily) {
6778d0ebef0SGreg Roach                    foreach ($sfamily->facts(['MARR']) as $fact) {
6788b9cfadbSGreg Roach                        if ($this->includeFact($fact, $min_date, $max_date)) {
679*7bf6ca81SGreg Roach                            switch ($option) {
680*7bf6ca81SGreg Roach                                case '_GCHI':
681*7bf6ca81SGreg Roach                                    switch ($relation) {
682*7bf6ca81SGreg Roach                                        case 'dau':
683*7bf6ca81SGreg Roach                                            $facts[] = $this->convertEvent($fact, $marriage_of_a_grandchild1['F']);
684*7bf6ca81SGreg Roach                                            break;
685*7bf6ca81SGreg Roach                                        case 'son':
686*7bf6ca81SGreg Roach                                            $facts[] = $this->convertEvent($fact, $marriage_of_a_grandchild2['M']);
687*7bf6ca81SGreg Roach                                            break;
688*7bf6ca81SGreg Roach                                        case 'chi':
689*7bf6ca81SGreg Roach                                            $facts[] = $this->convertEvent($fact, $marriage_of_a_grandchild['U']);
690*7bf6ca81SGreg Roach                                            break;
691*7bf6ca81SGreg Roach                                    }
692*7bf6ca81SGreg Roach                                    break;
693*7bf6ca81SGreg Roach                                case '_SIBL':
694*7bf6ca81SGreg Roach                                    $facts[] = $this->convertEvent($fact, $marriage_of_a_sibling['U']);
695*7bf6ca81SGreg Roach                                    break;
696*7bf6ca81SGreg Roach                                case '_HSIB':
697*7bf6ca81SGreg Roach                                    $facts[] = $this->convertEvent($fact, $marriage_of_a_half_sibling['U']);
698*7bf6ca81SGreg Roach                                    break;
699*7bf6ca81SGreg Roach                                case '_CHIL':
700*7bf6ca81SGreg Roach                                    $facts[] = $this->convertEvent($fact, $marriage_of_a_child['U']);
701*7bf6ca81SGreg Roach                                    break;
7023763c3f2SGreg Roach                            }
7033763c3f2SGreg Roach                        }
7043763c3f2SGreg Roach                    }
7053763c3f2SGreg Roach                }
7063763c3f2SGreg Roach            }
7073763c3f2SGreg Roach        }
7083763c3f2SGreg Roach
7093763c3f2SGreg Roach        return $facts;
7103763c3f2SGreg Roach    }
7113763c3f2SGreg Roach
7123763c3f2SGreg Roach    /**
7133763c3f2SGreg Roach     * Get the events of parents and grandparents.
7143763c3f2SGreg Roach     *
7153763c3f2SGreg Roach     * @param Individual $person
716cbc1590aSGreg Roach     * @param int        $sosa
717ee727175SGreg Roach     * @param Date       $min_date
718ee727175SGreg Roach     * @param Date       $max_date
7193763c3f2SGreg Roach     *
7203763c3f2SGreg Roach     * @return Fact[]
7213763c3f2SGreg Roach     */
7228b9cfadbSGreg Roach    private function parentFacts(Individual $person, $sosa, Date $min_date, Date $max_date): array
723c1010edaSGreg Roach    {
724f4afa648SGreg Roach        $SHOW_RELATIVES_EVENTS = $person->tree()->getPreference('SHOW_RELATIVES_EVENTS');
7253763c3f2SGreg Roach
726*7bf6ca81SGreg Roach        $death_of_a_parent = [
727*7bf6ca81SGreg Roach            'DEAT' => [
728*7bf6ca81SGreg Roach                'M' => I18N::translate('Death of a father'),
729*7bf6ca81SGreg Roach                'F' => I18N::translate('Death of a mother'),
730*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a parent'),
731*7bf6ca81SGreg Roach            ],
732*7bf6ca81SGreg Roach            'BURI' => [
733*7bf6ca81SGreg Roach                'M' => I18N::translate('Burial of a father'),
734*7bf6ca81SGreg Roach                'F' => I18N::translate('Burial of a mother'),
735*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a parent'),
736*7bf6ca81SGreg Roach            ],
737*7bf6ca81SGreg Roach            'CREM' => [
738*7bf6ca81SGreg Roach                'M' => I18N::translate('Cremation of a father'),
739*7bf6ca81SGreg Roach                'F' => I18N::translate('Cremation of a mother'),
740*7bf6ca81SGreg Roach                'U' => I18N::translate('Cremation of a parent'),
741*7bf6ca81SGreg Roach            ],
742*7bf6ca81SGreg Roach        ];
743*7bf6ca81SGreg Roach
744*7bf6ca81SGreg Roach        $death_of_a_grandparent = [
745*7bf6ca81SGreg Roach            'DEAT' => [
746*7bf6ca81SGreg Roach                'M' => I18N::translate('Death of a grandfather'),
747*7bf6ca81SGreg Roach                'F' => I18N::translate('Death of a grandmother'),
748*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a grandparent'),
749*7bf6ca81SGreg Roach            ],
750*7bf6ca81SGreg Roach            'BURI' => [
751*7bf6ca81SGreg Roach                'M' => I18N::translate('Burial of a grandfather'),
752*7bf6ca81SGreg Roach                'F' => I18N::translate('Burial of a grandmother'),
753*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a grandparent'),
754*7bf6ca81SGreg Roach            ],
755*7bf6ca81SGreg Roach            'CREM' => [
756*7bf6ca81SGreg Roach                'M' => I18N::translate('Cremation of a grandfather'),
757*7bf6ca81SGreg Roach                'F' => I18N::translate('Cremation of a grandmother'),
758*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a grandparent'),
759*7bf6ca81SGreg Roach            ],
760*7bf6ca81SGreg Roach        ];
761*7bf6ca81SGreg Roach
762*7bf6ca81SGreg Roach        $death_of_a_maternal_grandparent = [
763*7bf6ca81SGreg Roach            'DEAT' => [
764*7bf6ca81SGreg Roach                'M' => I18N::translateContext('mother’s father', 'Death of a grandfather'),
765*7bf6ca81SGreg Roach                'F' => I18N::translateContext('mother’s mother', 'Death of a grandmother'),
766*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a grandparent'),
767*7bf6ca81SGreg Roach            ],
768*7bf6ca81SGreg Roach            'BURI' => [
769*7bf6ca81SGreg Roach                'M' => I18N::translateContext('mother’s father', 'Burial of a grandfather'),
770*7bf6ca81SGreg Roach                'F' => I18N::translateContext('mother’s mother', 'Burial of a grandmother'),
771*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a grandparent'),
772*7bf6ca81SGreg Roach            ],
773*7bf6ca81SGreg Roach            'CREM' => [
774*7bf6ca81SGreg Roach                'M' => I18N::translateContext('mother’s father', 'Cremation of a grandfather'),
775*7bf6ca81SGreg Roach                'F' => I18N::translateContext('mother’s mother', 'Cremation of a grandmother'),
776*7bf6ca81SGreg Roach                'U' => I18N::translate('Baptism of a grandparent'),
777*7bf6ca81SGreg Roach            ],
778*7bf6ca81SGreg Roach        ];
779*7bf6ca81SGreg Roach
780*7bf6ca81SGreg Roach        $death_of_a_paternal_grandparent = [
781*7bf6ca81SGreg Roach            'DEAT' => [
782*7bf6ca81SGreg Roach                'M' => I18N::translateContext('father‘s father', 'Death of a grandfather'),
783*7bf6ca81SGreg Roach                'F' => I18N::translateContext('father‘s mother', 'Death of a grandmother'),
784*7bf6ca81SGreg Roach                'U' => I18N::translate('Death of a grandparent'),
785*7bf6ca81SGreg Roach            ],
786*7bf6ca81SGreg Roach            'BURI' => [
787*7bf6ca81SGreg Roach                'M' => I18N::translateContext('father‘s father', 'Burial of a grandfather'),
788*7bf6ca81SGreg Roach                'F' => I18N::translateContext('father‘s mother', 'Burial of a grandmother'),
789*7bf6ca81SGreg Roach                'U' => I18N::translate('Burial of a grandparent'),
790*7bf6ca81SGreg Roach            ],
791*7bf6ca81SGreg Roach            'CREM' => [
792*7bf6ca81SGreg Roach                'M' => I18N::translateContext('father‘s father', 'Cremation of a grandfather'),
793*7bf6ca81SGreg Roach                'F' => I18N::translateContext('father‘s mother', 'Cremation of a grandmother'),
794*7bf6ca81SGreg Roach                'U' => I18N::translate('Cremation of a grandparent'),
795*7bf6ca81SGreg Roach            ],
796*7bf6ca81SGreg Roach        ];
797*7bf6ca81SGreg Roach
798*7bf6ca81SGreg Roach        $marriage_of_a_parent = [
799*7bf6ca81SGreg Roach            'M' => I18N::translate('Marriage of a father'),
800*7bf6ca81SGreg Roach            'F' => I18N::translate('Marriage of a mother'),
801*7bf6ca81SGreg Roach            'U' => I18N::translate('Marriage of a parent'),
802*7bf6ca81SGreg Roach        ];
803*7bf6ca81SGreg Roach
80413abd6f3SGreg Roach        $facts = [];
8053763c3f2SGreg Roach
8063763c3f2SGreg Roach        if ($sosa == 1) {
80739ca88baSGreg Roach            foreach ($person->childFamilies() as $family) {
8083763c3f2SGreg Roach                // Add siblings
8098b9cfadbSGreg Roach                foreach ($this->childFacts($person, $family, '_SIBL', '', $min_date, $max_date) as $fact) {
8103763c3f2SGreg Roach                    $facts[] = $fact;
8113763c3f2SGreg Roach                }
81239ca88baSGreg Roach                foreach ($family->spouses() as $spouse) {
81339ca88baSGreg Roach                    foreach ($spouse->spouseFamilies() as $sfamily) {
8143763c3f2SGreg Roach                        if ($family !== $sfamily) {
8153763c3f2SGreg Roach                            // Add half-siblings
8168b9cfadbSGreg Roach                            foreach ($this->childFacts($person, $sfamily, '_HSIB', '', $min_date, $max_date) as $fact) {
8173763c3f2SGreg Roach                                $facts[] = $fact;
8183763c3f2SGreg Roach                            }
8193763c3f2SGreg Roach                        }
8203763c3f2SGreg Roach                    }
8213763c3f2SGreg Roach                    // Add grandparents
82222d65e5aSGreg Roach                    foreach ($this->parentFacts($spouse, $spouse->sex() === 'F' ? 3 : 2, $min_date, $max_date) as $fact) {
8233763c3f2SGreg Roach                        $facts[] = $fact;
8243763c3f2SGreg Roach                    }
8253763c3f2SGreg Roach                }
8263763c3f2SGreg Roach            }
8273763c3f2SGreg Roach
828*7bf6ca81SGreg Roach            if (strpos($SHOW_RELATIVES_EVENTS, '_MARR_PARE') !== false) {
8293763c3f2SGreg Roach                // add father/mother marriages
83039ca88baSGreg Roach                foreach ($person->childFamilies() as $sfamily) {
8318d0ebef0SGreg Roach                    foreach ($sfamily->facts(['MARR']) as $fact) {
8328b9cfadbSGreg Roach                        if ($this->includeFact($fact, $min_date, $max_date)) {
8333763c3f2SGreg Roach                            // marriage of parents (to each other)
834*7bf6ca81SGreg Roach                            $facts[] = $this->convertEvent($fact, I18N::translate('Marriage of parents'));
8353763c3f2SGreg Roach                        }
8363763c3f2SGreg Roach                    }
8373763c3f2SGreg Roach                }
83839ca88baSGreg Roach                foreach ($person->childStepFamilies() as $sfamily) {
8398d0ebef0SGreg Roach                    foreach ($sfamily->facts(['MARR']) as $fact) {
8408b9cfadbSGreg Roach                        if ($this->includeFact($fact, $min_date, $max_date)) {
8413763c3f2SGreg Roach                            // marriage of a parent (to another spouse)
842*7bf6ca81SGreg Roach                            $facts[] = $this->convertEvent($fact, $marriage_of_a_parent['U']);
8433763c3f2SGreg Roach                        }
8443763c3f2SGreg Roach                    }
8453763c3f2SGreg Roach                }
8463763c3f2SGreg Roach            }
8473763c3f2SGreg Roach        }
8483763c3f2SGreg Roach
84939ca88baSGreg Roach        foreach ($person->childFamilies() as $family) {
85039ca88baSGreg Roach            foreach ($family->spouses() as $parent) {
851*7bf6ca81SGreg Roach                if (strpos($SHOW_RELATIVES_EVENTS, '_DEAT' . ($sosa === 1 ? '_PARE' : '_GPAR')) !== false) {
852*7bf6ca81SGreg Roach                    foreach ($parent->facts(['DEAT', 'BURI', 'CREM']) as $fact) {
8538b9cfadbSGreg Roach                        if ($this->includeFact($fact, $min_date, $max_date)) {
8543763c3f2SGreg Roach                            switch ($sosa) {
8553763c3f2SGreg Roach                                case 1:
856*7bf6ca81SGreg Roach                                    $facts[] = $this->convertEvent($fact, $death_of_a_parent[$fact->getTag()][$fact->record()->sex()]);
8573763c3f2SGreg Roach                                    break;
8583763c3f2SGreg Roach                                case 2:
8593763c3f2SGreg Roach                                case 3:
860*7bf6ca81SGreg Roach                                    switch ($parent->sex()) {
861*7bf6ca81SGreg Roach                                        case 'M':
862*7bf6ca81SGreg Roach                                            $facts[] = $this->convertEvent($fact, $death_of_a_paternal_grandparent[$fact->getTag()][$fact->record()->sex()]);
8633763c3f2SGreg Roach                                            break;
864*7bf6ca81SGreg Roach                                        case 'F':
865*7bf6ca81SGreg Roach                                            $facts[] = $this->convertEvent($fact, $death_of_a_maternal_grandparent[$fact->getTag()][$fact->record()->sex()]);
866*7bf6ca81SGreg Roach                                            break;
867*7bf6ca81SGreg Roach                                        default:
868*7bf6ca81SGreg Roach                                            $facts[] = $this->convertEvent($fact, $death_of_a_grandparent[$fact->getTag()][$fact->record()->sex()]);
869*7bf6ca81SGreg Roach                                            break;
870*7bf6ca81SGreg Roach                                    }
8713763c3f2SGreg Roach                            }
8723763c3f2SGreg Roach                        }
8733763c3f2SGreg Roach                    }
8743763c3f2SGreg Roach                }
8753763c3f2SGreg Roach            }
8763763c3f2SGreg Roach        }
8773763c3f2SGreg Roach
8783763c3f2SGreg Roach        return $facts;
8793763c3f2SGreg Roach    }
8803763c3f2SGreg Roach
8813763c3f2SGreg Roach    /**
8823763c3f2SGreg Roach     * Get any historical events.
8833763c3f2SGreg Roach     *
88417c50b57SGreg Roach     * @param Individual $individual
8853763c3f2SGreg Roach     *
8863763c3f2SGreg Roach     * @return Fact[]
8873763c3f2SGreg Roach     */
8884ca7e03cSGreg Roach    private function historicalFacts(Individual $individual): array
889c1010edaSGreg Roach    {
8904ca7e03cSGreg Roach        return $this->module_service->findByInterface(ModuleHistoricEventsInterface::class)
8910b5fd0a6SGreg Roach            ->map(static function (ModuleHistoricEventsInterface $module) use ($individual): Collection {
89217c50b57SGreg Roach                return $module->historicEventsForIndividual($individual);
89317c50b57SGreg Roach            })
89417c50b57SGreg Roach            ->flatten()
89517c50b57SGreg Roach            ->all();
8963763c3f2SGreg Roach    }
8973763c3f2SGreg Roach
8983763c3f2SGreg Roach    /**
8993763c3f2SGreg Roach     * Get the events of associates.
9003763c3f2SGreg Roach     *
9013763c3f2SGreg Roach     * @param Individual $person
9023763c3f2SGreg Roach     *
9033763c3f2SGreg Roach     * @return Fact[]
9043763c3f2SGreg Roach     */
9058b9cfadbSGreg Roach    private function associateFacts(Individual $person): array
906c1010edaSGreg Roach    {
90713abd6f3SGreg Roach        $facts = [];
9083763c3f2SGreg Roach
909ee727175SGreg Roach        /** @var Individual[] $associates */
910907c1109SGreg Roach        $asso1 = $person->linkedIndividuals('ASSO');
911907c1109SGreg Roach        $asso2 = $person->linkedIndividuals('_ASSO');
912907c1109SGreg Roach        $asso3 = $person->linkedFamilies('ASSO');
913907c1109SGreg Roach        $asso4 = $person->linkedFamilies('_ASSO');
914907c1109SGreg Roach
915907c1109SGreg Roach        $associates = $asso1->merge($asso2)->merge($asso3)->merge($asso4);
916907c1109SGreg Roach
9173763c3f2SGreg Roach        foreach ($associates as $associate) {
91830158ae7SGreg Roach            foreach ($associate->facts() as $fact) {
919907c1109SGreg Roach                if (preg_match('/\n\d _?ASSO @' . $person->xref() . '@/', $fact->gedcom())) {
9203763c3f2SGreg Roach                    // Extract the important details from the fact
9213763c3f2SGreg Roach                    $factrec = '1 ' . $fact->getTag();
922138ca96cSGreg Roach                    if (preg_match('/\n2 DATE .*/', $fact->gedcom(), $match)) {
9233763c3f2SGreg Roach                        $factrec .= $match[0];
9243763c3f2SGreg Roach                    }
925138ca96cSGreg Roach                    if (preg_match('/\n2 PLAC .*/', $fact->gedcom(), $match)) {
9263763c3f2SGreg Roach                        $factrec .= $match[0];
9273763c3f2SGreg Roach                    }
9283763c3f2SGreg Roach                    if ($associate instanceof Family) {
92939ca88baSGreg Roach                        foreach ($associate->spouses() as $spouse) {
930c0935879SGreg Roach                            $factrec .= "\n2 _ASSO @" . $spouse->xref() . '@';
9313763c3f2SGreg Roach                        }
9323763c3f2SGreg Roach                    } else {
933c0935879SGreg Roach                        $factrec .= "\n2 _ASSO @" . $associate->xref() . '@';
9343763c3f2SGreg Roach                    }
9353763c3f2SGreg Roach                    $facts[] = new Fact($factrec, $associate, 'asso');
9363763c3f2SGreg Roach                }
9373763c3f2SGreg Roach            }
9383763c3f2SGreg Roach        }
9393763c3f2SGreg Roach
9403763c3f2SGreg Roach        return $facts;
9413763c3f2SGreg Roach    }
9428eaf8709SGreg Roach
9438eaf8709SGreg Roach    /**
9448eaf8709SGreg Roach     * This module handles the following facts - so don't show them on the "Facts and events" tab.
9458eaf8709SGreg Roach     *
946b5c8fd7eSGreg Roach     * @return Collection<string>
9478eaf8709SGreg Roach     */
9488eaf8709SGreg Roach    public function supportedFacts(): Collection
9498eaf8709SGreg Roach    {
9508eaf8709SGreg Roach        // We don't actually displaye these facts, but they are displayed
9518eaf8709SGreg Roach        // outside the tabs/sidebar systems. This just forces them to be excluded here.
9528eaf8709SGreg Roach        return new Collection(['NAME', 'SEX']);
9538eaf8709SGreg Roach    }
9543763c3f2SGreg Roach}
955