xref: /webtrees/app/Services/ClipboardService.php (revision b8361dd5080ab0443965de1e3b951eabe557fe5b)
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