PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk 1.2.0 All 47 releases
fluent-cart / database / Migrations / Migrator.php

Migrator.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at database/Migrations/Migrator.php

215 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\Database\Migrations;
4
5 use FluentCart\Framework\Database\Schema;
6
7 abstract class Migrator
8 {
9 public static string $tableName = '';
10
11 /**
12 * Migrate the table.
13 *
14 * @return void
15 */
16
17 public static function migrate()
18 {
19 Schema::createTableIfNotExist(
20 static::getTableName(),
21 static::getSqlSchema()
22 );
23
24 static::migrated();
25 }
26
27 /**
28 * Called once migration is done.
29 *
30 * Override this method in child migrators to perform
31 * post-migration tasks like seeding data or adding indexes.
32 *
33 * @return void
34 */
35 public static function migrated()
36 {
37 // Override in child classes as needed.
38 }
39
40 /**
41 * Add a column if it does not exist.
42 *
43 * @param string $column Column name
44 * @param string $definition Column definition (e.g. "VARCHAR(100) NULL")
45 * @param string|null $after Place after this column (ignored on SQLite)
46 * @return void
47 */
48 protected static function addColumnIfNotExists($column, $definition, $after = null)
49 {
50 if (Schema::hasColumn($column, static::$tableName)) {
51 return;
52 }
53
54 $sql = "ADD COLUMN `{$column}` {$definition}";
55
56 if ($after && !Schema::isSqlite()) {
57 $sql .= " AFTER `{$after}`";
58 }
59
60 Schema::alterTable(static::$tableName, $sql);
61 }
62
63 /**
64 * Rename a column if the old name exists.
65 *
66 * @param string $oldColumn Current column name
67 * @param string $newColumn New column name
68 * @param string $definition New column definition
69 * @return void
70 */
71 protected static function renameColumnIfExists($oldColumn, $newColumn, $definition)
72 {
73 if (!Schema::hasColumn($oldColumn, static::$tableName)) {
74 return;
75 }
76
77 Schema::alterTable(
78 static::$tableName,
79 "CHANGE `{$oldColumn}` `{$newColumn}` {$definition}"
80 );
81 }
82
83 /**
84 * Modify a column type/definition if it exists.
85 *
86 * @param string $column Column name
87 * @param string $definition New column definition
88 * @return void
89 */
90 protected static function modifyColumnIfExists($column, $definition)
91 {
92 if (!Schema::hasColumn($column, static::$tableName)) {
93 return;
94 }
95
96 if (Schema::isSqlite()) {
97 // SQLite has no MODIFY; use CHANGE with same name to trigger rebuild
98 Schema::alterTable(
99 static::$tableName,
100 "CHANGE COLUMN `{$column}` `{$column}` {$definition}"
101 );
102 } else {
103 Schema::alterTable(
104 static::$tableName,
105 "MODIFY COLUMN `{$column}` {$definition}"
106 );
107 }
108 }
109
110 /**
111 * Check if an index exists on the table.
112 *
113 * @param string $indexName Index name
114 * @return bool
115 */
116 protected static function hasIndex($indexName)
117 {
118 $wpdb = Schema::db();
119 $tableName = static::getTableName();
120
121 // SHOW INDEX works on both MySQL and SQLite (the WP SQLite integration
122 // plugin translates it).
123 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
124 $results = $wpdb->get_results($wpdb->prepare(
125 "SHOW INDEX FROM %i WHERE Key_name = %s",
126 $tableName,
127 $indexName
128 ));
129
130 return !empty($results);
131 }
132
133 /**
134 * Add an index if it does not exist.
135 *
136 * @param string $indexName Index name
137 * @param string|array $columns Column name(s)
138 * @param bool $unique Whether the index is unique
139 * @return void
140 */
141 protected static function addIndexIfNotExists($indexName, $columns, $unique = false)
142 {
143 if (static::hasIndex($indexName)) {
144 return;
145 }
146
147 $type = $unique ? 'UNIQUE INDEX' : 'INDEX';
148
149 if (is_array($columns)) {
150 $colsSql = '`' . implode('`, `', $columns) . '`';
151 } else {
152 $colsSql = "`{$columns}`";
153 }
154
155 Schema::alterTable(
156 static::$tableName,
157 "ADD {$type} `{$indexName}` ({$colsSql})"
158 );
159 }
160
161 /**
162 * Drop an index if it exists.
163 *
164 * @param string $indexName Index name
165 * @return void
166 */
167 protected static function dropIndexIfExists($indexName)
168 {
169 if (!static::hasIndex($indexName)) {
170 return;
171 }
172
173 // Drop the index with a single direct ALTER rather than routing through
174 // Schema::dropIndex(), which calls WP core drop_index(). That core helper
175 // fires 25 speculative "DROP INDEX {name}_0".."_24" queries to clean up
176 // stray dbDelta-created duplicates; none of those variants exist for our
177 // explicitly-named indexes, so each one errors as "Can't DROP ..., check
178 // that column/key exists" and floods migration/test output with noise.
179 // hasIndex() above already confirmed the real index is present, so one
180 // ALTER is sufficient. The %i placeholder mirrors hasIndex() and keeps
181 // this safe on both MySQL and the WP SQLite integration.
182 $wpdb = Schema::db();
183 $tableName = static::getTableName();
184 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
185 $wpdb->query($wpdb->prepare(
186 "ALTER TABLE %i DROP INDEX %i",
187 $tableName,
188 $indexName
189 ));
190 }
191
192 public static function getTableName(bool $withPrefix = true): string
193 {
194 return ($withPrefix ? static::getDbPrefix() : '') . static::$tableName;
195 }
196
197 public static function getDbPrefix(): string
198 {
199 global $wpdb;
200 return $wpdb->prefix;
201 }
202
203 public static function getCharsetCollate(): string
204 {
205 global $wpdb;
206 return $wpdb->get_charset_collate();
207 }
208
209 public static function dropTable()
210 {
211 Schema::dropTableIfExists(static::getTableName(false));
212 }
213
214 abstract public static function getSqlSchema(): string;
215 }