xref: /webtrees/app/Http/RequestHandlers/MergeTreesAction.php (revision 1270d2767576ed4a83917769b0ee3613e3b010bf)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2023 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 <https://www.gnu.org/licenses/>.
16 */
17
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees\Http\RequestHandlers;
21
22use Fisharebest\Webtrees\DB;
23use Fisharebest\Webtrees\FlashMessages;
24use Fisharebest\Webtrees\Header;
25use Fisharebest\Webtrees\I18N;
26use Fisharebest\Webtrees\Services\AdminService;
27use Fisharebest\Webtrees\Services\TreeService;
28use Fisharebest\Webtrees\Tree;
29use Fisharebest\Webtrees\Validator;
30use Illuminate\Database\Query\Builder;
31use Illuminate\Database\Query\Expression;
32use Psr\Http\Message\ResponseInterface;
33use Psr\Http\Message\ServerRequestInterface;
34use Psr\Http\Server\RequestHandlerInterface;
35
36use function redirect;
37use function route;
38
39/**
40 * Merge two family trees.
41 */
42class MergeTreesAction implements RequestHandlerInterface
43{
44    private AdminService $admin_service;
45
46    private TreeService $tree_service;
47
48    /**
49     * @param AdminService $admin_service
50     * @param TreeService  $tree_service
51     */
52    public function __construct(AdminService $admin_service, TreeService $tree_service)
53    {
54        $this->admin_service = $admin_service;
55        $this->tree_service  = $tree_service;
56    }
57
58    /**
59     * @param ServerRequestInterface $request
60     *
61     * @return ResponseInterface
62     */
63    public function handle(ServerRequestInterface $request): ResponseInterface
64    {
65        $tree1_name = Validator::parsedBody($request)->string('tree1_name');
66        $tree2_name = Validator::parsedBody($request)->string('tree2_name');
67
68        $tree1 = $this->tree_service->all()->get($tree1_name);
69        $tree2 = $this->tree_service->all()->get($tree2_name);
70
71        if ($tree1 instanceof Tree && $tree2 instanceof Tree && $tree1 !== $tree2 && $this->admin_service->countCommonXrefs($tree1, $tree2) === 0) {
72            DB::query()->from('individuals')->insertUsing([
73                'i_file',
74                'i_id',
75                'i_rin',
76                'i_sex',
77                'i_gedcom',
78            ], static function (Builder $query) use ($tree1, $tree2): void {
79                $query->select([
80                    new Expression($tree2->id()),
81                    'i_id',
82                    'i_rin',
83                    'i_sex',
84                    'i_gedcom',
85                ])->from('individuals')
86                    ->where('i_file', '=', $tree1->id());
87            });
88
89            DB::query()->from('families')->insertUsing([
90                'f_file',
91                'f_id',
92                'f_husb',
93                'f_wife',
94                'f_gedcom',
95                'f_numchil',
96            ], static function (Builder $query) use ($tree1, $tree2): void {
97                $query->select([
98                    new Expression($tree2->id()),
99                    'f_id',
100                    'f_husb',
101                    'f_wife',
102                    'f_gedcom',
103                    'f_numchil',
104                ])->from('families')
105                    ->where('f_file', '=', $tree1->id());
106            });
107
108            DB::query()->from('sources')->insertUsing([
109                's_file',
110                's_id',
111                's_name',
112                's_gedcom',
113            ], static function (Builder $query) use ($tree1, $tree2): void {
114                $query->select([
115                    new Expression($tree2->id()),
116                    's_id',
117                    's_name',
118                    's_gedcom',
119                ])->from('sources')
120                    ->where('s_file', '=', $tree1->id());
121            });
122
123            DB::query()->from('media')->insertUsing([
124                'm_file',
125                'm_id',
126                'm_gedcom',
127            ], static function (Builder $query) use ($tree1, $tree2): void {
128                $query->select([
129                    new Expression($tree2->id()),
130                    'm_id',
131                    'm_gedcom',
132                ])->from('media')
133                    ->where('m_file', '=', $tree1->id());
134            });
135
136            DB::query()->from('media_file')->insertUsing([
137                'm_file',
138                'm_id',
139                'multimedia_file_refn',
140                'multimedia_format',
141                'source_media_type',
142                'descriptive_title',
143            ], static function (Builder $query) use ($tree1, $tree2): void {
144                $query->select([
145                    new Expression($tree2->id()),
146                    'm_id',
147                    'multimedia_file_refn',
148                    'multimedia_format',
149                    'source_media_type',
150                    'descriptive_title',
151                ])->from('media_file')
152                    ->where('m_file', '=', $tree1->id());
153            });
154
155            DB::query()->from('other')->insertUsing([
156                'o_file',
157                'o_id',
158                'o_type',
159                'o_gedcom',
160            ], static function (Builder $query) use ($tree1, $tree2): void {
161                $query->select([
162                    new Expression($tree2->id()),
163                    'o_id',
164                    'o_type',
165                    'o_gedcom',
166                ])->from('other')
167                    ->whereNotIn('o_type', [Header::RECORD_TYPE, 'TRLR'])
168                    ->where('o_file', '=', $tree1->id());
169            });
170
171            DB::query()->from('name')->insertUsing([
172                'n_file',
173                'n_id',
174                'n_num',
175                'n_type',
176                'n_sort',
177                'n_full',
178                'n_surname',
179                'n_surn',
180                'n_givn',
181                'n_soundex_givn_std',
182                'n_soundex_surn_std',
183                'n_soundex_givn_dm',
184                'n_soundex_surn_dm',
185            ], static function (Builder $query) use ($tree1, $tree2): void {
186                $query->select([
187                    new Expression($tree2->id()),
188                    'n_id',
189                    'n_num',
190                    'n_type',
191                    'n_sort',
192                    'n_full',
193                    'n_surname',
194                    'n_surn',
195                    'n_givn',
196                    'n_soundex_givn_std',
197                    'n_soundex_surn_std',
198                    'n_soundex_givn_dm',
199                    'n_soundex_surn_dm',
200                ])->from('name')
201                    ->where('n_file', '=', $tree1->id());
202            });
203
204            DB::query()->from('dates')->insertUsing([
205                'd_file',
206                'd_gid',
207                'd_day',
208                'd_month',
209                'd_mon',
210                'd_year',
211                'd_julianday1',
212                'd_julianday2',
213                'd_fact',
214                'd_type',
215            ], static function (Builder $query) use ($tree1, $tree2): void {
216                $query->select([
217                    new Expression($tree2->id()),
218                    'd_gid',
219                    'd_day',
220                    'd_month',
221                    'd_mon',
222                    'd_year',
223                    'd_julianday1',
224                    'd_julianday2',
225                    'd_fact',
226                    'd_type',
227                ])->from('dates')
228                    ->where('d_file', '=', $tree1->id());
229            });
230
231            DB::query()->from('link')->insertUsing([
232                'l_file',
233                'l_from',
234                'l_type',
235                'l_to',
236            ], static function (Builder $query) use ($tree1, $tree2): void {
237                $query->select([
238                    new Expression($tree2->id()),
239                    'l_from',
240                    'l_type',
241                    'l_to',
242                ])->from('link')
243                    ->whereNotIn('l_from', [Header::RECORD_TYPE, 'TRLR'])
244                    ->where('l_file', '=', $tree1->id());
245            });
246
247            FlashMessages::addMessage(I18N::translate('The family trees have been merged successfully.'), 'success');
248
249            $url = route(ManageTrees::class, ['tree' => $tree2->name()]);
250        } else {
251            $url = route(MergeTreesPage::class, [
252                'tree1_name' => $tree1->name(),
253                'tree2_name' => $tree2->name(),
254            ]);
255        }
256
257        return redirect($url);
258    }
259}
260