1*6fd01894SGreg Roach<?php 2*6fd01894SGreg Roach 3*6fd01894SGreg Roach/** 4*6fd01894SGreg Roach * webtrees: online genealogy 5*6fd01894SGreg Roach * Copyright (C) 2020 webtrees development team 6*6fd01894SGreg Roach * This program is free software: you can redistribute it and/or modify 7*6fd01894SGreg Roach * it under the terms of the GNU General Public License as published by 8*6fd01894SGreg Roach * the Free Software Foundation, either version 3 of the License, or 9*6fd01894SGreg Roach * (at your option) any later version. 10*6fd01894SGreg Roach * This program is distributed in the hope that it will be useful, 11*6fd01894SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*6fd01894SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*6fd01894SGreg Roach * GNU General Public License for more details. 14*6fd01894SGreg Roach * You should have received a copy of the GNU General Public License 15*6fd01894SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 16*6fd01894SGreg Roach */ 17*6fd01894SGreg Roach 18*6fd01894SGreg Roachdeclare(strict_types=1); 19*6fd01894SGreg Roach 20*6fd01894SGreg Roachnamespace Fisharebest\Webtrees\Http\RequestHandlers; 21*6fd01894SGreg Roach 22*6fd01894SGreg Roachuse Fisharebest\Webtrees\FlashMessages; 23*6fd01894SGreg Roachuse Fisharebest\Webtrees\Header; 24*6fd01894SGreg Roachuse Fisharebest\Webtrees\I18N; 25*6fd01894SGreg Roachuse Fisharebest\Webtrees\Services\AdminService; 26*6fd01894SGreg Roachuse Fisharebest\Webtrees\Services\TreeService; 27*6fd01894SGreg Roachuse Fisharebest\Webtrees\Tree; 28*6fd01894SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 29*6fd01894SGreg Roachuse Illuminate\Database\Query\Builder; 30*6fd01894SGreg Roachuse Illuminate\Database\Query\Expression; 31*6fd01894SGreg Roachuse Psr\Http\Message\ResponseInterface; 32*6fd01894SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 33*6fd01894SGreg Roachuse Psr\Http\Server\RequestHandlerInterface; 34*6fd01894SGreg Roach 35*6fd01894SGreg Roachuse function redirect; 36*6fd01894SGreg Roachuse function route; 37*6fd01894SGreg Roach 38*6fd01894SGreg Roach/** 39*6fd01894SGreg Roach * Merge two family trees. 40*6fd01894SGreg Roach */ 41*6fd01894SGreg Roachclass MergeTreesAction implements RequestHandlerInterface 42*6fd01894SGreg Roach{ 43*6fd01894SGreg Roach /** @var AdminService */ 44*6fd01894SGreg Roach private $admin_service; 45*6fd01894SGreg Roach 46*6fd01894SGreg Roach /** @var TreeService */ 47*6fd01894SGreg Roach private $tree_service; 48*6fd01894SGreg Roach 49*6fd01894SGreg Roach /** 50*6fd01894SGreg Roach * AdminTreesController constructor. 51*6fd01894SGreg Roach * 52*6fd01894SGreg Roach * @param AdminService $admin_service 53*6fd01894SGreg Roach * @param TreeService $tree_service 54*6fd01894SGreg Roach */ 55*6fd01894SGreg Roach public function __construct(AdminService $admin_service, TreeService $tree_service) 56*6fd01894SGreg Roach { 57*6fd01894SGreg Roach $this->admin_service = $admin_service; 58*6fd01894SGreg Roach $this->tree_service = $tree_service; 59*6fd01894SGreg Roach } 60*6fd01894SGreg Roach 61*6fd01894SGreg Roach /** 62*6fd01894SGreg Roach * @param ServerRequestInterface $request 63*6fd01894SGreg Roach * 64*6fd01894SGreg Roach * @return ResponseInterface 65*6fd01894SGreg Roach */ 66*6fd01894SGreg Roach public function handle(ServerRequestInterface $request): ResponseInterface 67*6fd01894SGreg Roach { 68*6fd01894SGreg Roach $params = (array) $request->getParsedBody(); 69*6fd01894SGreg Roach $tree1_name = $params['tree1_name'] ?? ''; 70*6fd01894SGreg Roach $tree2_name = $params['tree2_name'] ?? ''; 71*6fd01894SGreg Roach 72*6fd01894SGreg Roach $tree1 = $this->tree_service->all()->get($tree1_name); 73*6fd01894SGreg Roach $tree2 = $this->tree_service->all()->get($tree2_name); 74*6fd01894SGreg Roach 75*6fd01894SGreg Roach if ($tree1 instanceof Tree && $tree2 instanceof Tree && $tree1 !== $tree2 && $this->admin_service->countCommonXrefs($tree1, $tree2) === 0) { 76*6fd01894SGreg Roach (new Builder(DB::connection()))->from('individuals')->insertUsing([ 77*6fd01894SGreg Roach 'i_file', 78*6fd01894SGreg Roach 'i_id', 79*6fd01894SGreg Roach 'i_rin', 80*6fd01894SGreg Roach 'i_sex', 81*6fd01894SGreg Roach 'i_gedcom', 82*6fd01894SGreg Roach ], static function (Builder $query) use ($tree1, $tree2): void { 83*6fd01894SGreg Roach $query->select([ 84*6fd01894SGreg Roach new Expression($tree2->id()), 85*6fd01894SGreg Roach 'i_id', 86*6fd01894SGreg Roach 'i_rin', 87*6fd01894SGreg Roach 'i_sex', 88*6fd01894SGreg Roach 'i_gedcom', 89*6fd01894SGreg Roach ])->from('individuals') 90*6fd01894SGreg Roach ->where('i_file', '=', $tree1->id()); 91*6fd01894SGreg Roach }); 92*6fd01894SGreg Roach 93*6fd01894SGreg Roach (new Builder(DB::connection()))->from('families')->insertUsing([ 94*6fd01894SGreg Roach 'f_file', 95*6fd01894SGreg Roach 'f_id', 96*6fd01894SGreg Roach 'f_husb', 97*6fd01894SGreg Roach 'f_wife', 98*6fd01894SGreg Roach 'f_gedcom', 99*6fd01894SGreg Roach 'f_numchil', 100*6fd01894SGreg Roach ], static function (Builder $query) use ($tree1, $tree2): void { 101*6fd01894SGreg Roach $query->select([ 102*6fd01894SGreg Roach new Expression($tree2->id()), 103*6fd01894SGreg Roach 'f_id', 104*6fd01894SGreg Roach 'f_husb', 105*6fd01894SGreg Roach 'f_wife', 106*6fd01894SGreg Roach 'f_gedcom', 107*6fd01894SGreg Roach 'f_numchil', 108*6fd01894SGreg Roach ])->from('families') 109*6fd01894SGreg Roach ->where('f_file', '=', $tree1->id()); 110*6fd01894SGreg Roach }); 111*6fd01894SGreg Roach 112*6fd01894SGreg Roach (new Builder(DB::connection()))->from('sources')->insertUsing([ 113*6fd01894SGreg Roach 's_file', 114*6fd01894SGreg Roach 's_id', 115*6fd01894SGreg Roach 's_name', 116*6fd01894SGreg Roach 's_gedcom', 117*6fd01894SGreg Roach ], static function (Builder $query) use ($tree1, $tree2): void { 118*6fd01894SGreg Roach $query->select([ 119*6fd01894SGreg Roach new Expression($tree2->id()), 120*6fd01894SGreg Roach 's_id', 121*6fd01894SGreg Roach 's_name', 122*6fd01894SGreg Roach 's_gedcom', 123*6fd01894SGreg Roach ])->from('sources') 124*6fd01894SGreg Roach ->where('s_file', '=', $tree1->id()); 125*6fd01894SGreg Roach }); 126*6fd01894SGreg Roach 127*6fd01894SGreg Roach (new Builder(DB::connection()))->from('media')->insertUsing([ 128*6fd01894SGreg Roach 'm_file', 129*6fd01894SGreg Roach 'm_id', 130*6fd01894SGreg Roach 'm_gedcom', 131*6fd01894SGreg Roach ], static function (Builder $query) use ($tree1, $tree2): void { 132*6fd01894SGreg Roach $query->select([ 133*6fd01894SGreg Roach new Expression($tree2->id()), 134*6fd01894SGreg Roach 'm_id', 135*6fd01894SGreg Roach 'm_gedcom', 136*6fd01894SGreg Roach ])->from('media') 137*6fd01894SGreg Roach ->where('m_file', '=', $tree1->id()); 138*6fd01894SGreg Roach }); 139*6fd01894SGreg Roach 140*6fd01894SGreg Roach (new Builder(DB::connection()))->from('media_file')->insertUsing([ 141*6fd01894SGreg Roach 'm_file', 142*6fd01894SGreg Roach 'm_id', 143*6fd01894SGreg Roach 'multimedia_file_refn', 144*6fd01894SGreg Roach 'multimedia_format', 145*6fd01894SGreg Roach 'source_media_type', 146*6fd01894SGreg Roach 'descriptive_title', 147*6fd01894SGreg Roach ], static function (Builder $query) use ($tree1, $tree2): void { 148*6fd01894SGreg Roach $query->select([ 149*6fd01894SGreg Roach new Expression($tree2->id()), 150*6fd01894SGreg Roach 'm_id', 151*6fd01894SGreg Roach 'multimedia_file_refn', 152*6fd01894SGreg Roach 'multimedia_format', 153*6fd01894SGreg Roach 'source_media_type', 154*6fd01894SGreg Roach 'descriptive_title', 155*6fd01894SGreg Roach ])->from('media_file') 156*6fd01894SGreg Roach ->where('m_file', '=', $tree1->id()); 157*6fd01894SGreg Roach }); 158*6fd01894SGreg Roach 159*6fd01894SGreg Roach (new Builder(DB::connection()))->from('other')->insertUsing([ 160*6fd01894SGreg Roach 'o_file', 161*6fd01894SGreg Roach 'o_id', 162*6fd01894SGreg Roach 'o_type', 163*6fd01894SGreg Roach 'o_gedcom', 164*6fd01894SGreg Roach ], static function (Builder $query) use ($tree1, $tree2): void { 165*6fd01894SGreg Roach $query->select([ 166*6fd01894SGreg Roach new Expression($tree2->id()), 167*6fd01894SGreg Roach 'o_id', 168*6fd01894SGreg Roach 'o_type', 169*6fd01894SGreg Roach 'o_gedcom', 170*6fd01894SGreg Roach ])->from('other') 171*6fd01894SGreg Roach ->whereNotIn('o_type', [Header::RECORD_TYPE, 'TRLR']) 172*6fd01894SGreg Roach ->where('o_file', '=', $tree1->id()); 173*6fd01894SGreg Roach }); 174*6fd01894SGreg Roach 175*6fd01894SGreg Roach (new Builder(DB::connection()))->from('name')->insertUsing([ 176*6fd01894SGreg Roach 'n_file', 177*6fd01894SGreg Roach 'n_id', 178*6fd01894SGreg Roach 'n_num', 179*6fd01894SGreg Roach 'n_type', 180*6fd01894SGreg Roach 'n_sort', 181*6fd01894SGreg Roach 'n_full', 182*6fd01894SGreg Roach 'n_surname', 183*6fd01894SGreg Roach 'n_surn', 184*6fd01894SGreg Roach 'n_givn', 185*6fd01894SGreg Roach 'n_soundex_givn_std', 186*6fd01894SGreg Roach 'n_soundex_surn_std', 187*6fd01894SGreg Roach 'n_soundex_givn_dm', 188*6fd01894SGreg Roach 'n_soundex_surn_dm', 189*6fd01894SGreg Roach ], static function (Builder $query) use ($tree1, $tree2): void { 190*6fd01894SGreg Roach $query->select([ 191*6fd01894SGreg Roach new Expression($tree2->id()), 192*6fd01894SGreg Roach 'n_id', 193*6fd01894SGreg Roach 'n_num', 194*6fd01894SGreg Roach 'n_type', 195*6fd01894SGreg Roach 'n_sort', 196*6fd01894SGreg Roach 'n_full', 197*6fd01894SGreg Roach 'n_surname', 198*6fd01894SGreg Roach 'n_surn', 199*6fd01894SGreg Roach 'n_givn', 200*6fd01894SGreg Roach 'n_soundex_givn_std', 201*6fd01894SGreg Roach 'n_soundex_surn_std', 202*6fd01894SGreg Roach 'n_soundex_givn_dm', 203*6fd01894SGreg Roach 'n_soundex_surn_dm', 204*6fd01894SGreg Roach ])->from('name') 205*6fd01894SGreg Roach ->where('n_file', '=', $tree1->id()); 206*6fd01894SGreg Roach }); 207*6fd01894SGreg Roach 208*6fd01894SGreg Roach (new Builder(DB::connection()))->from('dates')->insertUsing([ 209*6fd01894SGreg Roach 'd_file', 210*6fd01894SGreg Roach 'd_gid', 211*6fd01894SGreg Roach 'd_day', 212*6fd01894SGreg Roach 'd_month', 213*6fd01894SGreg Roach 'd_mon', 214*6fd01894SGreg Roach 'd_year', 215*6fd01894SGreg Roach 'd_julianday1', 216*6fd01894SGreg Roach 'd_julianday2', 217*6fd01894SGreg Roach 'd_fact', 218*6fd01894SGreg Roach 'd_type', 219*6fd01894SGreg Roach ], static function (Builder $query) use ($tree1, $tree2): void { 220*6fd01894SGreg Roach $query->select([ 221*6fd01894SGreg Roach new Expression($tree2->id()), 222*6fd01894SGreg Roach 'd_gid', 223*6fd01894SGreg Roach 'd_day', 224*6fd01894SGreg Roach 'd_month', 225*6fd01894SGreg Roach 'd_mon', 226*6fd01894SGreg Roach 'd_year', 227*6fd01894SGreg Roach 'd_julianday1', 228*6fd01894SGreg Roach 'd_julianday2', 229*6fd01894SGreg Roach 'd_fact', 230*6fd01894SGreg Roach 'd_type', 231*6fd01894SGreg Roach ])->from('dates') 232*6fd01894SGreg Roach ->where('d_file', '=', $tree1->id()); 233*6fd01894SGreg Roach }); 234*6fd01894SGreg Roach 235*6fd01894SGreg Roach (new Builder(DB::connection()))->from('link')->insertUsing([ 236*6fd01894SGreg Roach 'l_file', 237*6fd01894SGreg Roach 'l_from', 238*6fd01894SGreg Roach 'l_type', 239*6fd01894SGreg Roach 'l_to', 240*6fd01894SGreg Roach ], static function (Builder $query) use ($tree1, $tree2): void { 241*6fd01894SGreg Roach $query->select([ 242*6fd01894SGreg Roach new Expression($tree2->id()), 243*6fd01894SGreg Roach 'l_from', 244*6fd01894SGreg Roach 'l_type', 245*6fd01894SGreg Roach 'l_to', 246*6fd01894SGreg Roach ])->from('link') 247*6fd01894SGreg Roach ->whereNotIn('l_from', [Header::RECORD_TYPE, 'TRLR']) 248*6fd01894SGreg Roach ->where('l_file', '=', $tree1->id()); 249*6fd01894SGreg Roach }); 250*6fd01894SGreg Roach 251*6fd01894SGreg Roach FlashMessages::addMessage(I18N::translate('The family trees have been merged successfully.'), 'success'); 252*6fd01894SGreg Roach 253*6fd01894SGreg Roach $url = route(ManageTrees::class, ['tree' => $tree2->name()]); 254*6fd01894SGreg Roach } else { 255*6fd01894SGreg Roach $url = route(MergeTreesPage::class, [ 256*6fd01894SGreg Roach 'tree1_name' => $tree1->name(), 257*6fd01894SGreg Roach 'tree2_name' => $tree2->name(), 258*6fd01894SGreg Roach ]); 259*6fd01894SGreg Roach } 260*6fd01894SGreg Roach 261*6fd01894SGreg Roach return redirect($url); 262*6fd01894SGreg Roach } 263*6fd01894SGreg Roach} 264