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\Factories; 21 22use Fisharebest\Webtrees\Contracts\XrefFactoryInterface; 23use Fisharebest\Webtrees\Site; 24use Illuminate\Database\Capsule\Manager as DB; 25 26/** 27 * Make an XREF. 28 */ 29class XrefFactory implements XrefFactoryInterface 30{ 31 /** 32 * Create a new XREF. 33 * 34 * @param string $record_type 35 * 36 * @return string 37 */ 38 public function make(string $record_type): string 39 { 40 return $this->generate('X', ''); 41 } 42 43 /** 44 * @param string $prefix 45 * @param string $suffix 46 * 47 * @return string 48 */ 49 protected function generate(string $prefix, string $suffix): string 50 { 51 // Lock the row, so that only one new XREF may be generated at a time. 52 DB::table('site_setting') 53 ->where('setting_name', '=', 'next_xref') 54 ->lockForUpdate() 55 ->get(); 56 57 $increment = 1.0; 58 do { 59 $num = (int) Site::getPreference('next_xref') + (int) $increment; 60 61 // This exponential increment allows us to scan over large blocks of 62 // existing data in a reasonable time. 63 $increment *= 1.01; 64 65 $xref = $prefix . $num . $suffix; 66 67 // Records may already exist with this sequence number. 68 $already_used = 69 DB::table('individuals')->where('i_id', '=', $xref)->exists() || 70 DB::table('families')->where('f_id', '=', $xref)->exists() || 71 DB::table('sources')->where('s_id', '=', $xref)->exists() || 72 DB::table('media')->where('m_id', '=', $xref)->exists() || 73 DB::table('other')->where('o_id', '=', $xref)->exists() || 74 DB::table('change')->where('xref', '=', $xref)->exists(); 75 } while ($already_used); 76 77 Site::setPreference('next_xref', (string) $num); 78 79 return $xref; 80 } 81} 82