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 = ''; protected DBmodel $dbh; public function __construct(?DBmodel $dbh) { if (is_null($dbh)) { if (!is_null(DBmodel::$instance)) { $this->dbh = DBmodel::$instance; } else { throw new \Exception('DB handler is null'); } } else { $this->dbh = $dbh; } } public function testDB($test, $test_out) { if (is_array($test_out)) { $test_out = array_change_key_case($test_out, CASE_LOWER); $row = $this->dbh->getRow($test); if (!is_array($row)) return false; $row = array_change_key_case($row, CASE_LOWER); 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 $this->dbh->getOne($test) == $test_out; } } public function checkDB($test, $test_out, $fix) { if ($this->testDB($test, $test_out)) { return Maintenance::OK; } else { $this->dbh->query($fix); if ($this->testDB($test, $test_out)) { return Maintenance::FIXED; } else { return Maintenance::FIX_FAILED; } } return 0; } public function existsTable($table_name) { return $this->testDB( 'SHOW TABLES LIKE "' . $table_name . '"', $table_name ); } public function checkDBTable($table_name, $definition, $after_definition = '') { if (strlen($table_name) <= 0) { $this->lastMessage = 'Table ' . strtoupper($table_name) . ' - 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 . ') ' . $after_definition ); $this->lastMessage = 'Table ' . strtoupper($table_name) . ' (' . $table_name . ')'; return $status; } public function existsColumn($table_name, $column) { return $this->testDB( 'DESCRIBE `' . $table_name . '` `' . $column . '`', $column ); } public function checkDBAdd($table_name, $column, $definition) { $status = $this->checkDB( // TEST query 'DESCRIBE `' . $table_name . '` `' . $column . '`', // TEST output $column, // FIX query 'ALTER TABLE `' . $table_name . '` ADD `' . $column . '` ' . $definition ); $this->lastMessage = "Added column $column to table $table_name"; return $status; } public function checkDBRename($table_name, $column_old, $column_new, $definition, $test = null) { if (!$this->existsColumn($table_name, $column_old)) { return Maintenance::ABNORMAL; } $status = $this->checkDB( // TEST query 'DESCRIBE `' . $table_name . '` `' . $column_old . '`', // TEST output $test, // FIX query 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_old . '` `' . $column_new . '` ' . $definition ); $this->lastMessage = "Renamed column $column_old to $column_new for $table_name"; return $status; } public function checkDBRetype($table_name, $column, $new_type, $definition) { if (!$this->existsColumn($table_name, $column)) { return Maintenance::ABNORMAL; } $status = $this->checkDB( // TEST query 'DESCRIBE `' . $table_name . '` `' . $column . '`', // TEST output array('type' => strtolower($new_type)), // FIX query 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column . '` `' . $column . '` ' . $definition ); $this->lastMessage = "Changed type of column $column for table " . strtoupper($table_name) . " to tyoe " . strtoupper($new_type); return $status; } public function checkDBRemove($table_name, $column) { $status = $this->checkDB( // TEST query 'DESCRIBE `' . $table_name . '` `' . $column . '`', // TEST output NULL, // FIX query 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column . '`' ); $this->lastMessage = "Removed column $column for " . strtoupper($table_name); return $status; } public function addKey($table_name, $key) { $test = 'SHOW INDEX FROM `' . $table_name . '` WHERE column_name = "' . $key . '"'; $test_out = array('table' => $table_name); if ($this->testDB($test, $test_out)) { $status = Maintenance::OK; } else { $fix = 'CREATE INDEX `' . $key . '` ON `' . $table_name . '` (`' . $key . '`)'; $this->dbh->query($fix); if ($this->testDB($test, $test_out)) { $status = Maintenance::FIXED; } else { $status = Maintenance::FIX_FAILED; } } $this->lastMessage = 'Added KEY ' . $key . ' for ' . strtoupper($table_name); return $status; } public function dropKey($table_name, $key) { $test = 'SHOW INDEX FROM `' . $table_name . '` WHERE column_name = "' . $key . '"'; $test_out = null; if ($this->testDB($test, $test_out)) { $status = Maintenance::OK; } else { $index_info = $this->dbh->getRow('SHOW INDEX FROM `' . $table_name . '` WHERE column_name = "' . $key . '"'); $index_info = array_change_key_case($index_info, CASE_LOWER); $index_name = $index_info['key_name']; $fix = 'ALTER TABLE `' . $table_name . '` DROP INDEX `' . $index_name . '`'; $this->dbh->query($fix); if ($this->testDB($test, $test_out)) { $status = Maintenance::FIXED; } else { $status = Maintenance::FIX_FAILED; } } $this->lastMessage = 'Deleted KEY ' . $key . ' for ' . strtoupper($table_name); return $status; } public function updateDB($test, $test_out, $update) { if (!$this->testDB($test, $test_out)) { return Maintenance::OK; } else { $suc = $this->dbh->query($update); if ($suc !== false) { return Maintenance::UPDATED; } else { return Maintenance::UPDATE_FAIL; } } return 0; } }