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