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\Services; 21 22use Fisharebest\Algorithm\MyersDiff; 23use Fisharebest\Webtrees\Family; 24use Fisharebest\Webtrees\Gedcom; 25use Fisharebest\Webtrees\GedcomRecord; 26use Fisharebest\Webtrees\Individual; 27use Fisharebest\Webtrees\Media; 28use Fisharebest\Webtrees\Note; 29use Fisharebest\Webtrees\Registry; 30use Fisharebest\Webtrees\Repository; 31use Fisharebest\Webtrees\Source; 32use Fisharebest\Webtrees\Submitter; 33use Fisharebest\Webtrees\Tree; 34 35use function e; 36use function explode; 37use function implode; 38use function preg_replace_callback; 39use function strip_tags; 40 41/** 42 * Bulk updates on genealogy data 43 */ 44class DataFixService 45{ 46 /** 47 * Since we know the type, this is quicker than calling Registry::gedcomRecordFactory()->make(). 48 * 49 * @param string $xref 50 * @param Tree $tree 51 * @param string $type 52 * 53 * @return GedcomRecord|null 54 */ 55 public function getRecordByType(string $xref, Tree $tree, string $type): ?GedcomRecord 56 { 57 switch ($type) { 58 case Family::RECORD_TYPE: 59 return Registry::familyFactory()->make($xref, $tree); 60 61 case Individual::RECORD_TYPE: 62 return Registry::individualFactory()->make($xref, $tree); 63 64 case Note::RECORD_TYPE: 65 return Registry::noteFactory()->make($xref, $tree); 66 67 case Media::RECORD_TYPE: 68 return Registry::mediaFactory()->make($xref, $tree); 69 70 case Repository::RECORD_TYPE: 71 return Registry::repositoryFactory()->make($xref, $tree); 72 73 case Source::RECORD_TYPE: 74 return Registry::sourceFactory()->make($xref, $tree); 75 76 case Submitter::RECORD_TYPE: 77 return Registry::submitterFactory()->make($xref, $tree); 78 79 default: 80 return Registry::gedcomRecordFactory()->make($xref, $tree); 81 } 82 } 83 84 /** 85 * Default preview generator. 86 * 87 * @param Tree $tree 88 * @param string $old_gedcom 89 * @param string $new_gedcom 90 * 91 * @return string 92 */ 93 public function gedcomDiff(Tree $tree, string $old_gedcom, string $new_gedcom): string 94 { 95 $old_lines = explode("\n", $old_gedcom); 96 $new_lines = explode("\n", $new_gedcom); 97 $algorithm = new MyersDiff(); 98 $differences = $algorithm->calculate($old_lines, $new_lines); 99 $diff_lines = []; 100 101 foreach ($differences as $difference) { 102 switch ($difference[1]) { 103 case MyersDiff::DELETE: 104 $diff_lines[] = '<del>' . e($difference[0]) . '</del><br>'; 105 break; 106 case MyersDiff::INSERT: 107 $diff_lines[] = '<ins>' . e($difference[0]) . '</ins><br>'; 108 break; 109 case MyersDiff::KEEP: 110 $diff_lines[] = e($difference[0]) . '<br>'; 111 break; 112 } 113 } 114 115 $html = implode('', $diff_lines); 116 117 $html = preg_replace_callback('/@(' . Gedcom::REGEX_XREF . ')@/', static function (array $match) use ($tree): string { 118 $record = Registry::gedcomRecordFactory()->make($match[0], $tree); 119 120 if ($record instanceof GedcomRecord) { 121 $title = strip_tags($record->fullName()); 122 $href = e($record->url()); 123 124 return '<a href="' . $href . '" title="' . $title . '">' . $match[0] . '</a>'; 125 } 126 127 return $match[0]; 128 }, $html); 129 130 return '<pre class="gedcom-data">' . $html . '</pre>'; 131 } 132} 133