summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Contracts/XrefFactoryInterface.php35
-rw-r--r--app/Factories/XrefFactory.php81
-rw-r--r--app/Factory.php20
-rw-r--r--app/Functions/FunctionsImport.php2
-rw-r--r--app/Http/Controllers/AdminTreesController.php2
-rw-r--r--app/Http/Middleware/RegisterFactories.php2
-rw-r--r--app/Tree.php43
-rw-r--r--tests/TestCase.php2
8 files changed, 149 insertions, 38 deletions
diff --git a/app/Contracts/XrefFactoryInterface.php b/app/Contracts/XrefFactoryInterface.php
new file mode 100644
index 0000000000..d085f77d29
--- /dev/null
+++ b/app/Contracts/XrefFactoryInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2020 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace Fisharebest\Webtrees\Contracts;
+
+/**
+ * Make an XREF.
+ */
+interface XrefFactoryInterface
+{
+ /**
+ * Create a new XREF.
+ *
+ * @param string $record_type
+ *
+ * @return string
+ */
+ public function make(string $record_type): string;
+}
diff --git a/app/Factories/XrefFactory.php b/app/Factories/XrefFactory.php
new file mode 100644
index 0000000000..807de864ce
--- /dev/null
+++ b/app/Factories/XrefFactory.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * webtrees: online genealogy
+ * Copyright (C) 2020 webtrees development team
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace Fisharebest\Webtrees\Factories;
+
+use Fisharebest\Webtrees\Contracts\XrefFactoryInterface;
+use Fisharebest\Webtrees\Site;
+use Illuminate\Database\Capsule\Manager as DB;
+
+/**
+ * Make an XREF.
+ */
+class XrefFactory implements XrefFactoryInterface
+{
+ /**
+ * Create a new XREF.
+ *
+ * @param string $record_type
+ *
+ * @return string
+ */
+ public function make(string $record_type): string
+ {
+ return $this->generate('X', '');
+ }
+
+ /**
+ * @param string $prefix
+ * @param string $suffix
+ *
+ * @return string
+ */
+ protected function generate(string $prefix, string $suffix): string
+ {
+ // Lock the row, so that only one new XREF may be generated at a time.
+ DB::table('site_setting')
+ ->where('setting_name', '=', 'next_xref')
+ ->lockForUpdate()
+ ->get();
+
+ $increment = 1.0;
+ do {
+ $num = (int) Site::getPreference('next_xref') + (int) $increment;
+
+ // This exponential increment allows us to scan over large blocks of
+ // existing data in a reasonable time.
+ $increment *= 1.01;
+
+ $xref = $prefix . $num . $suffix;
+
+ // Records may already exist with this sequence number.
+ $already_used =
+ DB::table('individuals')->where('i_id', '=', $xref)->exists() ||
+ DB::table('families')->where('f_id', '=', $xref)->exists() ||
+ DB::table('sources')->where('s_id', '=', $xref)->exists() ||
+ DB::table('media')->where('m_id', '=', $xref)->exists() ||
+ DB::table('other')->where('o_id', '=', $xref)->exists() ||
+ DB::table('change')->where('xref', '=', $xref)->exists();
+ } while ($already_used);
+
+ Site::setPreference('next_xref', (string) $num);
+
+ return $xref;
+ }
+}
diff --git a/app/Factory.php b/app/Factory.php
index d6269b6ed8..f164c6287c 100644
--- a/app/Factory.php
+++ b/app/Factory.php
@@ -30,6 +30,7 @@ use Fisharebest\Webtrees\Contracts\RepositoryFactoryInterface;
use Fisharebest\Webtrees\Contracts\SourceFactoryInterface;
use Fisharebest\Webtrees\Contracts\SubmissionFactoryInterface;
use Fisharebest\Webtrees\Contracts\SubmitterFactoryInterface;
+use Fisharebest\Webtrees\Contracts\XrefFactoryInterface;
/**
* A service locator for our various factory objects.
@@ -69,6 +70,9 @@ class Factory
/** @var SubmitterFactoryInterface */
private static $submitter_factory;
+ /** @var XrefFactoryInterface */
+ private static $xref_factory;
+
/**
* Store or retrieve a factory object.
*
@@ -244,4 +248,20 @@ class Factory
return self::$submitter_factory;
}
+
+ /**
+ * Store or retrieve a factory object.
+ *
+ * @param XrefFactoryInterface|null $factory
+ *
+ * @return XrefFactoryInterface
+ */
+ public static function xref(XrefFactoryInterface $factory = null): XrefFactoryInterface
+ {
+ if ($factory instanceof XrefFactoryInterface) {
+ self::$xref_factory = $factory;
+ }
+
+ return self::$xref_factory;
+ }
}
diff --git a/app/Functions/FunctionsImport.php b/app/Functions/FunctionsImport.php
index b8acad3584..26f5255095 100644
--- a/app/Functions/FunctionsImport.php
+++ b/app/Functions/FunctionsImport.php
@@ -666,7 +666,7 @@ class FunctionsImport
->value('m_id');
if ($xref === null) {
- $xref = $tree->getNewXref();
+ $xref = Factory::xref()->make(Media::RECORD_TYPE);
// renumber the lines
$gedrec = preg_replace_callback('/\n(\d+)/', static function (array $m) use ($level): string {
return "\n" . ($m[1] - $level);
diff --git a/app/Http/Controllers/AdminTreesController.php b/app/Http/Controllers/AdminTreesController.php
index fb71935a4b..0a31631ff3 100644
--- a/app/Http/Controllers/AdminTreesController.php
+++ b/app/Http/Controllers/AdminTreesController.php
@@ -995,7 +995,7 @@ class AdminTreesController extends AbstractBaseController
$xrefs = $this->duplicateXrefs($tree);
foreach ($xrefs as $old_xref => $type) {
- $new_xref = $tree->getNewXref();
+ $new_xref = Factory::xref()->make($type);
switch ($type) {
case Individual::RECORD_TYPE:
DB::table('individuals')
diff --git a/app/Http/Middleware/RegisterFactories.php b/app/Http/Middleware/RegisterFactories.php
index f30dbfb3a3..128030fb8f 100644
--- a/app/Http/Middleware/RegisterFactories.php
+++ b/app/Http/Middleware/RegisterFactories.php
@@ -31,6 +31,7 @@ use Fisharebest\Webtrees\Factories\RepositoryFactory;
use Fisharebest\Webtrees\Factories\SourceFactory;
use Fisharebest\Webtrees\Factories\SubmissionFactory;
use Fisharebest\Webtrees\Factories\SubmitterFactory;
+use Fisharebest\Webtrees\Factories\XrefFactory;
use Fisharebest\Webtrees\Factory;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
@@ -67,6 +68,7 @@ class RegisterFactories implements MiddlewareInterface
Factory::source(new SourceFactory($cache));
Factory::submission(new SubmissionFactory($cache));
Factory::submitter(new SubmitterFactory($cache));
+ Factory::xref(new XrefFactory());
return $handler->handle($request);
}
diff --git a/app/Tree.php b/app/Tree.php
index 8c95393812..34b1b6a90b 100644
--- a/app/Tree.php
+++ b/app/Tree.php
@@ -446,11 +446,11 @@ class Tree
*/
public function createRecord(string $gedcom): GedcomRecord
{
- if (!str_starts_with($gedcom, '0 @@ ')) {
+ if (!preg_match('/^0 @@ ([_A-Z]+)/', $gedcom, $match)) {
throw new InvalidArgumentException('GedcomRecord::createRecord(' . $gedcom . ') does not begin 0 @@');
}
- $xref = $this->getNewXref();
+ $xref = Factory::xref()->make($match[1]);
$gedcom = substr_replace($gedcom, $xref, 3, 0);
// Create a change record
@@ -483,40 +483,11 @@ class Tree
* Generate a new XREF, unique across all family trees
*
* @return string
+ * @deprecated - use the factory directly.
*/
public function getNewXref(): string
{
- // Lock the row, so that only one new XREF may be generated at a time.
- DB::table('site_setting')
- ->where('setting_name', '=', 'next_xref')
- ->lockForUpdate()
- ->get();
-
- $prefix = 'X';
-
- $increment = 1.0;
- do {
- $num = (int) Site::getPreference('next_xref') + (int) $increment;
-
- // This exponential increment allows us to scan over large blocks of
- // existing data in a reasonable time.
- $increment *= 1.01;
-
- $xref = $prefix . $num;
-
- // Records may already exist with this sequence number.
- $already_used =
- DB::table('individuals')->where('i_id', '=', $xref)->exists() ||
- DB::table('families')->where('f_id', '=', $xref)->exists() ||
- DB::table('sources')->where('s_id', '=', $xref)->exists() ||
- DB::table('media')->where('m_id', '=', $xref)->exists() ||
- DB::table('other')->where('o_id', '=', $xref)->exists() ||
- DB::table('change')->where('xref', '=', $xref)->exists();
- } while ($already_used);
-
- Site::setPreference('next_xref', (string) $num);
-
- return $xref;
+ return Factory::xref()->make(GedcomRecord::RECORD_TYPE);
}
/**
@@ -533,7 +504,7 @@ class Tree
throw new InvalidArgumentException('GedcomRecord::createFamily(' . $gedcom . ') does not begin 0 @@ FAM');
}
- $xref = $this->getNewXref();
+ $xref = Factory::xref()->make(Family::RECORD_TYPE);
$gedcom = substr_replace($gedcom, $xref, 3, 0);
// Create a change record
@@ -576,7 +547,7 @@ class Tree
throw new InvalidArgumentException('GedcomRecord::createIndividual(' . $gedcom . ') does not begin 0 @@ INDI');
}
- $xref = $this->getNewXref();
+ $xref = Factory::xref()->make(Individual::RECORD_TYPE);
$gedcom = substr_replace($gedcom, $xref, 3, 0);
// Create a change record
@@ -619,7 +590,7 @@ class Tree
throw new InvalidArgumentException('GedcomRecord::createIndividual(' . $gedcom . ') does not begin 0 @@ OBJE');
}
- $xref = $this->getNewXref();
+ $xref = Factory::xref()->make(Media::RECORD_TYPE);
$gedcom = substr_replace($gedcom, $xref, 3, 0);
// Create a change record
diff --git a/tests/TestCase.php b/tests/TestCase.php
index c27ddcb8f6..d18d1ccca6 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -33,6 +33,7 @@ use Fisharebest\Webtrees\Factories\RepositoryFactory;
use Fisharebest\Webtrees\Factories\SourceFactory;
use Fisharebest\Webtrees\Factories\SubmissionFactory;
use Fisharebest\Webtrees\Factories\SubmitterFactory;
+use Fisharebest\Webtrees\Factories\XrefFactory;
use Fisharebest\Webtrees\Http\Controllers\GedcomFileController;
use Fisharebest\Webtrees\Http\Routes\WebRoutes;
use Fisharebest\Webtrees\Module\ModuleThemeInterface;
@@ -102,6 +103,7 @@ class TestCase extends \PHPUnit\Framework\TestCase
Factory::source(new SourceFactory($cache));
Factory::submission(new SubmissionFactory($cache));
Factory::submitter(new SubmitterFactory($cache));
+ Factory::xref(new XrefFactory());
app()->bind(ModuleThemeInterface::class, WebtreesTheme::class);