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