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