Update.class.php (4270B)
1 <?php 2 3 namespace cms\update; 4 5 use cms\base\Startup; 6 use cms\base\Version; 7 use database\Database; 8 use Exception; 9 use logger\Logger; 10 11 12 class Update 13 { 14 // This is the required DB version: 15 const SUPPORTED_VERSION = 31; 16 // -----------------------^^----------------------------- 17 18 const STATUS_UPDATE_PROGRESS = 0; 19 const STATUS_UPDATE_SUCCESS = 1; 20 21 /** 22 * Detects if the database must be upgraded. 23 * 24 * @param Database $db 25 * @return bool true if database must be updated 26 */ 27 public function isUpdateRequired(Database $db) 28 { 29 $version = $this->getDbVersion($db); 30 31 Logger::debug("Need DB-Version: " . self::SUPPORTED_VERSION . "; Actual DB-Version: " . $version); 32 33 if ($version == self::SUPPORTED_VERSION) 34 // Cool, der aktuelle DB-Stand passt zu dieser Version. Das ist auch der Normalfall. Weiter so. 35 return false; 36 37 elseif ($version > self::SUPPORTED_VERSION) 38 // Oh oh, in der Datenbank ist eine neuere Version, als wir unterstützen. 39 throw new \LogicException('Actual DB version is not supported. ' . "DB-Version is $version, but " . Startup::TITLE . " " . Startup::VERSION . " only supports version " . self::SUPPORTED_VERSION); 40 41 else 42 return true; // Update required. 43 } 44 45 46 /** 47 * Update the database to a newer version. 48 * 49 * @param Database $db 50 */ 51 public function update(Database $db) 52 { 53 $version = $this->getDbVersion($db); 54 55 56 for ($installVersion = $version + 1; $installVersion <= self::SUPPORTED_VERSION; $installVersion++) { 57 if ($installVersion > 2) // Up to version 2 there was no table 'version'. 58 { 59 $db->start(); 60 $sql = $db->sql('INSERT INTO {{version}} (id,version,status,installed) VALUES( {id},{version},{status},{time} )', $db->id); 61 $sql->setInt('id', $installVersion); 62 $sql->setInt('version', $installVersion); 63 $sql->setInt('status', self::STATUS_UPDATE_PROGRESS); 64 $sql->setInt('time', time()); 65 $sql->execute(); 66 $db->commit(); 67 } 68 69 $updaterClassName = __NAMESPACE__.'\version\DBVersion' . str_pad($installVersion, 6, '0', STR_PAD_LEFT); 70 71 $db->start(); 72 /** @var \database\DbVersion $updater */ 73 $updater = new $updaterClassName($db); 74 75 $updater->update(); 76 $db->commit(); 77 78 if ($installVersion > 2) { 79 $db->start(); 80 $sql = $db->sql('UPDATE {{version}} SET status={status},installed={time} WHERE version={version}', $db->id); 81 $sql->setInt('status', self::STATUS_UPDATE_SUCCESS); 82 $sql->setInt('version', $installVersion); 83 $sql->setInt('time', time()); 84 $sql->execute(); 85 $db->commit(); 86 } 87 } 88 } 89 90 91 /** 92 * Detects the actual version of the database scheme. 93 * 94 * @param Database $db 95 * @return int 96 */ 97 private function getDbVersion(Database $db) 98 { 99 $versionTableExists = $this->testQuery($db, 'SELECT 1 FROM {{version}}'); 100 101 if ($versionTableExists) { 102 // Prüfen, ob die vorherigen Updates fehlerfrei sind. 103 $sql = $db->sql(<<<SQL 104 SELECT COUNT(*) FROM {{version}} WHERE STATUS=0 105 SQL 106 , $db->id); 107 $countErrors = $sql->getOne(); 108 if ($countErrors > 0) 109 throw new \LogicException('Database error: There are dirty versions (means: versions with status 0), see table VERSION for details.'); 110 111 // Aktuelle Version ermitteln. 112 $sql = $db->sql(<<<SQL 113 SELECT MAX(version) FROM {{version}} 114 SQL 115 , $db->id); 116 $version = $sql->getOne(); 117 118 if (is_numeric($version)) 119 return $version; // Aktuelle Version.s 120 else 121 // Tabelle 'version' ist noch leer. 122 // Tabelle 'version' wurde in Version 2 angelegt. 123 return 2; 124 } else { 125 // no version table exists. 126 127 // find out if there is the project table... 128 $projectTableExists = $this->testQuery($db, 'SELECT 1 FROM {{project}}'); 129 130 if ($projectTableExists) 131 // seems to be the old baseline version without a version table. 132 return 1; 133 else 134 // there are no tables, everything must be created. 135 return 0; 136 } 137 } 138 139 140 /** 141 * Stellt fest, ob eine DB-Anfrage funktioniert. 142 * 143 * @param $db Database 144 * @param $sql 145 * @return <code>true</code> falls SQL funktioniert. 146 */ 147 private function testQuery($db, $sql) 148 { 149 try { 150 $sql = $db->sql($sql, $db->id); 151 $sql->execute(); 152 return true; // Bisher alles ok? Dann funktioniert die Query. 153 } catch (Exception $e) { 154 // Query funktioniert nicht. 155 return false; 156 } 157 } 158 } 159 160 ?>