1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2019 webtrees development team 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16declare(strict_types=1); 17 18namespace Fisharebest\Webtrees\Services; 19 20use Fisharebest\Webtrees\Fact; 21use Fisharebest\Webtrees\GedcomRecord; 22use Fisharebest\Webtrees\Session; 23 24/** 25 * Copy and past facts between records. 26 */ 27class ClipboardService 28{ 29 // Maximum number of entries in the clipboard. 30 private const CLIPBOARD_SIZE = 10; 31 32 // Some facts can be copied to multiple types of record. 33 // Others can only be copied to the same type. 34 // NOTE: just because GEDCOM permits these, it doesn't mean that they are advisable. 35 private const DESTINATION_TYPES = [ 36 'CENS' => ['FAM', 'INDI'], 37 'RESI' => ['FAM', 'INDI'], 38 'NOTE' => ['FAM', 'INDI', 'OBJE', 'REPO', 'SOUR'], 39 'OBJE' => ['FAM', 'INDI', 'NOTE', 'SOUR'], 40 'SOUR' => ['FAM', 'INDI', 'NOTE', 'OBJE'], 41 ]; 42 43 /** 44 * Copy a fact to the clipboard. 45 * 46 * @param Fact $fact 47 */ 48 public function copyFact(Fact $fact): void 49 { 50 $clipboard = Session::get('clipboard', []); 51 52 $fact_type = $fact->getTag(); 53 $record_type = $fact->record()::RECORD_TYPE; 54 55 $destination_types = self::DESTINATION_TYPES[$fact_type] ?? [$record_type]; 56 57 $fact_id = $fact->id(); 58 59 foreach ($destination_types as $destination_type) { 60 // If we are copying the same fact twice, make sure the new one is at the end. 61 unset($clipboard[$destination_type][$fact_id]); 62 63 $clipboard[$destination_type][$fact_id] = [ 64 'factrec' => $fact->gedcom(), 65 'fact' => $fact->getTag(), 66 ]; 67 68 // The clipboard only holds a limited number of facts. 69 $clipboard[$destination_type] = array_slice($clipboard[$destination_type], -self::CLIPBOARD_SIZE); 70 } 71 72 Session::put('clipboard', $clipboard); 73 } 74 75 /** 76 * Copy a fact from the clipboard to a record. 77 * 78 * @param string $fact_id 79 * @param GedcomRecord $record 80 * 81 * @return bool 82 */ 83 public function pasteFact(string $fact_id, GedcomRecord $record): bool 84 { 85 $clipboard = Session::get('clipboard'); 86 87 $record_type = $record::RECORD_TYPE; 88 89 if (isset($clipboard[$record_type][$fact_id])) { 90 $record->createFact($clipboard[$record_type][$fact_id]['factrec'], true); 91 92 return true; 93 } 94 95 return false; 96 } 97 98 /** 99 * Createa a list of facts that can be pasted into a given record 100 * 101 * @param GedcomRecord $record 102 * 103 * @return Fact[] 104 */ 105 public function pastableFacts(GedcomRecord $record): array 106 { 107 // The facts are stored in the session. 108 $clipboard = Session::get('clipboard', []); 109 110 // Put the most recently copied fact at the top of the list. 111 $clipboard = array_reverse($clipboard[$record::RECORD_TYPE] ?? []); 112 113 // Create facts for the record. 114 $facts = array_map(function (array $clipping) use ($record): Fact { 115 return new Fact($clipping['factrec'], $record, md5($clipping['factrec'])); 116 }, $clipboard); 117 118 return $facts; 119 } 120} 121