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