PluginProbe
User Access Manager / 2.2.2
User Access Manager v2.2.2
2.3.20 2.3.19 2.3.18 2.3.17 2.3.16 2.3.15 2.3.14 2.3.13 trunk 0.6 0.6.1 0.6.2 0.7 0.7 Beta 0.7.0.1 0.8 0.8.0.1 0.8.0.2 0.9 0.9.1 0.9.1.1 0.9.1.2 0.9.1.3 0.9.1.4 1.0 All 136 releases
← All changes | src/Setup/Database/DatabaseHandler.php +195 -74 trunk2.2.2 View file →
@@ -1,5 +1,18 @@
1 1 <?php
2 +/**
3 + * DatabaseHandler.php
4 + *
5 + * The DatabaseHandler class file.
6 + *
7 + * PHP versions 5
8 + *
9 + * @author Alexander Schneider <alexanderschneider85@gmail.com>
10 + * @copyright 2008-2017 Alexander Schneider
11 + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2
12 + * @version SVN: $id$
13 + * @link http://wordpress.org/extend/plugins/user-access-manager/
14 + */
2 15
3 16 declare(strict_types=1);
4 17
5 18 namespace UserAccessManager\Setup\Database;
@@ -9,36 +22,82 @@
9 22 use UserAccessManager\Setup\Update\UpdateInterface;
10 23 use UserAccessManager\UserAccessManager;
11 24 use UserAccessManager\Wrapper\Wordpress;
12 25
26 +/**
27 + * Class DatabaseHandler
28 + *
29 + * @package UserAccessManager\Setup\Database
30 + */
13 31 class DatabaseHandler
14 32 {
15 - public const MISSING_TABLES = 'MISSING_TABLE';
16 - public const MISSING_COLUMNS = 'MISSING_COLUMNS';
17 - public const MODIFIED_COLUMNS = 'MODIFIED_COLUMNS';
18 - public const EXTRA_COLUMNS = 'EXTRA_COLUMNS';
33 + const MISSING_TABLES = 'MISSING_TABLE';
34 + const MISSING_COLUMNS = 'MISSING_COLUMNS';
35 + const MODIFIED_COLUMNS = 'MODIFIED_COLUMNS';
36 + const EXTRA_COLUMNS = 'EXTRA_COLUMNS';
19 37
38 + /**
39 + * @var Wordpress
40 + */
41 + private $wordpress;
42 +
43 + /**
44 + * @var Database
45 + */
46 + private $database;
47 +
48 + /**
49 + * @var DatabaseObjectFactory
50 + */
51 + private $databaseObjectFactory;
52 +
53 + /**
54 + * @var UpdateFactory
55 + */
56 + private $updateFactory;
57 +
58 + /**
59 + * DatabaseHandler constructor.
60 + * @param Wordpress $wordpress
61 + * @param Database $database
62 + * @param DatabaseObjectFactory $databaseObjectFactory
63 + * @param UpdateFactory $updateFactory
64 + */
20 65 public function __construct(
21 - private Wordpress $wordpress,
22 - private Database $database,
23 - private DatabaseObjectFactory $databaseObjectFactory,
24 - private UpdateFactory $updateFactory
66 + Wordpress $wordpress,
67 + Database $database,
68 + DatabaseObjectFactory $databaseObjectFactory,
69 + UpdateFactory $updateFactory
25 70 ) {
71 + $this->wordpress = $wordpress;
72 + $this->database = $database;
73 + $this->databaseObjectFactory = $databaseObjectFactory;
74 + $this->updateFactory = $updateFactory;
26 75 }
27 76
77 + /**
78 + * Checks if the table exists.
79 + * @param string $table
80 + * @return bool
81 + */
28 82 private function tableExists(string $table): bool
29 83 {
30 - $dbTable = $this->database->getVariable("SHOW TABLES LIKE '$table'");
84 + $dbTable = $this->database->getVariable("SHOW TABLES LIKE '{$table}'");
31 85
32 86 return ($table === $dbTable);
33 87 }
34 88
35 - private function addTable(Table $table): void
89 + /**
90 + * Adds a table.
91 + * @param Table $table
92 + */
93 + private function addTable(Table $table)
36 94 {
37 95 $this->database->dbDelta((string) $table);
38 96 }
39 97
40 98 /**
99 + * Returns all tables.
41 100 * @return Table[]
42 101 * @throws MissingColumnsException
43 102 */
44 103 private function getTables(): array
@@ -49,9 +108,9 @@
49 108 $tables[] = $this->databaseObjectFactory->createTable(
50 109 $this->database->getUserGroupTable(),
51 110 $charsetCollate,
52 111 [
53 - $this->databaseObjectFactory->createColumn('ID', 'INT', false, null, true, true),
112 + $this->databaseObjectFactory->createColumn('ID', 'INT(11)', false, null, true, true),
54 113 $this->databaseObjectFactory->createColumn('groupname', 'TINYTEXT'),
55 114 $this->databaseObjectFactory->createColumn('groupdesc', 'TEXT'),
56 115 $this->databaseObjectFactory->createColumn('read_access', 'TINYTEXT'),
57 116 $this->databaseObjectFactory->createColumn('write_access', 'TINYTEXT'),
@@ -76,11 +135,12 @@
76 135 return $tables;
77 136 }
78 137
79 138 /**
139 + * Adds the tables to the database.
80 140 * @throws MissingColumnsException
81 141 */
82 - public function install(): void
142 + public function install()
83 143 {
84 144 foreach ($this->getTables() as $table) {
85 145 if ($this->tableExists($table->getName()) === false) {
86 146 $this->addTable($table);
@@ -90,8 +150,10 @@
90 150 $this->wordpress->addOption('uam_db_version', UserAccessManager::DB_VERSION);
91 151 }
92 152
93 153 /**
154 + * Returns the existing columns for a table.
155 + * @param Table $table
94 156 * @return Column[]
95 157 */
96 158 private function getExistingColumns(Table $table): array
97 159 {
@@ -112,9 +174,14 @@
112 174
113 175 return $existingColumns;
114 176 }
115 177
116 - private function addCorruptedRows(Table $table, array &$information): void
178 + /**
179 + * Add corrupted columns to the information array if the are some.
180 + * @param Table $table
181 + * @param array $information
182 + */
183 + private function addCorruptedRows(Table $table, array &$information)
117 184 {
118 185 $existingColumns = $this->getExistingColumns($table);
119 186
120 187 foreach ($table->getColumns() as $column) {
@@ -127,8 +194,9 @@
127 194 unset($existingColumns[$column->getName()]);
128 195
129 196 if ((string) $column !== (string) $existingColumn) {
130 197 $information[self::MODIFIED_COLUMNS][] = [$table, $column];
198 + continue;
131 199 }
132 200 }
133 201
134 202 foreach ($existingColumns as $existingColumn) {
@@ -136,8 +204,10 @@
136 204 }
137 205 }
138 206
139 207 /**
208 + * Returns corrupted database information.
209 + * @return array
140 210 * @throws MissingColumnsException
141 211 */
142 212 public function getCorruptedDatabaseInformation(): array
143 213 {
@@ -159,14 +229,45 @@
159 229
160 230 return $information;
161 231 }
162 232
163 - private function alterTable(Table $table, string $alteration): bool
233 + /**
234 + * Adds a new column.
235 + * @param Table $table
236 + * @param Column $column
237 + * @return bool
238 + */
239 + private function addColumn(Table $table, Column $column): bool
164 240 {
165 - return $this->database->query("ALTER TABLE `{$table->getName()}` $alteration;") !== false;
241 + return $this->database->query("ALTER TABLE `{$table->getName()}` ADD $column;") !== false;
166 242 }
167 243
168 244 /**
245 + * Modify an existing column.
246 + * @param Table $table
247 + * @param Column $column
248 + * @return bool
249 + */
250 + private function modifyColumn(Table $table, Column $column): bool
251 + {
252 + return $this->database->query("ALTER TABLE `{$table->getName()}` MODIFY $column;") !== false;
253 + }
254 +
255 + /**
256 + * Drops an existing column.
257 + * @param Table $table
258 + * @param Column $column
259 + * @return bool
260 + */
261 + private function dropColumn(Table $table, Column $column): bool
262 + {
263 + return $this->database->query("ALTER TABLE `{$table->getName()}` DROP `{$column->getName()}`;") !== false;
264 + }
265 +
266 + /**
267 + * Repairs a corrupt database.
268 + * @param array $information
269 + * @return bool
169 270 * @throws MissingColumnsException
170 271 */
171 272 public function repairDatabase(array $information = []): bool
172 273 {
@@ -176,23 +277,27 @@
176 277 foreach ($information[self::MISSING_TABLES] as $table) {
177 278 $this->addTable($table);
178 279 }
179 280
180 - $alterationsByInformationKey = [
181 - self::MISSING_COLUMNS => static fn(Column $column) => "ADD $column",
182 - self::MODIFIED_COLUMNS => static fn(Column $column) => "MODIFY $column",
183 - self::EXTRA_COLUMNS => static fn(Column $column) => "DROP `{$column->getName()}`"
184 - ];
281 + foreach ($information[self::MISSING_COLUMNS] as $columnInformation) {
282 + $success = $success && $this->addColumn($columnInformation[0], $columnInformation[1]);
283 + }
185 284
186 - foreach ($alterationsByInformationKey as $informationKey => $buildAlteration) {
187 - foreach ($information[$informationKey] as [$table, $column]) {
188 - $success = $success && $this->alterTable($table, $buildAlteration($column));
189 - }
285 + foreach ($information[self::MODIFIED_COLUMNS] as $columnInformation) {
286 + $success = $success && $this->modifyColumn($columnInformation[0], $columnInformation[1]);
190 287 }
191 288
289 + foreach ($information[self::EXTRA_COLUMNS] as $columnInformation) {
290 + $success = $success && $this->dropColumn($columnInformation[0], $columnInformation[1]);
291 + }
292 +
192 293 return $success;
193 294 }
194 295
296 + /**
297 + * Returns all sites where the user access manager is active.
298 + * @return array
299 + */
195 300 private function getActivePluginSites(): array
196 301 {
197 302 $activeSites = [];
198 303
@@ -210,59 +315,40 @@
210 315
211 316 return $activeSites;
212 317 }
213 318
214 - private function hasSiteWithOutdatedDatabase(): bool
215 - {
216 - foreach ($this->getActivePluginSites() as $siteId) {
217 - $table = $this->database->getBlogPrefix($siteId) . 'options';
218 - $select = "SELECT `option_value` FROM `$table` WHERE `option_name` = '%s' LIMIT 1";
219 - $select = $this->database->prepare($select, 'uam_db_version');
220 - $currentDbVersion = $this->database->getVariable($select);
221 -
222 - if ($currentDbVersion !== null
223 - && version_compare((string) $currentDbVersion, UserAccessManager::DB_VERSION, '<') === true
224 - ) {
225 - return true;
226 - }
227 - }
228 -
229 - return false;
230 - }
231 -
232 319 /**
233 - * @throws MissingColumnsException
320 + * Checks if a database update is necessary.
321 + * @return bool
234 322 */
235 323 public function isDatabaseUpdateNecessary(): bool
236 324 {
237 - if ($this->wordpress->isSuperAdmin() === true && $this->hasSiteWithOutdatedDatabase() === true) {
238 - return true;
239 - }
325 + if ($this->wordpress->isSuperAdmin() === true) {
326 + foreach ($this->getActivePluginSites() as $siteId) {
327 + $table = $this->database->getBlogPrefix($siteId) . 'options';
328 + $select = "SELECT option_value FROM {$table} WHERE option_name = '%s' LIMIT 1";
329 + $select = $this->database->prepare($select, 'uam_db_version');
330 + $currentDbVersion = $this->database->getVariable($select);
240 331
241 - $currentDbVersion = (string) $this->wordpress->getOption('uam_db_version');
242 -
243 - if (empty($currentDbVersion) === true) {
244 - $this->install();
245 - $currentDbVersion = (string) $this->wordpress->getOption('uam_db_version');
332 + if ($currentDbVersion !== null
333 + && version_compare($currentDbVersion, UserAccessManager::DB_VERSION, '<') === true
334 + ) {
335 + return true;
336 + }
337 + }
246 338 }
247 339
340 + $currentDbVersion = $this->wordpress->getOption('uam_db_version');
248 341 return version_compare($currentDbVersion, UserAccessManager::DB_VERSION, '<');
249 342 }
250 343
251 344 /**
252 - * @return string[]
345 + * Creates a database backup.
346 + * @return bool
253 347 */
254 - private function getTableNames(): array
255 - {
256 - return [
257 - $this->database->getUserGroupTable(),
258 - $this->database->getUserGroupToObjectTable()
259 - ];
260 - }
261 -
262 348 public function backupDatabase(): bool
263 349 {
264 - $currentDbVersion = (string) $this->wordpress->getOption('uam_db_version');
350 + $currentDbVersion = $this->wordpress->getOption('uam_db_version');
265 351
266 352 if (empty($currentDbVersion) === true
267 353 || version_compare($currentDbVersion, '1.2', '<') === true
268 354 ) {
@@ -268,15 +354,20 @@
268 354 ) {
269 355 return false;
270 356 }
271 357
358 + $tables = [
359 + $this->database->getUserGroupTable(),
360 + $this->database->getUserGroupToObjectTable()
361 + ];
362 +
272 363 $currentDbVersion = str_replace('.', '-', $currentDbVersion);
273 364 $success = true;
274 365
275 - foreach ($this->getTableNames() as $table) {
276 - $createQuery = "CREATE TABLE `{$table}_$currentDbVersion` LIKE `$table`";
366 + foreach ($tables as $table) {
367 + $createQuery = "CREATE TABLE `{$table}_{$currentDbVersion}` LIKE `{$table}`";
277 368 $success = $success && ($this->database->query($createQuery) !== false);
278 - $insertQuery = "INSERT `{$table}_$currentDbVersion` SELECT * FROM `$table`";
369 + $insertQuery = "INSERT `{$table}_{$currentDbVersion}` SELECT * FROM `{$table}`";
279 370 $success = $success && ($this->database->query($insertQuery) !== false);
280 371 }
281 372
282 373 return $success;
@@ -281,17 +372,21 @@
281 372
282 373 return $success;
283 374 }
284 375
376 + /**
377 + * Returns the version for which a backup was created.
378 + * @return array
379 + */
285 380 public function getBackups(): array
286 381 {
287 382 $versions = [];
288 - $tables = $this->database->getColumn(
383 + $tables = (array) $this->database->getColumn(
289 384 "SHOW TABLES LIKE '{$this->database->getPrefix()}uam_%'"
290 385 );
291 386
292 387 foreach ($tables as $table) {
293 - if (preg_match('/.*_([0-9\-]+)/', $table, $matches) === 1) {
388 + if (preg_match('/.*_([0-9\-]+)/i', $table, $matches) === 1) {
294 389 $version = str_replace('-', '.', $matches[1]);
295 390 $versions[$version] = $version;
296 391 }
297 392 }
@@ -298,16 +393,26 @@
298 393
299 394 return $versions;
300 395 }
301 396
397 + /**
398 + * Returns the backup tables for the given version.
399 + * @param string $version
400 + * @return array
401 + */
302 402 private function getBackupTables(string $version): array
303 403 {
304 404 $backupTables = [];
405 + $tables = [
406 + $this->database->getUserGroupTable(),
407 + $this->database->getUserGroupToObjectTable()
408 + ];
409 +
305 410 $versionForDb = str_replace('.', '-', $version);
306 411
307 - foreach ($this->getTableNames() as $table) {
412 + foreach ($tables as $table) {
308 413 $backupTable = (string) $this->database->getVariable(
309 - "SHOW TABLES LIKE '{$table}_$versionForDb'"
414 + "SHOW TABLES LIKE '{$table}_{$versionForDb}'"
310 415 );
311 416
312 417 if ($backupTable !== '') {
313 418 $backupTables[$table] = $backupTable;
@@ -316,8 +421,13 @@
316 421
317 422 return $backupTables;
318 423 }
319 424
425 + /**
426 + * Reverts the database to the given version.
427 + * @param string $version
428 + * @return bool
429 + */
320 430 public function revertDatabase(string $version): bool
321 431 {
322 432 $success = true;
323 433 $tables = $this->getBackupTables($version);
@@ -322,11 +432,11 @@
322 432 $success = true;
323 433 $tables = $this->getBackupTables($version);
324 434
325 435 foreach ($tables as $table => $backupTable) {
326 - $dropQuery = "DROP TABLE IF EXISTS `$table`";
436 + $dropQuery = "DROP TABLE IF EXISTS `{$table}`";
327 437 $success = $success && ($this->database->query($dropQuery) !== false);
328 - $renameQuery = "RENAME TABLE `$backupTable` TO `$table`";
438 + $renameQuery = "RENAME TABLE `{$backupTable}` TO `{$table}`";
329 439 $success = $success && ($this->database->query($renameQuery) !== false);
330 440 }
331 441
332 442 if ($success === true) {
@@ -335,15 +445,20 @@
335 445
336 446 return $success;
337 447 }
338 448
449 + /**
450 + * Deletes the given database backup.
451 + * @param string $version
452 + * @return bool
453 + */
339 454 public function deleteBackup(string $version): bool
340 455 {
341 456 $success = true;
342 457 $tables = $this->getBackupTables($version);
343 458
344 - foreach ($tables as $backupTable) {
345 - $dropQuery = "DROP TABLE IF EXISTS `$backupTable`";
459 + foreach ($tables as $table => $backupTable) {
460 + $dropQuery = "DROP TABLE IF EXISTS `{$backupTable}`";
346 461 $success = $success && ($this->database->query($dropQuery) !== false);
347 462 }
348 463
349 464 return $success;
@@ -349,8 +464,9 @@
349 464 return $success;
350 465 }
351 466
352 467 /**
468 + * Returns the ordered updates.
353 469 * @return UpdateInterface[]
354 470 */
355 471 private function getOrderedDatabaseUpdates(): array
356 472 {
@@ -364,11 +480,15 @@
364 480 uksort($updates, 'version_compare');
365 481 return $updates;
366 482 }
367 483
484 + /**
485 + * Updates the database.
486 + * @return bool
487 + */
368 488 public function updateDatabase(): bool
369 489 {
370 - $currentDbVersion = (string) $this->wordpress->getOption('uam_db_version');
490 + $currentDbVersion = $this->wordpress->getOption('uam_db_version');
371 491
372 492 if (empty($currentDbVersion) === true) {
373 493 return false;
374 494 }
@@ -388,11 +508,12 @@
388 508 return $success;
389 509 }
390 510
391 511 /**
512 + * Removes the tables.
392 513 * @throws MissingColumnsException
393 514 */
394 - public function removeTables(): void
515 + public function removeTables()
395 516 {
396 517 foreach ($this->getTables() as $table) {
397 518 $dropQuery = "DROP TABLE IF EXISTS `{$table->getName()}`";
398 519 $this->database->query($dropQuery);