PowerKiKi /
mqueue
| 1 | <?php |
||
| 2 | |||
| 3 | require_once __DIR__ . '/../public/index.php'; |
||
| 4 | |||
| 5 | $settingName = 'databaseVersion'; // This is the setting name used in the database to store the version information |
||
| 6 | $sqlPath = __DIR__ . '/sql/'; // This is the path where all SQL patches resides |
||
| 7 | |||
| 8 | /** |
||
| 9 | * Returns the last version available in SQL file |
||
| 10 | * |
||
| 11 | * @return int last version of patches |
||
| 12 | */ |
||
| 13 | function getPatchVersion() |
||
| 14 | { |
||
| 15 | global $sqlPath; |
||
| 16 | $lastVersion = 0; |
||
| 17 | $d = dir($sqlPath); |
||
| 18 | while (false !== ($entry = $d->read())) { |
||
| 19 | if (preg_match('/^version\.(\d+)\.sql$/i', $entry, $a)) { |
||
| 20 | if ((int) $a[1] > $lastVersion) { |
||
| 21 | $lastVersion = (int) $a[1]; |
||
| 22 | } |
||
| 23 | } |
||
| 24 | } |
||
| 25 | $d->close(); |
||
| 26 | |||
| 27 | return $lastVersion; |
||
| 28 | } |
||
| 29 | |||
| 30 | /** |
||
| 31 | * Returns the whole SQL (enclosed in transaction) needed to update from |
||
| 32 | * specified version to specified target version. |
||
| 33 | * |
||
| 34 | * @param int $currentVersion the version currently found in database |
||
| 35 | * @param int $targetVersion the target version to reach wich patches |
||
| 36 | * |
||
| 37 | * @return string the SQL |
||
| 38 | */ |
||
| 39 | function buildSQL($currentVersion, $targetVersion) |
||
| 40 | { |
||
| 41 | global $sqlPath; |
||
| 42 | |||
| 43 | if ($currentVersion > $targetVersion) { |
||
| 44 | throw new Exception('Cannot downgrade versions. Target version must be higher than current version'); |
||
| 45 | } |
||
| 46 | |||
| 47 | $sql = "START TRANSACTION;\n"; |
||
| 48 | |||
| 49 | $missingVersions = []; |
||
| 50 | for ($v = $currentVersion + 1; $v <= $targetVersion; ++$v) { |
||
| 51 | $file = $sqlPath . 'version.' . $v . '.sql'; |
||
| 52 | if (is_file($file)) { |
||
| 53 | $sql .= "\n-- -------- VERSION $v BEGINS ------------------------\n"; |
||
| 54 | $sql .= file_get_contents($file); |
||
| 55 | $sql .= "\n-- -------- VERSION $v ENDS --------------------------\n"; |
||
| 56 | } else { |
||
| 57 | $missingVersions[] = $v; |
||
| 58 | } |
||
| 59 | } |
||
| 60 | |||
| 61 | $sql .= "\nCOMMIT;\n"; |
||
| 62 | |||
| 63 | if (count($missingVersions)) { |
||
| 64 | throw new Exception('Missing SQL file for versions: ' . implode(',', $missingVersions)); |
||
| 65 | } |
||
| 66 | |||
| 67 | return $sql; |
||
| 68 | } |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Executes a batch of SQL commands. |
||
| 72 | * (This is a workaround to Zend limitation to have only one command at once) |
||
| 73 | * |
||
| 74 | * @param string $sql to be executed |
||
| 75 | */ |
||
| 76 | function executeBatchSql($sql): void |
||
| 77 | { |
||
| 78 | $affectedRows = 0; |
||
| 79 | $queries = preg_split("/;+(?=([^'|^\\\']*['|\\\'][^'|^\\\']*['|\\\'])*[^'|^\\\']*[^'|^\\\']$)/", $sql); |
||
| 80 | foreach ($queries as $query) { |
||
| 81 | if (mb_strlen(trim($query)) > 0) { |
||
| 82 | try { |
||
| 83 | $result = Zend_Registry::get('db')->query($query); |
||
| 84 | } catch (\Exception $exception) { |
||
| 85 | echo 'FAILED QUERY: ' . $query . PHP_EOL; |
||
| 86 | |||
| 87 | throw $exception; |
||
| 88 | } |
||
| 89 | |||
| 90 | $affectedRows += $result->rowCount(); |
||
| 91 | } |
||
| 92 | } |
||
| 93 | |||
| 94 | echo "\n" . 'affected rows count: ' . $affectedRows . "\n"; |
||
| 95 | } |
||
| 96 | |||
| 97 | /** |
||
| 98 | * Do the actual update |
||
| 99 | */ |
||
| 100 | function doUpdate(): void |
||
| 101 | { |
||
| 102 | global $settingName; |
||
| 103 | |||
| 104 | try { |
||
| 105 | $currentVersion = (int) \mQueue\Model\Setting::get($settingName, 0)->value; |
||
| 106 | } catch (Exception $e) { |
||
| 107 | if (mb_strpos($e->getMessage(), 'SQLSTATE[42S02]') >= 0) { |
||
| 108 | $currentVersion = -1; |
||
| 109 | } else { |
||
| 110 | die('Caught exception: ' . $e->getMessage() . "\n"); |
||
|
0 ignored issues
–
show
|
|||
| 111 | } |
||
| 112 | } |
||
| 113 | |||
| 114 | $targetVersion = getPatchVersion(); |
||
| 115 | |||
| 116 | echo 'current version is: ' . $currentVersion . "\n"; |
||
| 117 | echo 'target version is : ' . $targetVersion . "\n"; |
||
| 118 | |||
| 119 | if ($currentVersion == $targetVersion) { |
||
| 120 | echo "already up-to-date\n"; |
||
| 121 | |||
| 122 | return; |
||
| 123 | } |
||
| 124 | |||
| 125 | $sql = buildSQL($currentVersion, $targetVersion); |
||
| 126 | echo $sql; |
||
| 127 | echo "\n_________________________________________________\n"; |
||
| 128 | echo "updating...\n"; |
||
| 129 | executeBatchSql($sql); |
||
| 130 | \mQueue\Model\Setting::set($settingName, $targetVersion); |
||
| 131 | |||
| 132 | echo "\nsuccessful update to version $targetVersion !\n"; |
||
| 133 | } |
||
| 134 | |||
| 135 | doUpdate(); |
||
| 136 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.