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