xref: /webtrees/app/Module/FixPrimaryTag.php (revision 39006dfb4f86f527d62c0ec9782e6b8609d673dd)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2023 webtrees development team
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees\Module;
21
22use Fisharebest\Webtrees\Fact;
23use Fisharebest\Webtrees\GedcomRecord;
24use Fisharebest\Webtrees\I18N;
25use Fisharebest\Webtrees\Individual;
26use Fisharebest\Webtrees\Services\LinkedRecordService;
27use Fisharebest\Webtrees\Tree;
28use Illuminate\Support\Collection;
29
30use function e;
31use function str_contains;
32use function strtoupper;
33
34/**
35 * Class FixPrimaryTag
36 */
37class FixPrimaryTag extends AbstractModule implements ModuleDataFixInterface
38{
39    use ModuleDataFixTrait;
40
41    private LinkedRecordService $linked_record_service;
42
43    /**
44     * @param LinkedRecordService $linked_record_service
45     */
46    public function __construct(LinkedRecordService $linked_record_service)
47    {
48        $this->linked_record_service = $linked_record_service;
49    }
50
51    /**
52     * How should this module be identified in the control panel, etc.?
53     *
54     * @return string
55     */
56    public function title(): string
57    {
58        /* I18N: Name of a module */
59        return I18N::translate('Convert %s tags to GEDCOM 5.5.1', 'OBJE:_PRIM');
60    }
61
62    public function description(): string
63    {
64        /* I18N: Description of a “Data fix” module */
65        return I18N::translate('“Highlighted image” (_PRIM) tags are used by some genealogy applications to indicate the preferred image for an individual. An alternative is to re-order the images so that the preferred one is listed first.');
66    }
67
68    /**
69     * XREFs of media records that might need fixing.
70     *
71     * @param Tree                 $tree
72     * @param array<string,string> $params
73     *
74     * @return Collection<int,string>
75     */
76    public function mediaToFix(Tree $tree, array $params): Collection
77    {
78        return $this->mediaToFixQuery($tree, $params)
79            ->where('m_file', '=', $tree->id())
80            ->where('m_gedcom', 'LIKE', "%\n1 _PRIM %")
81            ->pluck('m_id');
82    }
83
84    /**
85     * Does a record need updating?
86     *
87     * @param GedcomRecord         $record
88     * @param array<string,string> $params
89     *
90     * @return bool
91     */
92    public function doesRecordNeedUpdate(GedcomRecord $record, array $params): bool
93    {
94        return str_contains($record->gedcom(), "\n1 _PRIM ");
95    }
96
97    /**
98     * Show the changes we would make
99     *
100     * @param GedcomRecord         $record
101     * @param array<string,string> $params
102     *
103     * @return string
104     */
105    public function previewUpdate(GedcomRecord $record, array $params): string
106    {
107        $html = '';
108        foreach ($record->facts(['_PRIM']) as $prim) {
109            $html = '<p>' . I18N::translate('Delete') . ' – <code>' . e($prim->gedcom()) . '</code></p>';
110        }
111
112        $html .= '<ul>';
113        foreach ($this->linked_record_service->linkedIndividuals($record) as $individual) {
114            $html .= '<li>' . I18N::translate('Re-order media') . ' – <a href="' . e($individual->url()) . '">' . $individual->fullName() . '</a></li>';
115        }
116        $html .= '</ul>';
117
118        return $html;
119    }
120
121    /**
122     * Fix a record
123     *
124     * @param GedcomRecord         $record
125     * @param array<string,string> $params
126     *
127     * @return void
128     */
129    public function updateRecord(GedcomRecord $record, array $params): void
130    {
131        $facts = $record->facts(['_PRIM'])->filter(static fn (Fact $fact): bool => !$fact->isPendingDeletion());
132
133        foreach ($facts as $fact) {
134            $primary = strtoupper($fact->value()) !== 'N';
135
136            foreach ($this->linked_record_service->linkedIndividuals($record) as $individual) {
137                $this->updateMediaLinks($individual, $record->xref(), $primary);
138            }
139
140            $record->deleteFact($fact->id(), false);
141        }
142    }
143
144    /**
145     * @param Individual $individual
146     * @param string     $xref
147     * @param bool       $primary
148     */
149    private function updateMediaLinks(Individual $individual, string $xref, bool $primary): void
150    {
151        $facts = $individual->facts([], false, null, true);
152
153        $facts1 = new Collection();
154        $facts2 = new Collection();
155        $facts3 = new Collection();
156        $facts4 = new Collection();
157
158        foreach ($facts as $fact) {
159            if ($fact->tag() !== 'INDI:OBJE') {
160                $facts1->push($fact);
161            } elseif ($fact->value() !== '@' . $xref . '@') {
162                $facts3->push($fact);
163            } elseif ($primary) {
164                $facts2->push($fact);
165            } else {
166                $facts4->push($fact);
167            }
168        }
169
170        $sorted_facts = $facts1->concat($facts2)->concat($facts3)->concat($facts4);
171
172        $gedcom = $sorted_facts->map(static fn (Fact $fact): string => "\n" . $fact->gedcom())->implode('');
173
174        $gedcom = '0 @' . $individual->xref() . '@ INDI' . $gedcom;
175
176        $individual->updateRecord($gedcom, false);
177    }
178}
179