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