[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/infrastructure/storage/management/ -> PhabricatorStorageManagementAPI.php (source)

   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  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1