[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class PhabricatorStorageManagementAPI { 4 5 private $host; 6 private $user; 7 private $port; 8 private $password; 9 private $namespace; 10 private $conns = array(); 11 private $disableUTF8MB4; 12 13 const CHARSET_DEFAULT = 'CHARSET'; 14 const CHARSET_FULLTEXT = 'CHARSET_FULLTEXT'; 15 const COLLATE_TEXT = 'COLLATE_TEXT'; 16 const COLLATE_SORT = 'COLLATE_SORT'; 17 const COLLATE_FULLTEXT = 'COLLATE_FULLTEXT'; 18 19 public function setDisableUTF8MB4($disable_utf8_mb4) { 20 $this->disableUTF8MB4 = $disable_utf8_mb4; 21 return $this; 22 } 23 24 public function getDisableUTF8MB4() { 25 return $this->disableUTF8MB4; 26 } 27 28 public function setNamespace($namespace) { 29 $this->namespace = $namespace; 30 PhabricatorLiskDAO::pushStorageNamespace($namespace); 31 return $this; 32 } 33 34 public function getNamespace() { 35 return $this->namespace; 36 } 37 38 public function setUser($user) { 39 $this->user = $user; 40 return $this; 41 } 42 43 public function getUser() { 44 return $this->user; 45 } 46 47 public function setPassword($password) { 48 $this->password = $password; 49 return $this; 50 } 51 52 public function getPassword() { 53 return $this->password; 54 } 55 56 public function setHost($host) { 57 $this->host = $host; 58 return $this; 59 } 60 61 public function getHost() { 62 return $this->host; 63 } 64 65 public function setPort($port) { 66 $this->port = $port; 67 return $this; 68 } 69 70 public function getPort() { 71 return $this->port; 72 } 73 74 public function getDatabaseName($fragment) { 75 return $this->namespace.'_'.$fragment; 76 } 77 78 public function getDatabaseList(array $patches, $only_living = false) { 79 assert_instances_of($patches, 'PhabricatorStoragePatch'); 80 81 $list = array(); 82 83 foreach ($patches as $patch) { 84 if ($patch->getType() == 'db') { 85 if ($only_living && $patch->isDead()) { 86 continue; 87 } 88 $list[] = $this->getDatabaseName($patch->getName()); 89 } 90 } 91 92 return $list; 93 } 94 95 public function getConn($fragment) { 96 $database = $this->getDatabaseName($fragment); 97 $return = &$this->conns[$this->host][$this->user][$database]; 98 if (!$return) { 99 $return = PhabricatorEnv::newObjectFromConfig( 100 'mysql.implementation', 101 array( 102 array( 103 'user' => $this->user, 104 'pass' => $this->password, 105 'host' => $this->host, 106 'port' => $this->port, 107 'database' => $fragment 108 ? $database 109 : null, 110 ), 111 )); 112 } 113 return $return; 114 } 115 116 public function getAppliedPatches() { 117 try { 118 $applied = queryfx_all( 119 $this->getConn('meta_data'), 120 'SELECT patch FROM patch_status'); 121 return ipull($applied, 'patch'); 122 } catch (AphrontQueryException $ex) { 123 return null; 124 } 125 } 126 127 public function createDatabase($fragment) { 128 $info = $this->getCharsetInfo(); 129 130 queryfx( 131 $this->getConn(null), 132 'CREATE DATABASE IF NOT EXISTS %T COLLATE %T', 133 $this->getDatabaseName($fragment), 134 $info[self::COLLATE_TEXT]); 135 } 136 137 public function createTable($fragment, $table, array $cols) { 138 queryfx( 139 $this->getConn($fragment), 140 'CREATE TABLE IF NOT EXISTS %T.%T (%Q) '. 141 'ENGINE=InnoDB, COLLATE utf8_general_ci', 142 $this->getDatabaseName($fragment), 143 $table, 144 implode(', ', $cols)); 145 } 146 147 public function getLegacyPatches(array $patches) { 148 assert_instances_of($patches, 'PhabricatorStoragePatch'); 149 150 try { 151 $row = queryfx_one( 152 $this->getConn('meta_data'), 153 'SELECT version FROM %T', 154 'schema_version'); 155 $version = $row['version']; 156 } catch (AphrontQueryException $ex) { 157 return array(); 158 } 159 160 $legacy = array(); 161 foreach ($patches as $key => $patch) { 162 if ($patch->getLegacy() !== false && $patch->getLegacy() <= $version) { 163 $legacy[] = $key; 164 } 165 } 166 167 return $legacy; 168 } 169 170 public function markPatchApplied($patch) { 171 queryfx( 172 $this->getConn('meta_data'), 173 'INSERT INTO %T (patch, applied) VALUES (%s, %d)', 174 'patch_status', 175 $patch, 176 time()); 177 } 178 179 public function applyPatch(PhabricatorStoragePatch $patch) { 180 $type = $patch->getType(); 181 $name = $patch->getName(); 182 switch ($type) { 183 case 'db': 184 $this->createDatabase($name); 185 break; 186 case 'sql': 187 $this->applyPatchSQL($name); 188 break; 189 case 'php': 190 $this->applyPatchPHP($name); 191 break; 192 default: 193 throw new Exception("Unable to apply patch of type '{$type}'."); 194 } 195 } 196 197 public function applyPatchSQL($sql) { 198 $sql = Filesystem::readFile($sql); 199 $queries = preg_split('/;\s+/', $sql); 200 $queries = array_filter($queries); 201 202 $conn = $this->getConn(null); 203 204 $charset_info = $this->getCharsetInfo(); 205 foreach ($charset_info as $key => $value) { 206 $charset_info[$key] = qsprintf($conn, '%T', $value); 207 } 208 209 foreach ($queries as $query) { 210 $query = str_replace('{$NAMESPACE}', $this->namespace, $query); 211 212 foreach ($charset_info as $key => $value) { 213 $query = str_replace('{$'.$key.'}', $value, $query); 214 } 215 216 queryfx( 217 $conn, 218 '%Q', 219 $query); 220 } 221 } 222 223 public function applyPatchPHP($script) { 224 $schema_conn = $this->getConn(null); 225 require_once $script; 226 } 227 228 public function isCharacterSetAvailable($character_set) { 229 if ($character_set == 'utf8mb4') { 230 if ($this->getDisableUTF8MB4()) { 231 return false; 232 } 233 } 234 235 $conn = $this->getConn(null); 236 237 $result = queryfx_one( 238 $conn, 239 'SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.CHARACTER_SETS 240 WHERE CHARACTER_SET_NAME = %s', 241 $character_set); 242 243 return (bool)$result; 244 } 245 246 public function getCharsetInfo() { 247 if ($this->isCharacterSetAvailable('utf8mb4')) { 248 // If utf8mb4 is available, we use it with the utf8mb4_unicode_ci 249 // collation. This is most correct, and will sort properly. 250 251 $charset = 'utf8mb4'; 252 $charset_full = 'utf8mb4'; 253 $collate_text = 'utf8mb4_bin'; 254 $collate_sort = 'utf8mb4_unicode_ci'; 255 $collate_full = 'utf8mb4_unicode_ci'; 256 } else { 257 // If utf8mb4 is not available, we use binary. This allows us to store 258 // 4-byte unicode characters. This has some tradeoffs: 259 // 260 // Unicode characters won't sort correctly. There's nothing we can do 261 // about this while still supporting 4-byte characters. 262 // 263 // It's possible that strings will be truncated in the middle of a 264 // character on insert. We encourage users to set STRICT_ALL_TABLES 265 // to prevent this. 266 // 267 // There's no valid collation we can use to get a fulltext index on 268 // 4-byte unicode characters: we can't add a fulltext key to a binary 269 // column. 270 271 $charset = 'binary'; 272 $charset_full = 'utf8'; 273 $collate_text = 'binary'; 274 $collate_sort = 'binary'; 275 $collate_full = 'utf8_general_ci'; 276 } 277 278 return array( 279 self::CHARSET_DEFAULT => $charset, 280 self::CHARSET_FULLTEXT => $charset_full, 281 self::COLLATE_TEXT => $collate_text, 282 self::COLLATE_SORT => $collate_sort, 283 self::COLLATE_FULLTEXT => $collate_full, 284 ); 285 } 286 287 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |