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