.
*/
declare(strict_types=1);
namespace Fisharebest\Webtrees\Http\RequestHandlers;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Factory;
use Fisharebest\Webtrees\FlashMessages;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Tree;
use Fisharebest\Webtrees\User;
use Illuminate\Database\Capsule\Manager as DB;
use Illuminate\Database\Query\Expression;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use function assert;
use function e;
use function in_array;
use function preg_replace;
use function redirect;
use function route;
use function str_replace;
/**
* Merge records
*/
class MergeFactsAction implements RequestHandlerInterface
{
/**
* @param ServerRequestInterface $request
*
* @return ResponseInterface
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$tree = $request->getAttribute('tree');
assert($tree instanceof Tree);
$params = (array) $request->getParsedBody();
$xref1 = $params['xref1'] ?? '';
$xref2 = $params['xref2'] ?? '';
$keep1 = $params['keep1'] ?? [];
$keep2 = $params['keep2'] ?? [];
// Merge record2 into record1
$record1 = Factory::gedcomRecord()->make($xref1, $tree);
$record2 = Factory::gedcomRecord()->make($xref2, $tree);
if (
$record1 === null ||
$record2 === null ||
$record1 === $record2 ||
$record1->tag() !== $record2->tag() ||
$record1->isPendingDeletion() ||
$record2->isPendingDeletion()
) {
return redirect(route(MergeRecordsPage::class, [
'tree' => $tree->name(),
'xref1' => $xref1,
'xref2' => $xref2,
]));
}
// If we are not auto-accepting, then we can show a link to the pending deletion
if (Auth::user()->getPreference(User::PREF_AUTO_ACCEPT_EDITS) === '1') {
$record2_name = $record2->fullName();
} else {
$record2_name = '' . $record2->fullName() . '';
}
// Update records that link to the one we will be removing.
$linking_records = $record2->linkingRecords();
foreach ($linking_records as $record) {
if (!$record->isPendingDeletion()) {
/* I18N: The placeholders are the names of individuals, sources, etc. */
FlashMessages::addMessage(I18N::translate(
'The link from “%1$s” to “%2$s” has been updated.',
'' . $record->fullName() . '',
$record2_name
), 'info');
$gedcom = str_replace('@' . $xref2 . '@', '@' . $xref1 . '@', $record->gedcom());
$gedcom = preg_replace(
'/(\n1.*@.+@.*(?:(?:\n[2-9].*)*))((?:\n1.*(?:\n[2-9].*)*)*\1)/',
'$2',
$gedcom
);
$record->updateRecord($gedcom, true);
}
}
// Update any linked user-accounts
DB::table('user_gedcom_setting')
->where('gedcom_id', '=', $tree->id())
->whereIn('setting_name', [User::PREF_TREE_ACCOUNT_XREF, User::PREF_TREE_DEFAULT_XREF])
->where('setting_value', '=', $xref2)
->update(['setting_value' => $xref1]);
// Merge hit counters
$hits = DB::table('hit_counter')
->where('gedcom_id', '=', $tree->id())
->whereIn('page_parameter', [$xref1, $xref2])
->groupBy(['page_name'])
->pluck(new Expression('SUM(page_count)'), 'page_name');
foreach ($hits as $page_name => $page_count) {
DB::table('hit_counter')
->where('gedcom_id', '=', $tree->id())
->where('page_name', '=', $page_name)
->where('page_parameter', '=', $xref1)
->update(['page_count' => $page_count]);
}
DB::table('hit_counter')
->where('gedcom_id', '=', $tree->id())
->where('page_parameter', '=', $xref2)
->delete();
$gedcom = '0 @' . $record1->xref() . '@ ' . $record1->tag();
foreach ($record1->facts() as $fact) {
if (in_array($fact->id(), $keep1, true)) {
$gedcom .= "\n" . $fact->gedcom();
}
}
foreach ($record2->facts() as $fact) {
if (in_array($fact->id(), $keep2, true)) {
$gedcom .= "\n" . $fact->gedcom();
}
}
DB::table('favorite')
->where('gedcom_id', '=', $tree->id())
->where('xref', '=', $xref2)
->update(['xref' => $xref1]);
$record1->updateRecord($gedcom, true);
$record2->deleteRecord();
/* I18N: Records are individuals, sources, etc. */
FlashMessages::addMessage(I18N::translate(
'The records “%1$s” and “%2$s” have been merged.',
'' . $record1->fullName() . '',
$record2_name
), 'success');
return redirect(route(MergeRecordsPage::class, ['tree' => $tree->name()]));
}
}