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