diff --git a/src/Maintenance.php b/src/Maintenance.php new file mode 100644 index 0000000..423be69 --- /dev/null +++ b/src/Maintenance.php @@ -0,0 +1,210 @@ + + License: GNU GPL-3.0 or later + + Description: Tool for automatic maintenance of database in your project. + Version: 1.0.0 + + Milestones: + 2025-05-29 07:59 Igor - Forked from Beteha to standalone public library +*/ + +namespace TPsoft\DBmodel; + +class Maintenance +{ + public const ABNORMAL = 0; + public const OK = 1; + public const FIXED = 2; + public const FIX_FAILED = 3; + public const UPDATED = 4; + public const UPDATE_FAIL = 5; + + public string $lastMessage = ''; + + private DBmodel $dbh; + + public function __construct(DBmodel $dbh) + { + $this->dbh = $dbh; + } + + public function testDB($test, $test_out) + { + global $core; + if (is_array($test_out)) { + $row = $core->dbh->getRow($test); + if (!is_array($row)) return false; + foreach ($test_out as $col => $val) { + if (strlen($row[$col]) != strlen($val)) { + $max_len = min(strlen($row[$col]), strlen($val)); + if (substr(strtolower($row[$col]), 0, $max_len) != substr(strtolower($val), 0, $max_len)) { + return false; + } + } else { + if (strtolower($row[$col]) != strtolower($val)) { + return false; + } + } + } + return true; + } else { + return $core->dbh->getOne($test) == $test_out; + } + } + + public function checkDB($test, $test_out, $fix) + { + global $core; + if ($this->testDB($test, $test_out)) { + return Maintenance::OK; + } else { + $core->dbh->query($fix); + if ($this->testDB($test, $test_out)) { + return Maintenance::FIXED; + } else { + return Maintenance::FIX_FAILED; + } + } + return 0; + } + + public function checkDBTable($table_index, $definition) + { + global $core; + $table_name = $core->tables[$table_index]; + if (strlen($table_name) <= 0) { + $this->lastMessage = 'Table ' . strtoupper($table_index) . ' - invalid index'; + return Maintenance::ABNORMAL; + } + $status = $this->checkDB( + // TEST query + 'SHOW TABLES LIKE "' . $table_name . '"', + // TEST output + $table_name, + // FIX query + 'CREATE TABLE `' . $table_name . '` (' . $definition . ')' + ); + $this->lastMessage = 'Table ' . strtoupper($table_index) . ' (' . $table_name . ')'; + return $status; + } + + public function checkDBAdd($table_index, $column, $definition) + { + global $core; + $status = $this->checkDB( + // TEST query + 'DESCRIBE `' . $core->tables[$table_index] . '` `' . $column . '`', + // TEST output + $column, + // FIX query + 'ALTER TABLE `' . $core->tables[$table_index] . '` ADD `' . $column . '` ' . $definition + ); + $this->lastMessage = "Added column $column to table $table_index"; + return $status; + } + + public function checkDBRename($table_index, $column_old, $column_new, $definition, $test = null) + { + global $core; + $status = $this->checkDB( + // TEST query + 'DESCRIBE `' . $core->tables[$table_index] . '` `' . $column_old . '`', + // TEST output + $test, + // FIX query + 'ALTER TABLE `' . $core->tables[$table_index] . '` CHANGE `' . $column_old . '` `' . $column_new . '` ' . $definition + ); + $this->lastMessage = "Renamed column $column_old to $column_new for $table_index"; + return $status; + } + + public function checkDBRetype($table_index, $column, $new_type, $definition) + { + global $core; + $status = $this->checkDB( + // TEST query + 'DESCRIBE `' . $core->tables[$table_index] . '` `' . $column . '`', + // TEST output + array('type' => strtolower($new_type)), + // FIX query + 'ALTER TABLE `' . $core->tables[$table_index] . '` CHANGE `' . $column . '` `' . $column . '` ' . $definition + ); + $this->lastMessage = "Changed type of column $column for tabke $table_index to tyoe " . strtoupper($new_type); + return $status; + } + + public function checkDBRemove($table_index, $column) + { + global $core; + $status = $this->checkDB( + // TEST query + 'DESCRIBE `' . $core->tables[$table_index] . '` `' . $column . '`', + // TEST output + NULL, + // FIX query + 'ALTER TABLE `' . $core->tables[$table_index] . '` DROP COLUMN `' . $column . '`' + ); + $this->lastMessage = "Removed column $column for $table_index"; + return $status; + } + + public function dropKey($table_index, $key) + { + global $core; + $test = 'SHOW INDEX FROM `' . $core->tables[$table_index] . '` WHERE column_name = "' . $key . '"'; + $test_out = null; + if ($this->testDB($test, $test_out)) { + $status = Maintenance::OK; + } else { + $index_name = $core->dbh->getRow('SHOW INDEX FROM `' . $core->tables[$table_index] . '` WHERE column_name = "' . $key . '"')['key_name']; + $fix = 'ALTER TABLE `' . $core->tables[$table_index] . '` DROP INDEX ' . $index_name; + $core->dbh->query($fix); + if ($this->testDB($test, $test_out)) { + $status = Maintenance::FIXED; + } else { + $status = Maintenance::FIX_FAILED; + } + } + $this->lastMessage = 'Deleted KEY ' . $key . ' for ' . $table_index; + return $status; + } + + public function addKey($table_index, $key) + { + global $core; + $test = 'SHOW INDEX FROM `' . $core->tables[$table_index] . '` WHERE column_name = "' . $key . '"'; + $test_out = array('table' => $core->tables[$table_index]); + if ($this->testDB($test, $test_out)) { + $status = Maintenance::OK; + } else { + $fix = 'CREATE INDEX `' . $key . '` ON `' . $core->tables[$table_index] . '` (`' . $key . '`)'; + $core->dbh->query($fix); + if ($this->testDB($test, $test_out)) { + $status = Maintenance::FIXED; + } else { + $status = Maintenance::FIX_FAILED; + } + } + $this->lastMessage = 'Added KEY ' . $key . ' for ' . $table_index; + return $status; + } + + public function updateDB($test, $test_out, $update) + { + global $core; + if (!$this->testDB($test, $test_out)) { + return Maintenance::OK; + } else { + $suc = $core->dbh->query($update); + if ($suc !== false) { + return Maintenance::UPDATED; + } else { + return Maintenance::UPDATE_FAIL; + } + } + return 0; + } +}