10c1c7615SGreg Roach<?php 23976b470SGreg Roach 30c1c7615SGreg Roach/** 40c1c7615SGreg Roach * webtrees: online genealogy 55bfc6897SGreg Roach * Copyright (C) 2022 webtrees development team 60c1c7615SGreg Roach * This program is free software: you can redistribute it and/or modify 70c1c7615SGreg Roach * it under the terms of the GNU General Public License as published by 80c1c7615SGreg Roach * the Free Software Foundation, either version 3 of the License, or 90c1c7615SGreg Roach * (at your option) any later version. 100c1c7615SGreg Roach * This program is distributed in the hope that it will be useful, 110c1c7615SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 120c1c7615SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 130c1c7615SGreg Roach * GNU General Public License for more details. 140c1c7615SGreg Roach * You should have received a copy of the GNU General Public License 1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 160c1c7615SGreg Roach */ 17fcfa147eSGreg Roach 180c1c7615SGreg Roachdeclare(strict_types=1); 190c1c7615SGreg Roach 200c1c7615SGreg Roachnamespace Fisharebest\Webtrees\Services; 210c1c7615SGreg Roach 220c1c7615SGreg Roachuse Fisharebest\Webtrees\Schema\MigrationInterface; 230c1c7615SGreg Roachuse Fisharebest\Webtrees\Schema\SeedDefaultResnTable; 240c1c7615SGreg Roachuse Fisharebest\Webtrees\Schema\SeedGedcomTable; 250c1c7615SGreg Roachuse Fisharebest\Webtrees\Schema\SeedUserTable; 260c1c7615SGreg Roachuse Fisharebest\Webtrees\Site; 27415cca73SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 280c1c7615SGreg Roachuse PDOException; 290c1c7615SGreg Roach 300c1c7615SGreg Roach/** 310c1c7615SGreg Roach * Update the database schema. 320c1c7615SGreg Roach */ 330c1c7615SGreg Roachclass MigrationService 340c1c7615SGreg Roach{ 350c1c7615SGreg Roach /** 360c1c7615SGreg Roach * Run a series of scripts to bring the database schema up to date. 370c1c7615SGreg Roach * 380c1c7615SGreg Roach * @param string $namespace Where to find our MigrationXXX classes 390c1c7615SGreg Roach * @param string $schema_name Which schema to update. 40415cca73SGreg Roach * @param int $target_version Upgrade to this version 410c1c7615SGreg Roach * 420c1c7615SGreg Roach * @return bool Were any updates applied 4324f2a3afSGreg Roach * @throws PDOException 440c1c7615SGreg Roach */ 4524f2a3afSGreg Roach public function updateSchema(string $namespace, string $schema_name, int $target_version): bool 460c1c7615SGreg Roach { 470c1c7615SGreg Roach try { 480c1c7615SGreg Roach $current_version = (int) Site::getPreference($schema_name); 49*28d026adSGreg Roach } catch (PDOException) { 500c1c7615SGreg Roach // During initial installation, the site_preference table won’t exist. 510c1c7615SGreg Roach $current_version = 0; 520c1c7615SGreg Roach } 530c1c7615SGreg Roach 542289e30bSGreg Roach if ($current_version < $target_version) { 552289e30bSGreg Roach try { 562289e30bSGreg Roach $this->transactionalTables(); 57*28d026adSGreg Roach } catch (PDOException) { 582289e30bSGreg Roach // There is probably nothing we can do. 592289e30bSGreg Roach } 602289e30bSGreg Roach } 612289e30bSGreg Roach 620c1c7615SGreg Roach $updates_applied = false; 630c1c7615SGreg Roach 640c1c7615SGreg Roach // Update the schema, one version at a time. 650c1c7615SGreg Roach while ($current_version < $target_version) { 660c1c7615SGreg Roach $class = $namespace . '\\Migration' . $current_version; 670c1c7615SGreg Roach /** @var MigrationInterface $migration */ 680c1c7615SGreg Roach $migration = new $class(); 690c1c7615SGreg Roach $migration->upgrade(); 700c1c7615SGreg Roach $current_version++; 710c1c7615SGreg Roach Site::setPreference($schema_name, (string) $current_version); 720c1c7615SGreg Roach $updates_applied = true; 730c1c7615SGreg Roach } 740c1c7615SGreg Roach 750c1c7615SGreg Roach return $updates_applied; 760c1c7615SGreg Roach } 770c1c7615SGreg Roach 780c1c7615SGreg Roach /** 79415cca73SGreg Roach * Upgrades from older installations may have MyISAM or other non-transactional tables. 80415cca73SGreg Roach * These could prevent us from creating foreign key constraints. 81415cca73SGreg Roach * 82415cca73SGreg Roach * @return void 83415cca73SGreg Roach * @throws PDOException 84415cca73SGreg Roach */ 85415cca73SGreg Roach private function transactionalTables(): void 86415cca73SGreg Roach { 87415cca73SGreg Roach $connection = DB::connection(); 88415cca73SGreg Roach 89415cca73SGreg Roach if ($connection->getDriverName() !== 'mysql') { 90415cca73SGreg Roach return; 91415cca73SGreg Roach } 92415cca73SGreg Roach 93415cca73SGreg Roach $sql = "SELECT table_name FROM information_schema.tables JOIN information_schema.engines USING (engine) WHERE table_schema = ? AND LEFT(table_name, ?) = ? AND transactions <> 'YES'"; 94415cca73SGreg Roach 95415cca73SGreg Roach $bindings = [ 96415cca73SGreg Roach $connection->getDatabaseName(), 97415cca73SGreg Roach mb_strlen($connection->getTablePrefix()), 98415cca73SGreg Roach $connection->getTablePrefix(), 99415cca73SGreg Roach ]; 100415cca73SGreg Roach 101415cca73SGreg Roach $rows = DB::connection()->select($sql, $bindings); 102415cca73SGreg Roach 103415cca73SGreg Roach foreach ($rows as $row) { 104415cca73SGreg Roach $table = $row->TABLE_NAME ?? $row->table_name; 105415cca73SGreg Roach $alter_sql = 'ALTER TABLE `' . $table . '` ENGINE=InnoDB'; 106415cca73SGreg Roach DB::connection()->statement($alter_sql); 107415cca73SGreg Roach } 108415cca73SGreg Roach } 109415cca73SGreg Roach 110415cca73SGreg Roach /** 1110c1c7615SGreg Roach * Write default data to the database. 1120c1c7615SGreg Roach * 1130c1c7615SGreg Roach * @return void 1140c1c7615SGreg Roach */ 1150c1c7615SGreg Roach public function seedDatabase(): void 1160c1c7615SGreg Roach { 1170c1c7615SGreg Roach (new SeedUserTable())->run(); 1180c1c7615SGreg Roach (new SeedGedcomTable())->run(); 1190c1c7615SGreg Roach (new SeedDefaultResnTable())->run(); 1200c1c7615SGreg Roach } 1210c1c7615SGreg Roach} 122