1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2018 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 $clipboard = Session::get('clipboard', []); 50 51 $fact_type = $fact->getTag(); 52 $record_type = $fact->record()::RECORD_TYPE; 53 54 $destination_types = self::DESTINATION_TYPES[$fact_type] ?? [$record_type]; 55 56 $fact_id = $fact->id(); 57 58 foreach ($destination_types as $destination_type) { 59 // If we are copying the same fact twice, make sure the new one is at the end. 60 unset($clipboard[$destination_type][$fact_id]); 61 62 $clipboard[$destination_type][$fact_id] = [ 63 'factrec' => $fact->gedcom(), 64 'fact' => $fact->getTag(), 65 ]; 66 67 // The clipboard only holds a limited number of facts. 68 $clipboard[$destination_type] = array_slice($clipboard[$destination_type], -self::CLIPBOARD_SIZE); 69 } 70 71 Session::put('clipboard', $clipboard); 72 } 73 74 /** 75 * Copy a fact from the clipboard to a record. 76 * 77 * @param string $fact_id 78 * @param GedcomRecord $record 79 * 80 * @return bool 81 */ 82 public function pasteFact(string $fact_id, GedcomRecord $record): bool { 83 $clipboard = Session::get('clipboard'); 84 85 $record_type = $record::RECORD_TYPE; 86 87 if (isset($clipboard[$record_type][$fact_id])) { 88 $record->createFact($clipboard[$record_type][$fact_id]['factrec'], true); 89 90 return true; 91 } 92 93 return false; 94 } 95 96 /** 97 * Createa a list of facts that can be pasted into a given record 98 * 99 * @param GedcomRecord $record 100 * 101 * @return Fact[] 102 */ 103 public function pastableFacts(GedcomRecord $record): array { 104 // The facts are stored in the session. 105 $clipboard = Session::get('clipboard', []); 106 107 // Put the most recently copied fact at the top of the list. 108 $clipboard = array_reverse($clipboard[$record::RECORD_TYPE] ?? []); 109 110 // Create facts for the record. 111 $facts = array_map(function(array $clipping) use ($record): Fact { 112 return new Fact($clipping['factrec'], $record, md5($clipping['factrec'])); 113 }, $clipboard); 114 115 return $facts; 116 } 117} 118