Lines
61.56%
173 / 281
Methods
60.00%
18 / 30
Classes
0.00%
0 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| getVersion | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| getDependencies | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| getDescription | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| up | 70.89% | 95 / 134 | 0.00% | 0 / 1 | 24.12 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] __construct | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] isReversible | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] down | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] table | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] isDbType | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] isMySql | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] isPostgreSql | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] isSqlite | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] isSqlServer | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] addColumn | 62.50% | 5 / 8 | 0.00% | 0 / 1 | 4.84 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] dropColumn | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] dropColumns | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] createIndex | 33.33% | 5 / 15 | 0.00% | 0 / 1 | 8.74 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] createUniqueIndex | 28.57% | 6 / 21 | 0.00% | 0 / 1 | 6.28 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] indexExists | 40.62% | 13 / 32 | 0.00% | 0 / 1 | 10.23 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] dropTable | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] dropTableIfExists | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] updateLanguageCode | 100.00% | 11 / 11 | 100.00% | 1 / 1 | 1 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] integerType | 66.66% | 2 / 3 | 0.00% | 0 / 1 | 3.33 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] textType | 66.66% | 2 / 3 | 0.00% | 0 / 1 | 3.33 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] varcharType | 0.00% | 0 / 3 | 0.00% | 0 / 1 | 12 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] timestampType | 40.00% | 4 / 10 | 0.00% | 0 / 1 | 21.82 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] booleanType | 0.00% | 0 / 4 | 0.00% | 0 / 1 | 20 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] autoIncrementColumn | 0.00% | 0 / 6 | 0.00% | 0 / 1 | 42 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] getConfig | 0.00% | 0 / 1 | 0.00% | 0 / 1 | 2 | ||
| [phpMyFAQ\Setup\Migration\AbstractMigration] getChecksum | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 1 | ||
| 26 | readonly class Migration400Alpha extends AbstractMigration | |
| 27 | { | |
| 28 | public function getVersion(): string | |
| 29 | { | |
| 30 | return '4.0.0-alpha'; | |
| 31 | } | |
| 32 | ||
| 33 | public function getDependencies(): array | |
| 34 | { | |
| 35 | return ['3.2.3']; | |
| 36 | } | |
| 37 | ||
| 38 | public function getDescription(): string | |
| 39 | { | |
| 40 | return 'New file layout, bookmarks, sticky order, online update config, remove social networks'; | |
| 41 | } | |
| 42 | ||
| 43 | public function up(OperationRecorder $recorder): void | |
| 44 | { | |
| 45 | // Copy database configuration | |
| 46 | if (defined('PMF_LEGACY_CONFIG_DIR') && defined('PMF_CONFIG_DIR')) { | |
| 47 | $legacyConfigDir = (string) PMF_LEGACY_CONFIG_DIR; | |
| 48 | $configDir = (string) PMF_CONFIG_DIR; | |
| 49 | $recorder->copyFile($legacyConfigDir . '/database.php', $configDir . '/database.php'); | |
| 50 | ||
| 51 | // Copy Azure configuration, if available | |
| 52 | $recorder->copyFile($legacyConfigDir . '/azure.php', $configDir . '/azure.php', true); | |
| 53 | ||
| 54 | // Copy Elasticsearch configuration, if available | |
| 55 | $recorder->copyFile($legacyConfigDir . '/elasticsearch.php', $configDir . '/elasticsearch.php', true); | |
| 56 | ||
| 57 | // Copy LDAP configuration, if available | |
| 58 | $recorder->copyFile($legacyConfigDir . '/ldap.php', $configDir . '/ldap.php', true); | |
| 59 | } | |
| 60 | ||
| 61 | if (defined('PMF_ROOT_DIR')) { | |
| 62 | $rootDir = (string) PMF_ROOT_DIR; | |
| 63 | ||
| 64 | // Copy data directory | |
| 65 | $recorder->copyDirectory($rootDir . '/data', $rootDir . '/content/core'); | |
| 66 | ||
| 67 | // Copy logs directory | |
| 68 | $recorder->copyDirectory($rootDir . '/logs', $rootDir . '/content/core'); | |
| 69 | ||
| 70 | // Copy attachments directory | |
| 71 | $recorder->copyDirectory($rootDir . '/attachments', $rootDir . '/content/user'); | |
| 72 | ||
| 73 | // Copy images directory | |
| 74 | $recorder->copyDirectory($rootDir . '/images', $rootDir . '/content/user'); | |
| 75 | } | |
| 76 | ||
| 77 | // Online Update configuration | |
| 78 | $recorder->addConfig('upgrade.onlineUpdateEnabled', true); | |
| 79 | $recorder->addConfig('upgrade.releaseEnvironment', ReleaseType::DEVELOPMENT->value); | |
| 80 | $recorder->addConfig('upgrade.dateLastChecked', ''); | |
| 81 | $recorder->addConfig('upgrade.lastDownloadedPackage', ''); | |
| 82 | ||
| 83 | // Rewrite rules are now mandatory, social network support removed | |
| 84 | $recorder->deleteConfig('main.enableRewriteRules'); | |
| 85 | $recorder->deleteConfig('socialnetworks.enableTwitterSupport'); | |
| 86 | $recorder->deleteConfig('socialnetworks.twitterConsumerKey'); | |
| 87 | $recorder->deleteConfig('socialnetworks.twitterConsumerSecret'); | |
| 88 | $recorder->deleteConfig('socialnetworks.twitterAccessTokenKey'); | |
| 89 | $recorder->deleteConfig('socialnetworks.twitterAccessTokenSecret'); | |
| 90 | $recorder->deleteConfig('socialnetworks.disableAll'); | |
| 91 | $recorder->deleteConfig('mail.remoteSMTPEncryption'); | |
| 92 | ||
| 93 | // Bookmarks support | |
| 94 | // "CREATE TABLE IF NOT EXISTS" keeps a re-run alive after a previously failed | |
| 95 | // update - SQL Server has no support for it | |
| 96 | if ($this->isMySql()) { | |
| 97 | $recorder->addSql( | |
| 98 | sprintf( | |
| 99 | 'CREATE TABLE IF NOT EXISTS %sfaqbookmarks (userid int(11) DEFAULT NULL, faqid int(11) DEFAULT NULL)', | |
| 100 | $this->tablePrefix, | |
| 101 | ), | |
| 102 | 'Create bookmarks table (MySQL)', | |
| 103 | ); | |
| 104 | } | |
| 105 | ||
| 106 | if (!$this->isMySql() && !$this->isSqlServer()) { | |
| 107 | $recorder->addSql( | |
| 108 | sprintf( | |
| 109 | 'CREATE TABLE IF NOT EXISTS %sfaqbookmarks (userid INTEGER DEFAULT NULL, faqid INTEGER DEFAULT NULL)', | |
| 110 | $this->tablePrefix, | |
| 111 | ), | |
| 112 | 'Create bookmarks table', | |
| 113 | ); | |
| 114 | } | |
| 115 | ||
| 116 | if ($this->isSqlServer()) { | |
| 117 | $recorder->addSql( | |
| 118 | sprintf( | |
| 119 | 'CREATE TABLE %sfaqbookmarks (userid INTEGER DEFAULT NULL, faqid INTEGER DEFAULT NULL)', | |
| 120 | $this->tablePrefix, | |
| 121 | ), | |
| 122 | 'Create bookmarks table', | |
| 123 | ); | |
| 124 | } | |
| 125 | ||
| 126 | // Custom order of sticky records | |
| 127 | if ($this->isMySql()) { | |
| 128 | $recorder->addSql( | |
| 129 | sprintf('ALTER TABLE %sfaqdata ADD COLUMN sticky_order int(10) DEFAULT NULL', $this->tablePrefix), | |
| 130 | 'Add sticky_order column to faqdata (MySQL)', | |
| 131 | ); | |
| 132 | ||
| 133 | $recorder->addSql( | |
| 134 | sprintf( | |
| 135 | 'ALTER TABLE %sfaqdata_revisions ADD COLUMN sticky_order int(10) DEFAULT NULL', | |
| 136 | $this->tablePrefix, | |
| 137 | ), | |
| 138 | 'Add sticky_order column to faqdata_revisions (MySQL)', | |
| 139 | ); | |
| 140 | } | |
| 141 | ||
| 142 | if ($this->isPostgreSql()) { | |
| 143 | // "IF NOT EXISTS" keeps a re-run alive after a previously failed update | |
| 144 | $recorder->addSql( | |
| 145 | sprintf( | |
| 146 | 'ALTER TABLE %sfaqdata ADD COLUMN IF NOT EXISTS sticky_order integer DEFAULT NULL', | |
| 147 | $this->tablePrefix, | |
| 148 | ), | |
| 149 | 'Add sticky_order column to faqdata', | |
| 150 | ); | |
| 151 | ||
| 152 | $recorder->addSql( | |
| 153 | sprintf( | |
| 154 | 'ALTER TABLE %sfaqdata_revisions ADD COLUMN IF NOT EXISTS sticky_order integer DEFAULT NULL', | |
| 155 | $this->tablePrefix, | |
| 156 | ), | |
| 157 | 'Add sticky_order column to faqdata_revisions', | |
| 158 | ); | |
| 159 | } | |
| 160 | ||
| 161 | if (!$this->isMySql() && !$this->isPostgreSql()) { | |
| 162 | $recorder->addSql( | |
| 163 | sprintf('ALTER TABLE %sfaqdata ADD COLUMN sticky_order integer DEFAULT NULL', $this->tablePrefix), | |
| 164 | 'Add sticky_order column to faqdata', | |
| 165 | ); | |
| 166 | ||
| 167 | $recorder->addSql( | |
| 168 | sprintf( | |
| 169 | 'ALTER TABLE %sfaqdata_revisions ADD COLUMN sticky_order integer DEFAULT NULL', | |
| 170 | $this->tablePrefix, | |
| 171 | ), | |
| 172 | 'Add sticky_order column to faqdata_revisions', | |
| 173 | ); | |
| 174 | } | |
| 175 | ||
| 176 | $recorder->addConfig('records.orderStickyFaqsCustom', 'false'); | |
| 177 | ||
| 178 | // Remove template metadata tables ("IF EXISTS" keeps a re-run alive after | |
| 179 | // a previously failed update - supported by all databases, SQL Server since 2016) | |
| 180 | $recorder->addSql($this->dropTableIfExists('faqmeta'), 'Drop faqmeta table'); | |
| 181 | ||
| 182 | // Blocked statistics browsers | |
| 183 | $recorder->addConfig('main.botIgnoreList', 'nustcrape,webpost,GoogleBot,msnbot,crawler,scooter, | |
| 184 | bravobrian,archiver,w3c,controler,wget,bot,spider,Yahoo! Slurp,htdig,gsa-crawler,AirControler,Uptime-Kuma'); | |
| 185 | ||
| 186 | // Enable/Disable cookie consent | |
| 187 | $recorder->addConfig('main.enableCookieConsent', true); | |
| 188 | ||
| 189 | // Add parent category ID to faqcategory_order | |
| 190 | if ($this->isMySql()) { | |
| 191 | $recorder->addSql( | |
| 192 | sprintf( | |
| 193 | 'ALTER TABLE %sfaqcategory_order ADD COLUMN parent_id int(11) DEFAULT NULL AFTER category_id', | |
| 194 | $this->tablePrefix, | |
| 195 | ), | |
| 196 | 'Add parent_id column to faqcategory_order (MySQL)', | |
| 197 | ); | |
| 198 | } | |
| 199 | ||
| 200 | if (!$this->isMySql() && $this->isSqlServer()) { | |
| 201 | $recorder->addSql( | |
| 202 | sprintf( | |
| 203 | 'ALTER TABLE %sfaqcategory_order ADD COLUMN parent_id INTEGER DEFAULT NULL', | |
| 204 | $this->tablePrefix, | |
| 205 | ), | |
| 206 | 'Add parent_id column to faqcategory_order (SQL Server)', | |
| 207 | ); | |
| 208 | } | |
| 209 | ||
| 210 | if (!$this->isMySql() && !$this->isSqlServer()) { | |
| 211 | // SQLite and PostgreSQL - table rebuild approach | |
| 212 | $recorder->addSql(sprintf( | |
| 213 | 'CREATE TABLE IF NOT EXISTS %sfaqcategory_order_new ( | |
| 214 | category_id INTEGER NOT NULL, | |
| 215 | parent_id INTEGER DEFAULT NULL, | |
| 216 | position INTEGER NOT NULL, | |
| 217 | PRIMARY KEY (category_id))', | |
| 218 | $this->tablePrefix, | |
| 219 | ), 'Create new faqcategory_order table with parent_id'); | |
| 220 | ||
| 221 | // The NOT IN guard keeps a re-run from violating the primary key if | |
| 222 | // a previous update attempt already copied some rows. | |
| 223 | $recorder->addSql( | |
| 224 | sprintf( | |
| 225 | 'INSERT INTO %sfaqcategory_order_new (category_id, parent_id, position) | |
| 226 | SELECT category_id, NULL AS parent_id, position FROM %sfaqcategory_order | |
| 227 | WHERE category_id NOT IN (SELECT category_id FROM %sfaqcategory_order_new)', | |
| 228 | $this->tablePrefix, | |
| 229 | $this->tablePrefix, | |
| 230 | $this->tablePrefix, | |
| 231 | ), | |
| 232 | 'Copy data to new faqcategory_order table', | |
| 233 | ); | |
| 234 | ||
| 235 | $recorder->addSql($this->dropTableIfExists('faqcategory_order'), 'Drop old faqcategory_order table'); | |
| 236 | ||
| 237 | $recorder->addSql( | |
| 238 | sprintf( | |
| 239 | 'ALTER TABLE %sfaqcategory_order_new RENAME TO %sfaqcategory_order', | |
| 240 | $this->tablePrefix, | |
| 241 | $this->tablePrefix, | |
| 242 | ), | |
| 243 | 'Rename new faqcategory_order table', | |
| 244 | ); | |
| 245 | } | |
| 246 | } | |
| 247 | } |
Inherited from phpMyFAQ\Setup\Migration\AbstractMigration
| 32 | public function __construct( | |
| 33 | protected Configuration $configuration, | |
| 34 | ) { | |
| 35 | $this->tablePrefix = Database::getTablePrefix(); | |
| 36 | $this->dbType = Database::getType(); | |
| 37 | } |
| 52 | public function isReversible(): bool | |
| 53 | { | |
| 54 | return false; | |
| 55 | } |
| 60 | public function down(OperationRecorder $recorder): void | |
| 61 | { | |
| 62 | // Override in subclass if migration is reversible | |
| 63 | } |
| 68 | protected function table(string $name): string | |
| 69 | { | |
| 70 | return $this->tablePrefix . $name; | |
| 71 | } |
| 78 | protected function isDbType(string|array $types): bool | |
| 79 | { | |
| 80 | $types = (array) $types; | |
| 81 | return in_array($this->dbType, $types, strict: true); | |
| 82 | } |
| 87 | protected function isMySql(): bool | |
| 88 | { | |
| 89 | return $this->isDbType(['mysqli', 'pdo_mysql']); | |
| 90 | } |
| 95 | protected function isPostgreSql(): bool | |
| 96 | { | |
| 97 | return $this->isDbType(['pgsql', 'pdo_pgsql']); | |
| 98 | } |
| 103 | protected function isSqlite(): bool | |
| 104 | { | |
| 105 | return $this->isDbType(['sqlite3', 'pdo_sqlite']); | |
| 106 | } |
| 111 | protected function isSqlServer(): bool | |
| 112 | { | |
| 113 | return $this->isDbType(['sqlsrv', 'pdo_sqlsrv']); | |
| 114 | } |
| 120 | protected function addColumn(string $table, string $column, string $type, ?string $default = null): string | |
| 121 | { | |
| 122 | $tableName = $this->table($table); | |
| 123 | $defaultClause = ''; | |
| 124 | if ($default !== null) { | |
| 125 | $defaultClause = " DEFAULT {$default}"; | |
| 126 | } | |
| 127 | ||
| 128 | if ($this->isSqlite()) { | |
| 129 | return sprintf('ALTER TABLE %s ADD COLUMN %s %s%s', $tableName, $column, $type, $defaultClause); | |
| 130 | } | |
| 131 | ||
| 132 | // MySQL, PostgreSQL, SQL Server | |
| 133 | $columnKeyword = $this->isSqlServer() ? '' : 'COLUMN '; | |
| 134 | return sprintf('ALTER TABLE %s ADD %s%s %s%s', $tableName, $columnKeyword, $column, $type, $defaultClause); | |
| 135 | } |
| 140 | protected function dropColumn(string $table, string $column): string | |
| 141 | { | |
| 142 | $tableName = $this->table($table); | |
| 143 | return sprintf('ALTER TABLE %s DROP COLUMN %s', $tableName, $column); | |
| 144 | } |
| 153 | protected function dropColumns(string $table, array $columns): array | |
| 154 | { | |
| 155 | $tableName = $this->table($table); | |
| 156 | return array_map(static fn(string $col): string => sprintf( | |
| 157 | 'ALTER TABLE %s DROP COLUMN %s', | |
| 158 | $tableName, | |
| 159 | $col, | |
| 160 | ), $columns); | |
| 161 | } |
| 168 | protected function createIndex(string $table, string $indexName, string|array $columns): string | |
| 169 | { | |
| 170 | $tableName = $this->table($table); | |
| 171 | $columnList = is_array($columns) ? implode(', ', $columns) : $columns; | |
| 172 | ||
| 173 | if ($this->isSqlServer()) { | |
| 174 | return sprintf( | |
| 175 | "IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = '%s' AND object_id = OBJECT_ID('%s')) " | |
| 176 | . 'CREATE INDEX %s ON %s (%s)', | |
| 177 | $indexName, | |
| 178 | $tableName, | |
| 179 | $indexName, | |
| 180 | $tableName, | |
| 181 | $columnList, | |
| 182 | ); | |
| 183 | } | |
| 184 | ||
| 185 | // MySQL/MariaDB don't support IF NOT EXISTS in older versions | |
| 186 | // Use conditional execution or manual check instead | |
| 187 | if ($this->isMySql()) { | |
| 188 | return sprintf('CREATE INDEX %s ON %s (%s)', $indexName, $tableName, $columnList); | |
| 189 | } | |
| 190 | ||
| 191 | // PostgreSQL and SQLite support IF NOT EXISTS | |
| 192 | return sprintf('CREATE INDEX IF NOT EXISTS %s ON %s (%s)', $indexName, $tableName, $columnList); | |
| 193 | } |
| 204 | protected function createUniqueIndex(string $table, string $indexName, string|array $columns): string | |
| 205 | { | |
| 206 | $tableName = $this->table($table); | |
| 207 | $columns = (array) $columns; | |
| 208 | $columnList = implode(', ', $columns); | |
| 209 | ||
| 210 | if ($this->isSqlServer()) { | |
| 211 | $whereClause = implode(' AND ', array_map(static fn(string $col): string => sprintf( | |
| 212 | '%s IS NOT NULL', | |
| 213 | $col, | |
| 214 | ), $columns)); | |
| 215 | return sprintf( | |
| 216 | "IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = '%s' AND object_id = OBJECT_ID('%s')) " | |
| 217 | . 'CREATE UNIQUE INDEX %s ON %s (%s) WHERE %s', | |
| 218 | $indexName, | |
| 219 | $tableName, | |
| 220 | $indexName, | |
| 221 | $tableName, | |
| 222 | $columnList, | |
| 223 | $whereClause, | |
| 224 | ); | |
| 225 | } | |
| 226 | ||
| 227 | if ($this->isMySql()) { | |
| 228 | return sprintf('CREATE UNIQUE INDEX %s ON %s (%s)', $indexName, $tableName, $columnList); | |
| 229 | } | |
| 230 | ||
| 231 | return sprintf('CREATE UNIQUE INDEX IF NOT EXISTS %s ON %s (%s)', $indexName, $tableName, $columnList); | |
| 232 | } |
| 238 | protected function indexExists(string $table, string $indexName): string | |
| 239 | { | |
| 240 | $db = $this->configuration->getDb(); | |
| 241 | $tableName = $this->table($table); | |
| 242 | $escapedTableName = $db->escape($tableName); | |
| 243 | $escapedIndexName = $db->escape($indexName); | |
| 244 | ||
| 245 | if ($this->isMySql()) { | |
| 246 | return sprintf( | |
| 247 | 'SELECT COUNT(*) as idx_count FROM information_schema.STATISTICS ' | |
| 248 | . "WHERE table_schema = DATABASE() AND table_name = '%s' AND index_name = '%s'", | |
| 249 | $escapedTableName, | |
| 250 | $escapedIndexName, | |
| 251 | ); | |
| 252 | } | |
| 253 | ||
| 254 | if ($this->isPostgreSql()) { | |
| 255 | return sprintf( | |
| 256 | 'SELECT COUNT(*) as idx_count FROM pg_indexes ' | |
| 257 | . "WHERE schemaname = 'public' AND tablename = '%s' AND indexname = '%s'", | |
| 258 | $escapedTableName, | |
| 259 | $escapedIndexName, | |
| 260 | ); | |
| 261 | } | |
| 262 | ||
| 263 | if ($this->isSqlite()) { | |
| 264 | return sprintf( | |
| 265 | 'SELECT COUNT(*) as idx_count FROM sqlite_master ' | |
| 266 | . "WHERE type = 'index' AND name = '%s' AND tbl_name = '%s'", | |
| 267 | $escapedIndexName, | |
| 268 | $escapedTableName, | |
| 269 | ); | |
| 270 | } | |
| 271 | ||
| 272 | if ($this->isSqlServer()) { | |
| 273 | return sprintf( | |
| 274 | 'SELECT COUNT(*) as idx_count FROM sys.indexes ' . "WHERE name = '%s' AND object_id = OBJECT_ID('%s')", | |
| 275 | $escapedIndexName, | |
| 276 | $escapedTableName, | |
| 277 | ); | |
| 278 | } | |
| 279 | ||
| 280 | throw new \RuntimeException("Unsupported database type for index existence check: {$this->dbType}"); | |
| 281 | } |
| 286 | protected function dropTable(string $table): string | |
| 287 | { | |
| 288 | return sprintf('DROP TABLE %s', $this->table($table)); | |
| 289 | } |
| 294 | protected function dropTableIfExists(string $table): string | |
| 295 | { | |
| 296 | return sprintf('DROP TABLE IF EXISTS %s', $this->table($table)); | |
| 297 | } |
| 302 | protected function updateLanguageCode(string $table, string $column, string $oldCode, string $newCode): string | |
| 303 | { | |
| 304 | $db = $this->configuration->getDb(); | |
| 305 | $escapedOldCode = $db->escape($oldCode); | |
| 306 | $escapedNewCode = $db->escape($newCode); | |
| 307 | ||
| 308 | return sprintf( | |
| 309 | "UPDATE %s SET %s='%s' WHERE %s='%s'", | |
| 310 | $this->table($table), | |
| 311 | $column, | |
| 312 | $escapedNewCode, | |
| 313 | $column, | |
| 314 | $escapedOldCode, | |
| 315 | ); | |
| 316 | } |
| 321 | protected function integerType(): string | |
| 322 | { | |
| 323 | return match ($this->dbType) { | |
| 324 | 'mysqli', 'pdo_mysql' => 'INT', | |
| 325 | default => 'INTEGER', | |
| 326 | }; | |
| 327 | } |
| 332 | protected function textType(): string | |
| 333 | { | |
| 334 | return match ($this->dbType) { | |
| 335 | 'sqlsrv', 'pdo_sqlsrv' => 'NVARCHAR(MAX)', | |
| 336 | default => 'TEXT', | |
| 337 | }; | |
| 338 | } |
| 343 | protected function varcharType(int $length): string | |
| 344 | { | |
| 345 | return match ($this->dbType) { | |
| 346 | 'sqlsrv', 'pdo_sqlsrv' => "NVARCHAR({$length})", | |
| 347 | default => "VARCHAR({$length})", | |
| 348 | }; | |
| 349 | } |
| 354 | protected function timestampType(bool $withDefault = true): string | |
| 355 | { | |
| 356 | $type = match ($this->dbType) { | |
| 357 | 'mysqli', 'pdo_mysql' => 'TIMESTAMP', | |
| 358 | 'sqlsrv', 'pdo_sqlsrv' => 'DATETIME', | |
| 359 | default => 'TIMESTAMP', | |
| 360 | }; | |
| 361 | ||
| 362 | if (!$withDefault) { | |
| 363 | return $type; | |
| 364 | } | |
| 365 | ||
| 366 | return match ($this->dbType) { | |
| 367 | 'sqlsrv', 'pdo_sqlsrv' => $type . ' NOT NULL DEFAULT GETDATE()', | |
| 368 | 'sqlite3', 'pdo_sqlite' => 'DATETIME DEFAULT CURRENT_TIMESTAMP', | |
| 369 | default => $type . ' NOT NULL DEFAULT CURRENT_TIMESTAMP', | |
| 370 | }; | |
| 371 | } |
| 376 | protected function booleanType(): string | |
| 377 | { | |
| 378 | return match ($this->dbType) { | |
| 379 | 'mysqli', 'pdo_mysql' => 'TINYINT(1)', | |
| 380 | 'sqlsrv', 'pdo_sqlsrv' => 'TINYINT', | |
| 381 | default => 'INTEGER', | |
| 382 | }; | |
| 383 | } |
| 388 | protected function autoIncrementColumn(string $columnName = 'id'): string | |
| 389 | { | |
| 390 | return match ($this->dbType) { | |
| 391 | 'mysqli', 'pdo_mysql' => "{$columnName} INT NOT NULL AUTO_INCREMENT", | |
| 392 | 'pgsql', 'pdo_pgsql' => "{$columnName} SERIAL NOT NULL", | |
| 393 | 'sqlite3', 'pdo_sqlite' => "{$columnName} INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT", | |
| 394 | 'sqlsrv', 'pdo_sqlsrv' => "{$columnName} INT IDENTITY(1,1) NOT NULL", | |
| 395 | default => "{$columnName} INTEGER NOT NULL", | |
| 396 | }; | |
| 397 | } |
| 402 | protected function getConfig(string $key): mixed | |
| 403 | { | |
| 404 | return $this->configuration->get(item: $key); | |
| 405 | } |
| 410 | public function getChecksum(): string | |
| 411 | { | |
| 412 | $data = [ | |
| 413 | 'version' => $this->getVersion(), | |
| 414 | 'description' => $this->getDescription(), | |
| 415 | 'class' => static::class, | |
| 416 | ]; | |
| 417 | return hash('sha256', (string) json_encode($data)); | |
| 418 | } |