billingerp/admin/update/UpdateManager.php

262 lines
9.3 KiB
PHP

<?php
/**
* Update Manager - განახლებების მართვის სისტემა
* ვერსია: 1.0.0
*/
class UpdateManager {
private $pdo;
private $currentVersion;
private $updatePath;
private $backupPath;
public function __construct($pdo = null)
{
if ($pdo === null) {
// თუ PDO არ არის გადაცემული, ვიყენებთ მიგრაციის db ფაილს
require_once __DIR__ . '/includes/db_migration.php';
global $pdo;
}
$this->pdo = $pdo;
$this->initVersionTable();
}
/**
* ვერსიების ცხრილის ინიციალიზაცია
*/
private function initVersionTable() {
$sql = "CREATE TABLE IF NOT EXISTS version_history (
id INT AUTO_INCREMENT PRIMARY KEY,
version VARCHAR(20) NOT NULL,
description TEXT,
migration_file VARCHAR(255),
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status ENUM('pending', 'completed', 'failed') DEFAULT 'pending'
)";
$this->pdo->exec($sql);
}
/**
* მიმდინარე ვერსიის მიღება
*/
public function getCurrentVersion() {
try {
$stmt = $this->pdo->query("SELECT version FROM version_history WHERE status = 'completed' ORDER BY executed_at DESC LIMIT 1");
$result = $stmt->fetch();
return $result ? $result['version'] : '1.0.0';
} catch (Exception $e) {
return '1.0.0';
}
}
/**
* ხელმისაწვდომი განახლებების სია
*/
public function getAvailableUpdates() {
$migrations = glob($this->updatePath . '/migrations/*.php');
$available = [];
foreach ($migrations as $file) {
$filename = basename($file);
if (preg_match('/^(\d+\.\d+\.\d+)_(.+)\.php$/', $filename, $matches)) {
$version = $matches[1];
$description = str_replace('_', ' ', $matches[2]);
// შევამოწმოთ უკვე გაშვებულია თუ არა
$stmt = $this->pdo->prepare("SELECT id FROM version_history WHERE version = ? AND status = 'completed'");
$stmt->execute([$version]);
if (!$stmt->fetch()) {
$available[] = [
'version' => $version,
'description' => $description,
'file' => $file,
'filename' => $filename
];
}
}
}
// ვერსიის მიხედვით დალაგება
usort($available, function($a, $b) {
return version_compare($a['version'], $b['version']);
});
return $available;
}
/**
* განახლების გაშვება
*/
public function runUpdate($version) {
$updates = $this->getAvailableUpdates();
$updateToRun = null;
foreach ($updates as $update) {
if ($update['version'] === $version) {
$updateToRun = $update;
break;
}
}
if (!$updateToRun) {
throw new Exception("განახლება ვერსია $version ვერ მოიძებნა");
}
// backup-ის შექმნა
$this->createBackup($version);
// განახლების ჩანაწერი
$stmt = $this->pdo->prepare("INSERT INTO version_history (version, description, migration_file, status) VALUES (?, ?, ?, 'pending')");
$stmt->execute([$version, $updateToRun['description'], $updateToRun['filename']]);
$updateId = $this->pdo->lastInsertId();
try {
// მიგრაციის ფაილის ჩატვირთვა და გაშვება
require_once $updateToRun['file'];
// განახლების სტატუსის შეცვლა
$stmt = $this->pdo->prepare("UPDATE version_history SET status = 'completed' WHERE id = ?");
$stmt->execute([$updateId]);
return [
'success' => true,
'message' => "განახლება $version წარმატებით დასრულდა",
'version' => $version
];
} catch (Exception $e) {
// შეცდომის მტკიცების ჩანაწერი
$stmt = $this->pdo->prepare("UPDATE version_history SET status = 'failed' WHERE id = ?");
$stmt->execute([$updateId]);
throw new Exception("განახლების შეცდომა: " . $e->getMessage());
}
}
/**
* ყველა ხელმისაწვდომი განახლების გაშვება
*/
public function runAllUpdates() {
$updates = $this->getAvailableUpdates();
$results = [];
foreach ($updates as $update) {
try {
$result = $this->runUpdate($update['version']);
$results[] = $result;
} catch (Exception $e) {
$results[] = [
'success' => false,
'message' => $e->getMessage(),
'version' => $update['version']
];
break; // შეწყვიტოს შემდგომი განახლებები შეცდომის შემთხვევაში
}
}
return $results;
}
/**
* Backup-ის შექმნა
*/
private function createBackup($version) {
$backupDir = $this->backupPath . '/backup_' . $version . '_' . date('Y-m-d_H-i-s');
if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true);
}
// ბაზის backup
$config = include __DIR__ . '/../config.php';
$dumpFile = $backupDir . '/database_backup.sql';
$command = sprintf(
'mysqldump -h%s -u%s -p%s %s > %s',
escapeshellarg($config['host']),
escapeshellarg($config['user']),
escapeshellarg($config['pass']),
escapeshellarg($config['dbname']),
escapeshellarg($dumpFile)
);
exec($command, $output, $returnVar);
if ($returnVar !== 0) {
throw new Exception("ბაზის backup ვერ შეიქმნა");
}
// კონფიგურაციის ფაილის backup
copy(__DIR__ . '/../config.php', $backupDir . '/config_backup.php');
return $backupDir;
}
/**
* განახლებების ისტორია
*/
public function getUpdateHistory() {
$stmt = $this->pdo->query("SELECT * FROM version_history ORDER BY executed_at DESC");
return $stmt->fetchAll();
}
/**
* ახალი მიგრაციის ფაილის შექმნა
*/
public function createMigration($version, $description, $upSql, $downSql = '') {
$filename = $version . '_' . str_replace(' ', '_', strtolower($description)) . '.php';
$filepath = $this->updatePath . '/migrations/' . $filename;
$template = $this->getMigrationTemplate($version, $description, $upSql, $downSql);
if (file_put_contents($filepath, $template)) {
return [
'success' => true,
'message' => "მიგრაციის ფაილი შეიქმნა: $filename",
'file' => $filepath
];
} else {
throw new Exception("მიგრაციის ფაილის შექმნა ვერ მოხერხდა");
}
}
/**
* მიგრაციის ფაილის შაბლონი
*/
private function getMigrationTemplate($version, $description, $upSql, $downSql) {
return "<?php
/**
* Migration: $description
* Version: $version
* Created: " . date('Y-m-d H:i:s') . "
*/
try {
// განახლების SQL
\$upSql = \"$upSql\";
if (\$upSql) {
\$pdo->exec(\$upSql);
echo \"$description - წარმატებით შესრულდა\\n\";
}
} catch (Exception \$e) {
// Rollback SQL (არასავალდებულო)
\$downSql = \"$downSql\";
if (\$downSql) {
try {
\$pdo->exec(\$downSql);
echo \"⚠️ Rollback SQL შესრულდა\\n\";
} catch (Exception \$rollbackError) {
echo \"❌ Rollback შეცდომა: \" . \$rollbackError->getMessage() . \"\\n\";
}
}
throw new Exception(\"$description - შეცდომა: \" . \$e->getMessage());
}
?>";
}
}
?>