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 */ 17declare(strict_types=1); 18 19namespace Fisharebest\Webtrees\Services; 20 21use Fisharebest\Webtrees\Fact; 22use Fisharebest\Webtrees\GedcomRecord; 23use Fisharebest\Webtrees\Session; 24use Illuminate\Support\Collection; 25 26/** 27 * Copy and past facts between records. 28 */ 29class ClipboardService 30{ 31 // Maximum number of entries in the clipboard. 32 private const CLIPBOARD_SIZE = 10; 33 34 /** 35 * Copy a fact to the clipboard. 36 * 37 * @param Fact $fact 38 */ 39 public function copyFact(Fact $fact): void 40 { 41 $clipboard = Session::get('clipboard', []); 42 $record_type = $fact->record()::RECORD_TYPE; 43 $fact_id = $fact->id(); 44 45 // If we are copying the same fact twice, make sure the new one is at the end. 46 unset($clipboard[$record_type][$fact_id]); 47 48 $clipboard[$record_type][$fact_id] = [ 49 'factrec' => $fact->gedcom(), 50 'fact' => $fact->getTag(), 51 ]; 52 53 // The clipboard only holds a limited number of facts. 54 $clipboard[$record_type] = array_slice($clipboard[$record_type], -self::CLIPBOARD_SIZE); 55 56 Session::put('clipboard', $clipboard); 57 } 58 59 /** 60 * Copy a fact from the clipboard to a record. 61 * 62 * @param string $fact_id 63 * @param GedcomRecord $record 64 * 65 * @return bool 66 */ 67 public function pasteFact(string $fact_id, GedcomRecord $record): bool 68 { 69 $clipboard = Session::get('clipboard'); 70 71 $record_type = $record::RECORD_TYPE; 72 73 if (isset($clipboard[$record_type][$fact_id])) { 74 $record->createFact($clipboard[$record_type][$fact_id]['factrec'], true); 75 76 return true; 77 } 78 79 return false; 80 } 81 82 /** 83 * Create a list of facts that can be pasted into a given record 84 * 85 * @param GedcomRecord $record 86 * @param Collection $exclude_types 87 * 88 * @return Collection 89 */ 90 public function pastableFacts(GedcomRecord $record, Collection $exclude_types): Collection 91 { 92 // The facts are stored in the session. 93 return (new Collection(Session::get('clipboard', [])[$record::RECORD_TYPE] ?? [])) 94 // Put the most recently copied fact at the top of the list. 95 ->reverse() 96 // Create facts for the record. 97 ->map(static function (array $clipping) use ($record): Fact { 98 return new Fact($clipping['factrec'], $record, md5($clipping['factrec'])); 99 })->filter(static function (Fact $fact) use ($exclude_types): bool { 100 return $exclude_types->isEmpty() || !$exclude_types->contains($fact->getTag()); 101 }); 102 } 103 104 /** 105 * Find facts of a given type, from all records. 106 * 107 * @param GedcomRecord $record 108 * @param Collection $types 109 * 110 * @return Collection 111 */ 112 public function pastableFactsOfType(GedcomRecord $record, Collection $types): Collection 113 { 114 // The facts are stored in the session. 115 return (new Collection(Session::get('clipboard', []))) 116 ->flatten(1) 117 ->reverse() 118 ->map(static function (array $clipping) use ($record): Fact { 119 return new Fact($clipping['factrec'], $record, md5($clipping['factrec'])); 120 }) 121 ->filter(static function (Fact $fact) use ($types): bool { 122 return $types->contains($fact->getTag()); 123 }); 124 } 125} 126