diff options
68 files changed, 369 insertions, 570 deletions
diff --git a/app/DB.php b/app/DB.php index 17567f65c8..6db8e8ae0f 100644 --- a/app/DB.php +++ b/app/DB.php @@ -21,17 +21,145 @@ namespace Fisharebest\Webtrees; use Illuminate\Database\Capsule\Manager; use Illuminate\Database\Query\Builder; +use Illuminate\Database\Query\Expression; use PDO; +use PDOException; use RuntimeException; +use SensitiveParameter; /** * Database abstraction */ class DB extends Manager { + // Supported drivers + public const MYSQL = 'mysql'; + public const POSTGRES = 'pgsql'; + public const SQLITE = 'sqlite'; + public const SQL_SERVER = 'sqlsrv'; + + private const COLLATION_ASCII = [ + self::MYSQL => 'ascii_bin', + self::POSTGRES => 'C', + self::SQLITE => 'C', + self::SQL_SERVER => 'Latin1_General_Bin', + ]; + + private const COLLATION_UTF8 = [ + self::MYSQL => 'utf8mb4_unicode_ci', + self::POSTGRES => 'und-x-icu', + self::SQLITE => 'nocase', + self::SQL_SERVER => 'utf8_CI_AI', + ]; + + private const REGEX_OPERATOR = [ + self::MYSQL => 'REGEXP', + self::POSTGRES => '~', + self::SQLITE => 'REGEXP', + self::SQL_SERVER => 'REGEXP', + ]; + + private const DRIVER_INITIALIZATION = [ + self::MYSQL => "SET NAMES utf8mb4, sql_mode := 'ANSI,STRICT_ALL_TABLES', TIME_ZONE := '+00:00', SQL_BIG_SELECTS := 1, GROUP_CONCAT_MAX_LEN := 1048576", + self::POSTGRES => '', + self::SQLITE => 'PRAGMA foreign_keys = ON', + self::SQL_SERVER => 'SET language us_english', // For timestamp columns + ]; + + public static function connect( + #[SensitiveParameter] + string $driver, + #[SensitiveParameter] + string $host, + #[SensitiveParameter] + string $port, + #[SensitiveParameter] + string $database, + #[SensitiveParameter] + string $username, + #[SensitiveParameter] + string $password, + #[SensitiveParameter] + string $prefix, + #[SensitiveParameter] + string $key, + #[SensitiveParameter] + string $certificate, + #[SensitiveParameter] + string $ca, + #[SensitiveParameter] + bool $verify_certificate, + ): void { + $options = [ + // Some drivers do this and some don't. Make them consistent. + PDO::ATTR_STRINGIFY_FETCHES => true, + ]; + + // MySQL/MariaDB support encrypted connections + if ($driver === self::MYSQL && $key !== '' && $certificate !== '' && $ca !== '') { + $options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $verify_certificate; + $options[PDO::MYSQL_ATTR_SSL_KEY] = Webtrees::ROOT_DIR . 'data/' . $key; + $options[PDO::MYSQL_ATTR_SSL_CERT] = Webtrees::ROOT_DIR . 'data/' . $certificate; + $options[PDO::MYSQL_ATTR_SSL_CA] = Webtrees::ROOT_DIR . 'data/' . $ca; + } + + if ($driver === self::SQLITE && $database !== ':memory:') { + $database = Webtrees::ROOT_DIR . 'data/' . $database . '.sqlite'; + } + + $capsule = new self(); + $capsule->addConnection([ + 'driver' => $driver, + 'host' => $host, + 'port' => $port, + 'database' => $database, + 'username' => $username, + 'password' => $password, + 'prefix' => $prefix, + 'prefix_indexes' => true, + 'options' => $options, + ]); + $capsule->setAsGlobal(); + + // Eager-load the connection, to prevent database credentials appearing in error logs. + try { + self::pdo(); + } catch (PDOException $exception) { + throw new RuntimeException($exception->getMessage()); + } + + $sql = self::DRIVER_INITIALIZATION[$driver]; + + if ($sql !== '') { + self::exec($sql); + } + } + public static function driverName(): string { - return parent::connection()->getPdo()->getAttribute(PDO::ATTR_DRIVER_NAME); + return self::pdo()->getAttribute(PDO::ATTR_DRIVER_NAME); + } + + public static function exec(string $sql): int|false + { + return self::pdo()->exec($sql); + } + + public static function lastInsertId(): int + { + $return = self::pdo()->lastInsertId(); + + if ($return === false) { + throw new RuntimeException('Unable to retrieve last insert ID'); + } + + // All IDs are integers in our schema. + return (int) $return; + } + + private static function pdo(): PDO + { + return parent::connection()->getPdo(); } public static function prefix(string $identifier = ''): string @@ -39,16 +167,21 @@ class DB extends Manager return parent::connection()->getTablePrefix() . $identifier; } + public static function rollBack(): void + { + parent::connection()->rollBack(); + } + /** * @internal */ - public static function caseInsensitiveLikeOperator(): string + public static function iLike(): string { - if (self::driverName() === 'pgsql') { + if (self::driverName() === self::POSTGRES) { return 'ILIKE'; } - if (self::driverName() === 'sqlsrv') { + if (self::driverName() === self::SQL_SERVER) { return 'COLLATE SQL_UTF8_General_CI_AI LIKE'; } @@ -61,27 +194,35 @@ class DB extends Manager public static function groupConcat(string $column): string { switch (self::driverName()) { - case 'pgsql': - case 'sqlsrv': + case self::POSTGRES: + case self::SQL_SERVER: return 'STRING_AGG(' . $column . ", ',')"; - case 'mysql': - case 'sqlite': + case self::MYSQL: + case self::SQLITE: default: return 'GROUP_CONCAT(' . $column . ')'; } } - public static function lastInsertId(): int + public static function binaryColumn(string $column, string|null $alias = null): Expression { - $return = parent::connection()->getPdo()->lastInsertId(); + if (self::driverName() === self::MYSQL) { + $sql = 'CAST(' . $column . ' AS binary)'; + } else { + $sql = $column; + } - if ($return === false) { - throw new RuntimeException('Unable to retrieve last insert ID'); + if ($alias !== null) { + $sql .= ' AS ' . $alias; } - // All IDs are integers in our schema. - return (int) $return; + return new Expression($sql); + } + + public static function regexOperator(): string + { + return self::REGEX_OPERATOR[self::driverName()]; } /** diff --git a/app/Http/Middleware/UseDatabase.php b/app/Http/Middleware/UseDatabase.php index e6a9346bc3..2ac38262ff 100644 --- a/app/Http/Middleware/UseDatabase.php +++ b/app/Http/Middleware/UseDatabase.php @@ -43,81 +43,19 @@ class UseDatabase implements MiddlewareInterface */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - // Earlier versions of webtrees did not have a dbtype config option. They always used mysql. - $driver = Validator::attributes($request)->string('dbtype', 'mysql'); - - $dbname = Validator::attributes($request)->string('dbname'); - - if ($driver === 'sqlite') { - $dbname = Webtrees::ROOT_DIR . 'data/' . $dbname . '.sqlite'; - } - - $capsule = new DB(); - - // Newer versions of webtrees support utf8mb4. Older ones only support 3-byte utf8 - if ($driver === 'mysql' && Validator::attributes($request)->boolean('mysql_utf8mb4', false)) { - $charset = 'utf8mb4'; - $collation = 'utf8mb4_unicode_ci'; - } else { - $charset = 'utf8'; - $collation = 'utf8_unicode_ci'; - } - - $options = [ - // Some drivers do this and some don't. Make them consistent. - PDO::ATTR_STRINGIFY_FETCHES => true, - ]; - - $dbkey = Validator::attributes($request)->string('dbkey', ''); - $dbcert = Validator::attributes($request)->string('dbcert', ''); - $dbca = Validator::attributes($request)->string('dbca', ''); - $dbverify = Validator::attributes($request)->boolean('dbverify', false); - - // MySQL/MariaDB support encrypted connections - if ($dbkey !== '' && $dbcert !== '' && $dbca !== '') { - $options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $dbverify; - $options[PDO::MYSQL_ATTR_SSL_KEY] = Webtrees::ROOT_DIR . 'data/' . $dbkey; - $options[PDO::MYSQL_ATTR_SSL_CERT] = Webtrees::ROOT_DIR . 'data/' . $dbcert; - $options[PDO::MYSQL_ATTR_SSL_CA] = Webtrees::ROOT_DIR . 'data/' . $dbca; - } - - $capsule->addConnection([ - 'driver' => $driver, - 'host' => Validator::attributes($request)->string('dbhost'), - 'port' => Validator::attributes($request)->string('dbport'), - 'database' => $dbname, - 'username' => Validator::attributes($request)->string('dbuser'), - 'password' => Validator::attributes($request)->string('dbpass'), - 'prefix' => Validator::attributes($request)->string('tblpfx'), - 'prefix_indexes' => true, - 'options' => $options, - // For MySQL - 'charset' => $charset, - 'collation' => $collation, - 'timezone' => '+00:00', - 'engine' => 'InnoDB', - 'modes' => [ - 'ANSI', - 'STRICT_ALL_TABLES', - // Use SQL injection(!) to override MAX_JOIN_SIZE and GROUP_CONCAT_MAX_LEN settings. - "', SQL_BIG_SELECTS=1, GROUP_CONCAT_MAX_LEN=1048576, @foobar='" - ], - // For SQLite - 'foreign_key_constraints' => true, - ]); - - $capsule->setAsGlobal(); - - if ($driver === 'sqlsrv') { - DB::connection()->unprepared('SET language us_english'); // For timestamp columns - } - - try { - // Eager-load the connection, to prevent database credentials appearing in error logs. - DB::connection()->getPdo(); - } catch (PDOException $exception) { - //throw new RuntimeException($exception->getMessage()); - } + DB::connect( + driver: Validator::attributes($request)->string('dbtype', DB::MYSQL), + host: Validator::attributes($request)->string('dbhost'), + port: Validator::attributes($request)->string('dbport'), + database: Validator::attributes($request)->string('dbname'), + username: Validator::attributes($request)->string('dbuser'), + password: Validator::attributes($request)->string('dbpass'), + prefix: Validator::attributes($request)->string('tblpfx'), + key: Validator::attributes($request)->string('dbkey', ''), + certificate: Validator::attributes($request)->string('dbcert', ''), + ca: Validator::attributes($request)->string('dbca', ''), + verify_certificate: Validator::attributes($request)->boolean('dbverify', false), + ); return $handler->handle($request); } diff --git a/app/Http/RequestHandlers/CleanDataFolder.php b/app/Http/RequestHandlers/CleanDataFolder.php index f7c9c756ce..a99d9e44be 100644 --- a/app/Http/RequestHandlers/CleanDataFolder.php +++ b/app/Http/RequestHandlers/CleanDataFolder.php @@ -19,6 +19,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; +use Fisharebest\Webtrees\DB; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Registry; @@ -68,7 +69,7 @@ class CleanDataFolder implements RequestHandlerInterface 'config.ini.php', ]; - if (Validator::attributes($request)->string('dbtype', 'mysql') === 'sqlite') { + if (Validator::attributes($request)->string('dbtype', DB::MYSQL) === DB::SQLITE) { $protected[] = Validator::attributes($request)->string('dbname') . '.sqlite'; } diff --git a/app/Http/RequestHandlers/GedcomLoad.php b/app/Http/RequestHandlers/GedcomLoad.php index 37bd74b542..9a338f18c9 100644 --- a/app/Http/RequestHandlers/GedcomLoad.php +++ b/app/Http/RequestHandlers/GedcomLoad.php @@ -213,7 +213,7 @@ class GedcomLoad implements RequestHandlerInterface 'tree' => $tree, ]); } catch (Exception $ex) { - DB::connection()->rollBack(); + DB::rollBack(); // Deadlock? Try again. if ($this->causedByConcurrencyError($ex)) { diff --git a/app/Http/RequestHandlers/MergeTreesAction.php b/app/Http/RequestHandlers/MergeTreesAction.php index b5eb578eac..205cc77ff2 100644 --- a/app/Http/RequestHandlers/MergeTreesAction.php +++ b/app/Http/RequestHandlers/MergeTreesAction.php @@ -69,7 +69,7 @@ class MergeTreesAction implements RequestHandlerInterface $tree2 = $this->tree_service->all()->get($tree2_name); if ($tree1 instanceof Tree && $tree2 instanceof Tree && $tree1 !== $tree2 && $this->admin_service->countCommonXrefs($tree1, $tree2) === 0) { - (new Builder(DB::connection()))->from('individuals')->insertUsing([ + DB::query()->from('individuals')->insertUsing([ 'i_file', 'i_id', 'i_rin', @@ -86,7 +86,7 @@ class MergeTreesAction implements RequestHandlerInterface ->where('i_file', '=', $tree1->id()); }); - (new Builder(DB::connection()))->from('families')->insertUsing([ + DB::query()->from('families')->insertUsing([ 'f_file', 'f_id', 'f_husb', @@ -105,7 +105,7 @@ class MergeTreesAction implements RequestHandlerInterface ->where('f_file', '=', $tree1->id()); }); - (new Builder(DB::connection()))->from('sources')->insertUsing([ + DB::query()->from('sources')->insertUsing([ 's_file', 's_id', 's_name', @@ -120,7 +120,7 @@ class MergeTreesAction implements RequestHandlerInterface ->where('s_file', '=', $tree1->id()); }); - (new Builder(DB::connection()))->from('media')->insertUsing([ + DB::query()->from('media')->insertUsing([ 'm_file', 'm_id', 'm_gedcom', @@ -133,7 +133,7 @@ class MergeTreesAction implements RequestHandlerInterface ->where('m_file', '=', $tree1->id()); }); - (new Builder(DB::connection()))->from('media_file')->insertUsing([ + DB::query()->from('media_file')->insertUsing([ 'm_file', 'm_id', 'multimedia_file_refn', @@ -152,7 +152,7 @@ class MergeTreesAction implements RequestHandlerInterface ->where('m_file', '=', $tree1->id()); }); - (new Builder(DB::connection()))->from('other')->insertUsing([ + DB::query()->from('other')->insertUsing([ 'o_file', 'o_id', 'o_type', @@ -168,7 +168,7 @@ class MergeTreesAction implements RequestHandlerInterface ->where('o_file', '=', $tree1->id()); }); - (new Builder(DB::connection()))->from('name')->insertUsing([ + DB::query()->from('name')->insertUsing([ 'n_file', 'n_id', 'n_num', @@ -201,7 +201,7 @@ class MergeTreesAction implements RequestHandlerInterface ->where('n_file', '=', $tree1->id()); }); - (new Builder(DB::connection()))->from('dates')->insertUsing([ + DB::query()->from('dates')->insertUsing([ 'd_file', 'd_gid', 'd_day', @@ -228,7 +228,7 @@ class MergeTreesAction implements RequestHandlerInterface ->where('d_file', '=', $tree1->id()); }); - (new Builder(DB::connection()))->from('link')->insertUsing([ + DB::query()->from('link')->insertUsing([ 'l_file', 'l_from', 'l_type', diff --git a/app/Http/RequestHandlers/SetupWizard.php b/app/Http/RequestHandlers/SetupWizard.php index b90237b6f8..415d5e7eaa 100644 --- a/app/Http/RequestHandlers/SetupWizard.php +++ b/app/Http/RequestHandlers/SetupWizard.php @@ -38,6 +38,7 @@ use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Session; use Fisharebest\Webtrees\Validator; use Fisharebest\Webtrees\Webtrees; +use Illuminate\Support\Collection; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; @@ -62,7 +63,7 @@ class SetupWizard implements RequestHandlerInterface { use ViewResponseTrait; - private const DEFAULT_DBTYPE = 'mysql'; + private const DEFAULT_DBTYPE = DB::MYSQL; private const DEFAULT_PREFIX = 'wt_'; private const DEFAULT_DATA = [ 'baseurl' => '', @@ -81,10 +82,10 @@ class SetupWizard implements RequestHandlerInterface ]; private const DEFAULT_PORTS = [ - 'mysql' => '3306', - 'pgsql' => '5432', - 'sqlite' => '', - 'sqlsrv' => '', // Do not use default, as it is valid to have no port number. + DB::MYSQL => '3306', + DB::POSTGRES => '5432', + DB::SQLITE => '', + DB::SQL_SERVER => '', // Do not use default, as it is valid to have no port number. ]; private MigrationService $migration_service; @@ -432,58 +433,42 @@ class SetupWizard implements RequestHandlerInterface */ private function connectToDatabase(array $data): void { - $capsule = new DB(); - // Try to create the database, if it does not already exist. switch ($data['dbtype']) { - case 'sqlite': - $data['dbname'] = Webtrees::ROOT_DIR . 'data/' . $data['dbname'] . '.sqlite'; - touch($data['dbname']); + case DB::SQLITE: + touch(Webtrees::ROOT_DIR . 'data/' . $data['dbname'] . '.sqlite'); break; - case 'mysql': - $capsule->addConnection([ - 'driver' => $data['dbtype'], - 'host' => $data['dbhost'], - 'port' => $data['dbport'], - 'database' => '', - 'username' => $data['dbuser'], - 'password' => $data['dbpass'], - ], 'temp'); - $capsule->getConnection('temp')->statement('CREATE DATABASE IF NOT EXISTS `' . $data['dbname'] . '` COLLATE utf8_unicode_ci'); + case DB::MYSQL: + DB::connect( + driver: $data['dbtype'], + host: $data['dbhost'], + port: $data['dbport'], + database: '', + username: $data['dbuser'], + password: $data['dbpass'], + prefix: $data['tblpfx'], + key: $data['dbkey'], + certificate: $data['dbcert'], + ca: $data['dbca'], + verify_certificate: (bool) $data['dbverify'], + ); + DB::exec('CREATE DATABASE IF NOT EXISTS `' . $data['dbname'] . '` COLLATE utf8mb4_unicode_ci'); break; } - // Connect to the database. - $capsule->addConnection([ - 'driver' => $data['dbtype'], - 'host' => $data['dbhost'], - 'port' => $data['dbport'], - 'database' => $data['dbname'], - 'username' => $data['dbuser'], - 'password' => $data['dbpass'], - 'prefix' => $data['tblpfx'], - 'prefix_indexes' => true, - // For MySQL - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'timezone' => '+00:00', - 'engine' => 'InnoDB', - 'modes' => [ - 'ANSI', - 'STRICT_TRANS_TABLES', - 'NO_ZERO_IN_DATE', - 'NO_ZERO_DATE', - 'ERROR_FOR_DIVISION_BY_ZERO', - ], - // For SQLite - 'foreign_key_constraints' => true, - ]); - - $capsule->setAsGlobal(); - - if ($data['dbtype'] === 'sqlsrv') { - DB::connection()->unprepared('SET language us_english'); // For timestamp columns - } + DB::connect( + driver: $data['dbtype'], + host: $data['dbhost'], + port: $data['dbport'], + database: $data['dbname'], + username: $data['dbuser'], + password: $data['dbpass'], + prefix: $data['tblpfx'], + key: $data['dbkey'], + certificate: $data['dbcert'], + ca: $data['dbca'], + verify_certificate: (bool) $data['dbverify'], + ); } } diff --git a/app/Http/RequestHandlers/TreePage.php b/app/Http/RequestHandlers/TreePage.php index 5be21750a2..b75a88fbe7 100644 --- a/app/Http/RequestHandlers/TreePage.php +++ b/app/Http/RequestHandlers/TreePage.php @@ -67,7 +67,7 @@ class TreePage implements RequestHandlerInterface $this->home_page_service->checkDefaultTreeBlocksExist(); // Copy the defaults - (new Builder(DB::connection()))->from('block')->insertUsing( + DB::query()->from('block')->insertUsing( ['gedcom_id', 'location', 'block_order', 'module_name'], static function (Builder $query) use ($tree): void { $query diff --git a/app/Http/RequestHandlers/UserPage.php b/app/Http/RequestHandlers/UserPage.php index 6b25ac645f..7564eda710 100644 --- a/app/Http/RequestHandlers/UserPage.php +++ b/app/Http/RequestHandlers/UserPage.php @@ -66,7 +66,7 @@ class UserPage implements RequestHandlerInterface $this->home_page_service->checkDefaultUserBlocksExist(); // Copy the defaults - (new Builder(DB::connection()))->from('block')->insertUsing( + DB::query()->from('block')->insertUsing( ['user_id', 'location', 'block_order', 'module_name'], static function (Builder $query) use ($user): void { $query diff --git a/app/Module/FamilyTreeStatisticsModule.php b/app/Module/FamilyTreeStatisticsModule.php index b46e96b566..a0baf090ce 100644 --- a/app/Module/FamilyTreeStatisticsModule.php +++ b/app/Module/FamilyTreeStatisticsModule.php @@ -123,13 +123,13 @@ class FamilyTreeStatisticsModule extends AbstractModule implements ModuleBlockIn ->where('n_surn', '<>', '') ->where('n_surn', '<>', Individual::NOMEN_NESCIO) ->select([ - $this->binaryColumn('n_surn', 'n_surn'), - $this->binaryColumn('n_surname', 'n_surname'), + DB::binaryColumn('n_surn', 'n_surn'), + DB::binaryColumn('n_surname', 'n_surname'), new Expression('COUNT(*) AS total'), ]) ->groupBy([ - $this->binaryColumn('n_surn'), - $this->binaryColumn('n_surname'), + DB::binaryColumn('n_surn'), + DB::binaryColumn('n_surname'), ]); /** @var array<array<int>> $top_surnames */ @@ -337,23 +337,4 @@ class FamilyTreeStatisticsModule extends AbstractModule implements ModuleBlockIn 'stat_avg_chil' => $stat_avg_chil, ]); } - - /** - * This module assumes the database will use binary collation on the name columns. - * Until we convert MySQL databases to use utf8_bin, we need to do this at run-time. - */ - private function binaryColumn(string $column, string|null $alias = null): Expression - { - if (DB::driverName() === 'mysql') { - $sql = 'CAST(' . $column . ' AS binary)'; - } else { - $sql = $column; - } - - if ($alias !== null) { - $sql .= ' AS ' . $alias; - } - - return new Expression($sql); - } } diff --git a/app/Module/FixSearchAndReplace.php b/app/Module/FixSearchAndReplace.php index 0cfa80e0ca..72caf7bd6f 100644 --- a/app/Module/FixSearchAndReplace.php +++ b/app/Module/FixSearchAndReplace.php @@ -437,20 +437,7 @@ class FixSearchAndReplace extends AbstractModule implements ModuleDataFixInterfa // of MySQL (e.g. 5.7), and harmless on others (e.g. 8.0). $search = strtr($search, ['\n' => "\n"]); - switch (DB::driverName()) { - case 'sqlite': - case 'mysql': - $query->where($column, 'REGEXP', $search); - break; - - case 'pgsql': - $query->where($column, '~', $search); - break; - - case 'sqlsrv': - // Not available - break; - } + $query->where($column, DB::regexOperator(), $search); break; } } diff --git a/app/Module/IndividualListModule.php b/app/Module/IndividualListModule.php index 841ffba78a..a32c25058a 100644 --- a/app/Module/IndividualListModule.php +++ b/app/Module/IndividualListModule.php @@ -600,8 +600,8 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface } $query - ->select([$this->binaryColumn('n_givn', 'n_givn'), new Expression('COUNT(*) AS count')]) - ->groupBy([$this->binaryColumn('n_givn')]); + ->select([DB::binaryColumn('n_givn', 'n_givn'), new Expression('COUNT(*) AS count')]) + ->groupBy([DB::binaryColumn('n_givn')]); foreach ($query->get() as $row) { $initial = I18N::strtoupper(I18N::language()->initialLetter($row->n_givn)); @@ -633,8 +633,8 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface ->whereNotNull('n_surn') // Filters old records for sources, repositories, etc. ->whereNotNull('n_surname') ->select([ - $this->binaryColumn('n_surn', 'n_surn'), - $this->binaryColumn('n_surname', 'n_surname'), + DB::binaryColumn('n_surn', 'n_surn'), + DB::binaryColumn('n_surname', 'n_surname'), new Expression('COUNT(*) AS total'), ]); @@ -642,8 +642,8 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface $this->whereMarriedName($marnm, $query); $query->groupBy([ - $this->binaryColumn('n_surn'), - $this->binaryColumn('n_surname'), + DB::binaryColumn('n_surn'), + DB::binaryColumn('n_surname'), ]); return $query @@ -771,7 +771,7 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface if ($surns_to_show === []) { $query->whereNotIn('n_surn', ['', '@N.N.']); } else { - $query->whereIn($this->binaryColumn('n_surn'), $surns_to_show); + $query->whereIn(DB::binaryColumn('n_surn'), $surns_to_show); } $individuals = new Collection(); @@ -822,23 +822,4 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface return $families->unique(); } - - /** - * This module assumes the database will use binary collation on the name columns. - * Until we convert MySQL databases to use utf8_bin, we need to do this at run-time. - */ - private function binaryColumn(string $column, string|null $alias = null): Expression - { - if (DB::driverName() === 'mysql') { - $sql = 'CAST(' . $column . ' AS binary)'; - } else { - $sql = $column; - } - - if ($alias !== null) { - $sql .= ' AS ' . $alias; - } - - return new Expression($sql); - } } diff --git a/app/Module/TopSurnamesModule.php b/app/Module/TopSurnamesModule.php index 884c8d0bcc..cae6e04dcc 100644 --- a/app/Module/TopSurnamesModule.php +++ b/app/Module/TopSurnamesModule.php @@ -106,13 +106,13 @@ class TopSurnamesModule extends AbstractModule implements ModuleBlockInterface ->where('n_surn', '<>', '') ->where('n_surn', '<>', Individual::NOMEN_NESCIO) ->select([ - $this->binaryColumn('n_surn', 'n_surn'), - $this->binaryColumn('n_surname', 'n_surname'), + DB::binaryColumn('n_surn', 'n_surn'), + DB::binaryColumn('n_surname', 'n_surname'), new Expression('COUNT(*) AS total'), ]) ->groupBy([ - $this->binaryColumn('n_surn'), - $this->binaryColumn('n_surname'), + DB::binaryColumn('n_surn'), + DB::binaryColumn('n_surname'), ]); /** @var array<array<int>> $top_surnames */ @@ -283,23 +283,4 @@ class TopSurnamesModule extends AbstractModule implements ModuleBlockInterface 'info_styles' => $info_styles, ]); } - - /** - * This module assumes the database will use binary collation on the name columns. - * Until we convert MySQL databases to use utf8_bin, we need to do this at run-time. - */ - private function binaryColumn(string $column, string|null $alias = null): Expression - { - if (DB::driverName() === 'mysql') { - $sql = 'CAST(' . $column . ' AS binary)'; - } else { - $sql = $column; - } - - if ($alias !== null) { - $sql .= ' AS ' . $alias; - } - - return new Expression($sql); - } } diff --git a/app/Schema/Migration0.php b/app/Schema/Migration0.php index 3fa217d4a0..e536dff521 100644 --- a/app/Schema/Migration0.php +++ b/app/Schema/Migration0.php @@ -27,11 +27,6 @@ use Illuminate\Database\Schema\Blueprint; */ class Migration0 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { DB::schema()->create('gedcom', static function (Blueprint $table): void { diff --git a/app/Schema/Migration1.php b/app/Schema/Migration1.php index 0995ec9479..9f2d9ca685 100644 --- a/app/Schema/Migration1.php +++ b/app/Schema/Migration1.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration1 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration10.php b/app/Schema/Migration10.php index 8e6cc0ee11..795861daab 100644 --- a/app/Schema/Migration10.php +++ b/app/Schema/Migration10.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration10 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration11.php b/app/Schema/Migration11.php index 95f2e206f9..f504f8c91d 100644 --- a/app/Schema/Migration11.php +++ b/app/Schema/Migration11.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration11 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration12.php b/app/Schema/Migration12.php index d580f030d3..d6ed117e63 100644 --- a/app/Schema/Migration12.php +++ b/app/Schema/Migration12.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration12 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration13.php b/app/Schema/Migration13.php index 98977e1ad7..1c35303782 100644 --- a/app/Schema/Migration13.php +++ b/app/Schema/Migration13.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration13 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration14.php b/app/Schema/Migration14.php index 6542b36cf3..bf36c52af3 100644 --- a/app/Schema/Migration14.php +++ b/app/Schema/Migration14.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration14 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration15.php b/app/Schema/Migration15.php index 690c0b61c4..6c7898bae2 100644 --- a/app/Schema/Migration15.php +++ b/app/Schema/Migration15.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration15 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration16.php b/app/Schema/Migration16.php index 41cf77cd0b..8a1715c9a6 100644 --- a/app/Schema/Migration16.php +++ b/app/Schema/Migration16.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration16 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration17.php b/app/Schema/Migration17.php index b081b028b2..94ccd4d13f 100644 --- a/app/Schema/Migration17.php +++ b/app/Schema/Migration17.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration17 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // Originally, this created wt_site_access_rule, diff --git a/app/Schema/Migration18.php b/app/Schema/Migration18.php index 4ffea6cdac..997bd62d8e 100644 --- a/app/Schema/Migration18.php +++ b/app/Schema/Migration18.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration18 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration19.php b/app/Schema/Migration19.php index d2b337c747..bd20026992 100644 --- a/app/Schema/Migration19.php +++ b/app/Schema/Migration19.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration19 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration2.php b/app/Schema/Migration2.php index b95b6f9bff..b58a298f26 100644 --- a/app/Schema/Migration2.php +++ b/app/Schema/Migration2.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration2 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration20.php b/app/Schema/Migration20.php index b5e8bfd543..8b36117fdf 100644 --- a/app/Schema/Migration20.php +++ b/app/Schema/Migration20.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration20 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration21.php b/app/Schema/Migration21.php index 6af3c46e1b..33f642f93c 100644 --- a/app/Schema/Migration21.php +++ b/app/Schema/Migration21.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration21 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration22.php b/app/Schema/Migration22.php index 2634b39159..00d668c232 100644 --- a/app/Schema/Migration22.php +++ b/app/Schema/Migration22.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration22 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration23.php b/app/Schema/Migration23.php index 0869f9ed63..e40443c4a2 100644 --- a/app/Schema/Migration23.php +++ b/app/Schema/Migration23.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration23 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration24.php b/app/Schema/Migration24.php index 21a86455fd..5e5a292680 100644 --- a/app/Schema/Migration24.php +++ b/app/Schema/Migration24.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration24 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration25.php b/app/Schema/Migration25.php index 3e7630f035..7775c6a41f 100644 --- a/app/Schema/Migration25.php +++ b/app/Schema/Migration25.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration25 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration26.php b/app/Schema/Migration26.php index c5c0a5d169..9cc3c3bfc8 100644 --- a/app/Schema/Migration26.php +++ b/app/Schema/Migration26.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration26 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration27.php b/app/Schema/Migration27.php index 7c16df694d..4e9b96fd25 100644 --- a/app/Schema/Migration27.php +++ b/app/Schema/Migration27.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration27 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration28.php b/app/Schema/Migration28.php index 8554936736..f22c326b92 100644 --- a/app/Schema/Migration28.php +++ b/app/Schema/Migration28.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration28 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration29.php b/app/Schema/Migration29.php index 18be3710f4..ac425fcd15 100644 --- a/app/Schema/Migration29.php +++ b/app/Schema/Migration29.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration29 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration3.php b/app/Schema/Migration3.php index 0f754ab6f6..e157766eae 100644 --- a/app/Schema/Migration3.php +++ b/app/Schema/Migration3.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration3 implements MigrationInterface { - /** - * Upgrade to the next version. - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration30.php b/app/Schema/Migration30.php index 60cdc52aac..d2dc07bb4c 100644 --- a/app/Schema/Migration30.php +++ b/app/Schema/Migration30.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration30 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration31.php b/app/Schema/Migration31.php index 0b5354cc90..0abd968b5c 100644 --- a/app/Schema/Migration31.php +++ b/app/Schema/Migration31.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration31 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration32.php b/app/Schema/Migration32.php index 95c3ee8750..58ecd01d5d 100644 --- a/app/Schema/Migration32.php +++ b/app/Schema/Migration32.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration32 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration33.php b/app/Schema/Migration33.php index 0edf091075..56fdd4222f 100644 --- a/app/Schema/Migration33.php +++ b/app/Schema/Migration33.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration33 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration34.php b/app/Schema/Migration34.php index dc26ff6be7..23d458e885 100644 --- a/app/Schema/Migration34.php +++ b/app/Schema/Migration34.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration34 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration35.php b/app/Schema/Migration35.php index 8539285bb6..4be8b4ea67 100644 --- a/app/Schema/Migration35.php +++ b/app/Schema/Migration35.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration35 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration36.php b/app/Schema/Migration36.php index d514f1cca6..73e29b5a5c 100644 --- a/app/Schema/Migration36.php +++ b/app/Schema/Migration36.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration36 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration37.php b/app/Schema/Migration37.php index 1a1aa138ff..fc9de44023 100644 --- a/app/Schema/Migration37.php +++ b/app/Schema/Migration37.php @@ -29,11 +29,6 @@ use Illuminate\Database\Schema\Blueprint; */ class Migration37 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These tables were created by webtrees 1.x, and may not exist if we first installed webtrees 2.x @@ -71,7 +66,7 @@ class Migration37 implements MigrationInterface 'descriptive_title', ], function (Builder $query): void { // SQLite also supports SUBSTRING() from 3.34.0 (2020-12-01) - $substring_function = DB::driverName() === 'sqlite' ? 'SUBSTR' : 'SUBSTRING'; + $substring_function = DB::driverName() === DB::SQLITE ? 'SUBSTR' : 'SUBSTRING'; $query->select([ 'm_id', diff --git a/app/Schema/Migration38.php b/app/Schema/Migration38.php index 3d2d1dd09f..3bcc8f4d13 100644 --- a/app/Schema/Migration38.php +++ b/app/Schema/Migration38.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration38 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // This module previously created the table placelocation - which is now deleted in migration 44. diff --git a/app/Schema/Migration39.php b/app/Schema/Migration39.php index b5f90c29a4..26db6f9c34 100644 --- a/app/Schema/Migration39.php +++ b/app/Schema/Migration39.php @@ -27,11 +27,6 @@ use Illuminate\Database\Schema\Blueprint; */ class Migration39 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // This table was previously created by the favorites module in 1.7.9. diff --git a/app/Schema/Migration4.php b/app/Schema/Migration4.php index d67b1dc099..4cb0310f51 100644 --- a/app/Schema/Migration4.php +++ b/app/Schema/Migration4.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration4 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration40.php b/app/Schema/Migration40.php index fc50710702..0057515d9b 100644 --- a/app/Schema/Migration40.php +++ b/app/Schema/Migration40.php @@ -27,11 +27,6 @@ use Illuminate\Database\Schema\Blueprint; */ class Migration40 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // This table was previously created by the news module in 1.7.9. diff --git a/app/Schema/Migration41.php b/app/Schema/Migration41.php index 78c05326bb..47bbcd4540 100644 --- a/app/Schema/Migration41.php +++ b/app/Schema/Migration41.php @@ -27,11 +27,6 @@ use Illuminate\Database\Schema\Blueprint; */ class Migration41 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { DB::schema()->table('module', static function (Blueprint $table): void { diff --git a/app/Schema/Migration42.php b/app/Schema/Migration42.php index 3b3e5e5bf2..00acbaee6e 100644 --- a/app/Schema/Migration42.php +++ b/app/Schema/Migration42.php @@ -46,11 +46,6 @@ class Migration42 implements MigrationInterface 'theme' => ModuleThemeInterface::class, ]; - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // doctrine/dbal cannot modify tables containing ENUM fields diff --git a/app/Schema/Migration43.php b/app/Schema/Migration43.php index 53258bd225..8eee1f8a88 100644 --- a/app/Schema/Migration43.php +++ b/app/Schema/Migration43.php @@ -26,11 +26,6 @@ use Fisharebest\Webtrees\DB; */ class Migration43 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // Language was previously a tree-setting. diff --git a/app/Schema/Migration44.php b/app/Schema/Migration44.php index 1fd1efcf00..0fd681afc4 100644 --- a/app/Schema/Migration44.php +++ b/app/Schema/Migration44.php @@ -29,11 +29,6 @@ use PDOException; */ class Migration44 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // It is simpler to create a new table than to update the existing one. @@ -55,7 +50,7 @@ class Migration44 implements MigrationInterface // SQL-server cannot cascade-delete/update on self-relations. // Users will need to delete all child locations before deleting the parent. - if (DB::driverName() === 'sqlsrv') { + if (DB::driverName() === DB::SQL_SERVER) { // SQL-Server doesn't support 'RESTRICT' $action = 'NO ACTION'; } else { @@ -74,7 +69,7 @@ class Migration44 implements MigrationInterface // This table should only exist if we are upgrading an old installation, which would have been // created with MySQL. Therefore we can safely use MySQL-specific SQL. if (DB::schema()->hasTable('placelocation')) { - if (DB::driverName() === 'mysql') { + if (DB::driverName() === DB::MYSQL) { DB::table('placelocation') ->where('pl_lati', '=', '') ->orWhere('pl_long', '=', '') diff --git a/app/Schema/Migration5.php b/app/Schema/Migration5.php index 98acd2adfc..e01cbb081b 100644 --- a/app/Schema/Migration5.php +++ b/app/Schema/Migration5.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration5 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration6.php b/app/Schema/Migration6.php index 8f2a0f1e49..02776c5aa4 100644 --- a/app/Schema/Migration6.php +++ b/app/Schema/Migration6.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration6 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration7.php b/app/Schema/Migration7.php index 7cf50fb14b..25e9fbf88e 100644 --- a/app/Schema/Migration7.php +++ b/app/Schema/Migration7.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration7 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration8.php b/app/Schema/Migration8.php index 6f5edd348e..1bcf20eeaa 100644 --- a/app/Schema/Migration8.php +++ b/app/Schema/Migration8.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration8 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/Migration9.php b/app/Schema/Migration9.php index 8919a6c461..8028ff9411 100644 --- a/app/Schema/Migration9.php +++ b/app/Schema/Migration9.php @@ -24,11 +24,6 @@ namespace Fisharebest\Webtrees\Schema; */ class Migration9 implements MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void { // These migrations have been merged into migration 0. diff --git a/app/Schema/MigrationInterface.php b/app/Schema/MigrationInterface.php index 88bdb0f098..9472758f2a 100644 --- a/app/Schema/MigrationInterface.php +++ b/app/Schema/MigrationInterface.php @@ -24,10 +24,5 @@ namespace Fisharebest\Webtrees\Schema; */ interface MigrationInterface { - /** - * Upgrade to the next version - * - * @return void - */ public function upgrade(): void; } diff --git a/app/Schema/SeedGedcomTable.php b/app/Schema/SeedGedcomTable.php index 61e0d1bf02..3448fa0ce1 100644 --- a/app/Schema/SeedGedcomTable.php +++ b/app/Schema/SeedGedcomTable.php @@ -35,8 +35,8 @@ class SeedGedcomTable implements SeedInterface { // Add a "default" tree, to store default settings - if (DB::driverName() === 'sqlsrv') { - DB::connection()->unprepared('SET IDENTITY_INSERT [' . DB::prefix() . 'gedcom] ON'); + if (DB::driverName() === DB::SQL_SERVER) { + DB::exec('SET IDENTITY_INSERT [' . DB::prefix() . 'gedcom] ON'); } DB::table('gedcom')->updateOrInsert([ @@ -45,8 +45,8 @@ class SeedGedcomTable implements SeedInterface 'gedcom_name' => 'DEFAULT_TREE', ]); - if (DB::driverName() === 'sqlsrv') { - DB::connection()->unprepared('SET IDENTITY_INSERT [' . DB::prefix() . 'gedcom] OFF'); + if (DB::driverName() === DB::SQL_SERVER) { + DB::exec('SET IDENTITY_INSERT [' . DB::prefix() . 'gedcom] OFF'); } } } diff --git a/app/Schema/SeedUserTable.php b/app/Schema/SeedUserTable.php index 903742b875..17b147237d 100644 --- a/app/Schema/SeedUserTable.php +++ b/app/Schema/SeedUserTable.php @@ -35,8 +35,8 @@ class SeedUserTable implements SeedInterface { // Add a "default" user, to store default settings - if (DB::driverName() === 'sqlsrv') { - DB::connection()->unprepared('SET IDENTITY_INSERT [' . DB::prefix() . 'user] ON'); + if (DB::driverName() === DB::SQL_SERVER) { + DB::exec('SET IDENTITY_INSERT [' . DB::prefix() . 'user] ON'); } DB::table('user')->updateOrInsert([ @@ -48,8 +48,8 @@ class SeedUserTable implements SeedInterface 'password' => 'DEFAULT_USER', ]); - if (DB::driverName() === 'sqlsrv') { - DB::connection()->unprepared('SET IDENTITY_INSERT [' . DB::prefix() . 'user] OFF'); + if (DB::driverName() === DB::SQL_SERVER) { + DB::exec('SET IDENTITY_INSERT [' . DB::prefix() . 'user] OFF'); } } } diff --git a/app/Services/MigrationService.php b/app/Services/MigrationService.php index 9ada98df5d..0479d40ceb 100644 --- a/app/Services/MigrationService.php +++ b/app/Services/MigrationService.php @@ -51,14 +51,6 @@ class MigrationService $current_version = 0; } - if ($current_version < $target_version) { - try { - $this->transactionalTables(); - } catch (PDOException) { - // There is probably nothing we can do. - } - } - $updates_applied = false; // Update the schema, one version at a time. @@ -76,38 +68,6 @@ class MigrationService } /** - * Upgrades from older installations may have MyISAM or other non-transactional tables. - * These could prevent us from creating foreign key constraints. - * - * @return void - * @throws PDOException - */ - private function transactionalTables(): void - { - $connection = DB::connection(); - - if (DB::driverName() !== 'mysql') { - return; - } - - $sql = "SELECT table_name FROM information_schema.tables JOIN information_schema.engines USING (engine) WHERE table_schema = ? AND LEFT(table_name, ?) = ? AND transactions <> 'YES'"; - - $bindings = [ - $connection->getDatabaseName(), - mb_strlen(DB::prefix()), - DB::prefix(), - ]; - - $rows = DB::connection()->select($sql, $bindings); - - foreach ($rows as $row) { - $table = $row->TABLE_NAME ?? $row->table_name; - $alter_sql = 'ALTER TABLE `' . $table . '` ENGINE=InnoDB'; - DB::connection()->statement($alter_sql); - } - } - - /** * Write default data to the database. * * @return void diff --git a/app/Services/SearchService.php b/app/Services/SearchService.php index 13e0602d68..0feb5c5894 100644 --- a/app/Services/SearchService.php +++ b/app/Services/SearchService.php @@ -489,7 +489,7 @@ class SearchService // Filter each level of the hierarchy. foreach (explode(',', $search, 9) as $level => $string) { - $query->where('p' . $level . '.p_place', DB::caseInsensitiveLikeOperator(), '%' . addcslashes($string, '\\%_') . '%'); + $query->where('p' . $level . '.p_place', DB::iLike(), '%' . addcslashes($string, '\\%_') . '%'); } $row_mapper = static function (object $row) use ($tree): Place { @@ -665,10 +665,10 @@ class SearchService $query->where('individual_name.n_givn', '=', $field_value); break; case 'BEGINS': - $query->where('individual_name.n_givn', DB::caseInsensitiveLikeOperator(), $field_value . '%'); + $query->where('individual_name.n_givn', DB::iLike(), $field_value . '%'); break; case 'CONTAINS': - $query->where('individual_name.n_givn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + $query->where('individual_name.n_givn', DB::iLike(), '%' . $field_value . '%'); break; case 'SDX_STD': $sdx = Soundex::russell($field_value); @@ -676,7 +676,7 @@ class SearchService $this->wherePhonetic($query, 'individual_name.n_soundex_givn_std', $sdx); } else { // No phonetic content? Use a substring match - $query->where('individual_name.n_givn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + $query->where('individual_name.n_givn', DB::iLike(), '%' . $field_value . '%'); } break; case 'SDX': // SDX uses DM by default. @@ -686,7 +686,7 @@ class SearchService $this->wherePhonetic($query, 'individual_name.n_soundex_givn_dm', $sdx); } else { // No phonetic content? Use a substring match - $query->where('individual_name.n_givn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + $query->where('individual_name.n_givn', DB::iLike(), '%' . $field_value . '%'); } break; } @@ -704,15 +704,15 @@ class SearchService case 'BEGINS': $query->where(function (Builder $query) use ($field_value): void { $query - ->where('individual_name.n_surn', DB::caseInsensitiveLikeOperator(), $field_value . '%') - ->orWhere('individual_name.n_surname', DB::caseInsensitiveLikeOperator(), $field_value . '%'); + ->where('individual_name.n_surn', DB::iLike(), $field_value . '%') + ->orWhere('individual_name.n_surname', DB::iLike(), $field_value . '%'); }); break; case 'CONTAINS': $query->where(function (Builder $query) use ($field_value): void { $query - ->where('individual_name.n_surn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%') - ->orWhere('individual_name.n_surname', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + ->where('individual_name.n_surn', DB::iLike(), '%' . $field_value . '%') + ->orWhere('individual_name.n_surname', DB::iLike(), '%' . $field_value . '%'); }); break; case 'SDX_STD': @@ -723,8 +723,8 @@ class SearchService // No phonetic content? Use a substring match $query->where(function (Builder $query) use ($field_value): void { $query - ->where('individual_name.n_surn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%') - ->orWhere('individual_name.n_surname', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + ->where('individual_name.n_surn', DB::iLike(), '%' . $field_value . '%') + ->orWhere('individual_name.n_surname', DB::iLike(), '%' . $field_value . '%'); }); } break; @@ -737,8 +737,8 @@ class SearchService // No phonetic content? Use a substring match $query->where(function (Builder $query) use ($field_value): void { $query - ->where('individual_name.n_surn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%') - ->orWhere('individual_name.n_surname', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + ->where('individual_name.n_surn', DB::iLike(), '%' . $field_value . '%') + ->orWhere('individual_name.n_surname', DB::iLike(), '%' . $field_value . '%'); }); } break; @@ -750,7 +750,7 @@ class SearchService case 'INDI:NAME:_HEB': case 'INDI:NAME:_AKA': $like = "%\n1 NAME%\n2 " . $parts[2] . ' %' . preg_quote($field_value, '/') . '%'; - $query->where('individuals.i_gedcom', DB::caseInsensitiveLikeOperator(), $like); + $query->where('individuals.i_gedcom', DB::iLike(), $like); break; } } elseif (str_starts_with($field_name, 'INDI:') && str_ends_with($field_name, ':DATE')) { @@ -788,10 +788,10 @@ class SearchService $query->where($table . '.n_givn', '=', $field_value); break; case 'BEGINS': - $query->where($table . '.n_givn', DB::caseInsensitiveLikeOperator(), $field_value . '%'); + $query->where($table . '.n_givn', DB::iLike(), $field_value . '%'); break; case 'CONTAINS': - $query->where($table . '.n_givn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + $query->where($table . '.n_givn', DB::iLike(), '%' . $field_value . '%'); break; case 'SDX_STD': $sdx = Soundex::russell($field_value); @@ -799,7 +799,7 @@ class SearchService $this->wherePhonetic($query, $table . '.n_soundex_givn_std', $sdx); } else { // No phonetic content? Use a substring match - $query->where($table . '.n_givn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + $query->where($table . '.n_givn', DB::iLike(), '%' . $field_value . '%'); } break; case 'SDX': // SDX uses DM by default. @@ -809,7 +809,7 @@ class SearchService $this->wherePhonetic($query, $table . '.n_soundex_givn_dm', $sdx); } else { // No phonetic content? Use a substring match - $query->where($table . '.n_givn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + $query->where($table . '.n_givn', DB::iLike(), '%' . $field_value . '%'); } break; } @@ -820,10 +820,10 @@ class SearchService $query->where($table . '.n_surn', '=', $field_value); break; case 'BEGINS': - $query->where($table . '.n_surn', DB::caseInsensitiveLikeOperator(), $field_value . '%'); + $query->where($table . '.n_surn', DB::iLike(), $field_value . '%'); break; case 'CONTAINS': - $query->where($table . '.n_surn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + $query->where($table . '.n_surn', DB::iLike(), '%' . $field_value . '%'); break; case 'SDX_STD': $sdx = Soundex::russell($field_value); @@ -831,7 +831,7 @@ class SearchService $this->wherePhonetic($query, $table . '.n_soundex_surn_std', $sdx); } else { // No phonetic content? Use a substring match - $query->where($table . '.n_surn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + $query->where($table . '.n_surn', DB::iLike(), '%' . $field_value . '%'); } break; case 'SDX': // SDX uses DM by default. @@ -841,7 +841,7 @@ class SearchService $this->wherePhonetic($query, $table . '.n_soundex_surn_dm', $sdx); } else { // No phonetic content? Use a substring match - $query->where($table . '.n_surn', DB::caseInsensitiveLikeOperator(), '%' . $field_value . '%'); + $query->where($table . '.n_surn', DB::iLike(), '%' . $field_value . '%'); } break; } @@ -851,14 +851,14 @@ class SearchService } elseif (str_starts_with($field_name, 'FAM:')) { // e.g. searches for occupation, religion, note, etc. // Initial matching only. Need PHP to apply filter. - $query->where('spouse_families.f_gedcom', DB::caseInsensitiveLikeOperator(), "%\n1 " . $parts[1] . ' %' . $field_value . '%'); + $query->where('spouse_families.f_gedcom', DB::iLike(), "%\n1 " . $parts[1] . ' %' . $field_value . '%'); } elseif (str_starts_with($field_name, 'INDI:') && str_ends_with($field_name, ':TYPE')) { // Initial matching only. Need PHP to apply filter. - $query->where('individuals.i_gedcom', DB::caseInsensitiveLikeOperator(), "%\n1 " . $parts[1] . "%\n2 TYPE %" . $field_value . '%'); + $query->where('individuals.i_gedcom', DB::iLike(), "%\n1 " . $parts[1] . "%\n2 TYPE %" . $field_value . '%'); } elseif (str_starts_with($field_name, 'INDI:')) { // e.g. searches for occupation, religion, note, etc. // Initial matching only. Need PHP to apply filter. - $query->where('individuals.i_gedcom', DB::caseInsensitiveLikeOperator(), "%\n1 " . $parts[1] . '%' . $parts[2] . '%' . $field_value . '%'); + $query->where('individuals.i_gedcom', DB::iLike(), "%\n1 " . $parts[1] . '%' . $parts[2] . '%' . $field_value . '%'); } } @@ -1072,7 +1072,7 @@ class SearchService private function whereSearch(Builder $query, Expression|string $column, array $search_terms): void { foreach ($search_terms as $search_term) { - $query->where($column, DB::caseInsensitiveLikeOperator(), '%' . addcslashes($search_term, '\\%_') . '%'); + $query->where($column, DB::iLike(), '%' . addcslashes($search_term, '\\%_') . '%'); } } @@ -1088,7 +1088,7 @@ class SearchService if ($soundex !== '') { $query->where(function (Builder $query) use ($soundex, $field): void { foreach (explode(':', $soundex) as $sdx) { - $query->orWhere($field, DB::caseInsensitiveLikeOperator(), '%' . $sdx . '%'); + $query->orWhere($field, DB::iLike(), '%' . $sdx . '%'); } }); } diff --git a/app/Services/ServerCheckService.php b/app/Services/ServerCheckService.php index 672177f66f..fbe94cfe40 100644 --- a/app/Services/ServerCheckService.php +++ b/app/Services/ServerCheckService.php @@ -19,6 +19,7 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Services; +use Fisharebest\Webtrees\DB; use Fisharebest\Webtrees\I18N; use Illuminate\Support\Collection; use SQLite3; @@ -276,13 +277,13 @@ class ServerCheckService private function databaseDriverErrors(string $driver): Collection { switch ($driver) { - case 'mysql': + case DB::MYSQL: return Collection::make([ $this->checkPhpExtension('pdo'), $this->checkPhpExtension('pdo_mysql'), ]); - case 'sqlite': + case DB::SQLITE: return Collection::make([ $this->checkPhpExtension('pdo'), $this->checkPhpExtension('sqlite3'), @@ -290,13 +291,13 @@ class ServerCheckService $this->checkSqliteVersion(), ]); - case 'pgsql': + case DB::POSTGRES: return Collection::make([ $this->checkPhpExtension('pdo'), $this->checkPhpExtension('pdo_pgsql'), ]); - case 'sqlsrv': + case DB::SQL_SERVER: return Collection::make([ $this->checkPhpExtension('pdo'), $this->checkPhpExtension('pdo_odbc'), @@ -315,17 +316,17 @@ class ServerCheckService private function databaseDriverWarnings(string $driver): Collection { switch ($driver) { - case 'sqlite': + case DB::SQLITE: return new Collection([ I18N::translate('SQLite is only suitable for small sites, testing and evaluation.'), ]); - case 'pgsql': + case DB::POSTGRES: return new Collection([ I18N::translate('Support for PostgreSQL is experimental.'), ]); - case 'sqlsrv': + case DB::SQL_SERVER: return new Collection([ I18N::translate('Support for SQL Server is experimental.'), ]); diff --git a/app/Services/TreeService.php b/app/Services/TreeService.php index a7fea57fdf..ca1252cad0 100644 --- a/app/Services/TreeService.php +++ b/app/Services/TreeService.php @@ -185,7 +185,7 @@ class TreeService $tree->setPreference('title', $title); // Set preferences from default tree - (new Builder(DB::connection()))->from('gedcom_setting')->insertUsing( + DB::query()->from('gedcom_setting')->insertUsing( ['gedcom_id', 'setting_name', 'setting_value'], static function (Builder $query) use ($tree_id): void { $query @@ -195,7 +195,7 @@ class TreeService } ); - (new Builder(DB::connection()))->from('default_resn')->insertUsing( + DB::query()->from('default_resn')->insertUsing( ['gedcom_id', 'tag_type', 'resn'], static function (Builder $query) use ($tree_id): void { $query diff --git a/phpstan-baseline.php b/phpstan-baseline.php index be269502a8..04d1ca9af4 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -19,6 +19,21 @@ $ignoreErrors[] = [ 'path' => __DIR__ . '/app/Container.php', ]; $ignoreErrors[] = [ + 'message' => '#^Constant Fisharebest\\\\Webtrees\\\\DB\\:\\:COLLATION_ASCII is unused\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/app/DB.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Constant Fisharebest\\\\Webtrees\\\\DB\\:\\:COLLATION_UTF8 is unused\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/app/DB.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Method Fisharebest\\\\Webtrees\\\\DB\\:\\:driverName\\(\\) should return string but returns mixed\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/app/DB.php', +]; +$ignoreErrors[] = [ 'message' => '#^Method Fisharebest\\\\Webtrees\\\\Elements\\\\AgeAtEvent\\:\\:value\\(\\) should return string but returns string\\|null\\.$#', 'count' => 1, 'path' => __DIR__ . '/app/Elements/AgeAtEvent.php', @@ -874,6 +889,56 @@ $ignoreErrors[] = [ 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', ]; $ignoreErrors[] = [ + 'message' => '#^Parameter \\$ca of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\$certificate of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\$database of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\$driver of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\$host of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\$key of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\$password of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\$port of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\$prefix of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Parameter \\$username of static method Fisharebest\\\\Webtrees\\\\DB\\:\\:connect\\(\\) expects string, mixed given\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/app/Http/RequestHandlers/SetupWizard.php', +]; +$ignoreErrors[] = [ 'message' => '#^Cannot call method setTimezone\\(\\) on DateTimeImmutable\\|false\\.$#', 'count' => 1, 'path' => __DIR__ . '/app/Http/RequestHandlers/SiteLogsData.php', diff --git a/resources/views/setup/step-3-database-type.phtml b/resources/views/setup/step-3-database-type.phtml index f8ccb3d28d..73148dc6ad 100644 --- a/resources/views/setup/step-3-database-type.phtml +++ b/resources/views/setup/step-3-database-type.phtml @@ -2,6 +2,7 @@ declare(strict_types=1); +use Fisharebest\Webtrees\DB; use Fisharebest\Webtrees\I18N; use Illuminate\Support\Collection; @@ -55,28 +56,28 @@ use Illuminate\Support\Collection; </label> <div class="col-sm-9"> <div class="form-check"> - <input class="form-check-input" type="radio" name="dbtype" id="dbtype-mysql" value="mysql" <?= $dbtype === 'mysql' ? 'checked' : '' ?>> + <input class="form-check-input" type="radio" name="dbtype" id="dbtype-mysql" value="mysql" <?= $dbtype === DB::MYSQL ? 'checked' : '' ?>> <label class="form-check-label" for="dbtype-mysql"> MySQL </label> </div> <div class="form-check"> - <input class="form-check-input" type="radio" name="dbtype" id="dbtype-sqlite" value="sqlite" <?= $dbtype === 'sqlite' ? 'checked' : '' ?>> + <input class="form-check-input" type="radio" name="dbtype" id="dbtype-sqlite" value="sqlite" <?= $dbtype === DB::SQLITE ? 'checked' : '' ?>> <label class="form-check-label" for="dbtype-sqlite"> SQLite </label> </div> <div class="form-check"> - <input class="form-check-input" type="radio" name="dbtype" id="dbtype-pgsql" value="pgsql" <?= $dbtype === 'pgsql' ? 'checked' : '' ?>> + <input class="form-check-input" type="radio" name="dbtype" id="dbtype-pgsql" value="pgsql" <?= $dbtype === DB::POSTGRES ? 'checked' : '' ?>> <label class="form-check-label" for="dbtype-pgsql"> PostgreSQL </label> </div> <div class="form-check"> - <input class="form-check-input" type="radio" name="dbtype" id="dbtype-sqlsrv" value="sqlsrv" <?= $dbtype === 'sqlsrv' ? 'checked' : '' ?>> + <input class="form-check-input" type="radio" name="dbtype" id="dbtype-sqlsrv" value="sqlsrv" <?= $dbtype === DB::SQL_SERVER ? 'checked' : '' ?>> <label class="form-check-label" for="dbtype-sqlsrv"> SQL Server </label> diff --git a/tests/TestCase.php b/tests/TestCase.php index d19f313262..ba4c025b5f 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -65,12 +65,19 @@ class TestCase extends \PHPUnit\Framework\TestCase */ private static function createTestDatabase(): void { - $capsule = new DB(); - $capsule->addConnection([ - 'driver' => 'sqlite', - 'database' => ':memory:', - ]); - $capsule->setAsGlobal(); + DB::connect( + driver: DB::SQLITE, + host: '', + port: '', + database: ':memory:', + username: '', + password: '', + prefix: 'wt_', + key: '', + certificate: '', + ca: '', + verify_certificate: false, + ); // Create tables $migration_service = new MigrationService(); diff --git a/tests/app/Module/FixDuplicateLinksTest.php b/tests/app/Module/FixDuplicateLinksTest.php index 5c42e6e22c..9f17f798b9 100644 --- a/tests/app/Module/FixDuplicateLinksTest.php +++ b/tests/app/Module/FixDuplicateLinksTest.php @@ -23,6 +23,7 @@ use Fisharebest\Webtrees\Auth; use Fisharebest\Webtrees\Services\DataFixService; use Fisharebest\Webtrees\Services\GedcomImportService; use Fisharebest\Webtrees\Services\TreeService; +use Fisharebest\Webtrees\Services\UserService; use Fisharebest\Webtrees\Session; use Fisharebest\Webtrees\TestCase; use Fisharebest\Webtrees\Tree; @@ -53,10 +54,9 @@ class FixDuplicateLinksTest extends TestCase $this->fixDuplicateLinks = new FixDuplicateLinks(new DataFixService()); - if (Auth::id() === null) { - Session::put('wt_user', 0); - $this->restore_session_user = true; - } + $user_service = new UserService(); + $user = $user_service->create('user', 'real', 'email', 'pass'); + Auth::login($user); } /** |
