diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseController.php b/src/applications/config/controller/PhabricatorConfigDatabaseController.php index c17b877082..37a8700834 100644 --- a/src/applications/config/controller/PhabricatorConfigDatabaseController.php +++ b/src/applications/config/controller/PhabricatorConfigDatabaseController.php @@ -1,70 +1,67 @@ setUser($conf->getUser()) ->setHost($conf->getHost()) ->setPort($conf->getPort()) ->setNamespace(PhabricatorLiskDAO::getDefaultStorageNamespace()) ->setPassword($conf->getPassword()); $query = id(new PhabricatorConfigSchemaQuery()) ->setAPI($api); return $query; } protected function renderIcon($status) { switch ($status) { case PhabricatorConfigStorageSchema::STATUS_OKAY: $icon = 'fa-check-circle green'; break; - case PhabricatorConfigStorageSchema::STATUS_NOTE: - $icon = 'fa-info-circle blue'; - break; case PhabricatorConfigStorageSchema::STATUS_WARN: $icon = 'fa-exclamation-circle yellow'; break; case PhabricatorConfigStorageSchema::STATUS_FAIL: default: $icon = 'fa-times-circle red'; break; } return id(new PHUIIconView()) ->setIconFont($icon); } protected function renderAttr($attr, $issue) { if ($issue) { return phutil_tag( 'span', array( 'style' => 'color: #aa0000;', ), $attr); } else { return $attr; } } protected function renderBoolean($value) { if ($value === null) { return ''; } else if ($value === true) { return pht('Yes'); } else { return pht('No'); } } } diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php index 1997d660be..bac31c5033 100644 --- a/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php +++ b/src/applications/config/controller/PhabricatorConfigDatabaseIssueController.php @@ -1,176 +1,170 @@ getRequest(); $viewer = $request->getUser(); $query = $this->buildSchemaQuery(); $actual = $query->loadActualSchema(); $expect = $query->loadExpectedSchema(); $comp = $query->buildComparisonSchema($expect, $actual); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Database Issues')); // Collect all open issues. $issues = array(); foreach ($comp->getDatabases() as $database_name => $database) { foreach ($database->getLocalIssues() as $issue) { $issues[] = array( $database_name, null, null, null, $issue); } foreach ($database->getTables() as $table_name => $table) { foreach ($table->getLocalIssues() as $issue) { $issues[] = array( $database_name, $table_name, null, null, $issue); } foreach ($table->getColumns() as $column_name => $column) { foreach ($column->getLocalIssues() as $issue) { $issues[] = array( $database_name, $table_name, 'column', $column_name, $issue); } } foreach ($table->getKeys() as $key_name => $key) { foreach ($key->getLocalIssues() as $issue) { $issues[] = array( $database_name, $table_name, 'key', $key_name, $issue); } } } } // Sort all open issues so that the most severe issues appear first. $order = array(); $counts = array(); foreach ($issues as $key => $issue) { $const = $issue[4]; $status = PhabricatorConfigStorageSchema::getIssueStatus($const); $severity = PhabricatorConfigStorageSchema::getStatusSeverity($status); $order[$key] = sprintf( '~%d~%s%s%s', 9 - $severity, $issue[0], $issue[1], $issue[3]); if (empty($counts[$status])) { $counts[$status] = 0; } $counts[$status]++; } asort($order); $issues = array_select_keys($issues, array_keys($order)); // Render the issues. $rows = array(); foreach ($issues as $issue) { $const = $issue[4]; $database_link = phutil_tag( 'a', array( 'href' => $this->getApplicationURI('/database/'.$issue[0].'/'), ), $issue[0]); $rows[] = array( $this->renderIcon( PhabricatorConfigStorageSchema::getIssueStatus($const)), $database_link, $issue[1], $issue[2], $issue[3], PhabricatorConfigStorageSchema::getIssueDescription($const), ); } $table = id(new AphrontTableView($rows)) ->setHeaders( array( null, pht('Database'), pht('Table'), pht('Type'), pht('Column/Key'), pht('Issue'), )) ->setColumnClasses( array( null, null, null, null, null, 'wide', )); $errors = array(); $errors[] = pht( 'IMPORTANT: This feature is in development and the information below '. 'is not accurate! Ignore it for now. See T1191.'); if (isset($counts[PhabricatorConfigStorageSchema::STATUS_FAIL])) { $errors[] = pht( 'Detected %s serious issue(s) with the schemata.', new PhutilNumber($counts[PhabricatorConfigStorageSchema::STATUS_FAIL])); } if (isset($counts[PhabricatorConfigStorageSchema::STATUS_WARN])) { $errors[] = pht( 'Detected %s warning(s) with the schemata.', new PhutilNumber($counts[PhabricatorConfigStorageSchema::STATUS_WARN])); } - if (isset($counts[PhabricatorConfigStorageSchema::STATUS_NOTE])) { - $errors[] = pht( - 'Detected %s minor issue(s) with the scheamata.', - new PhutilNumber($counts[PhabricatorConfigStorageSchema::STATUS_NOTE])); - } - $title = pht('Database Issues'); $table_box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->setFormErrors($errors) ->appendChild($table); $nav = $this->buildSideNavView(); $nav->selectFilter('dbissue/'); $nav->appendChild( array( $crumbs, $table_box, )); return $this->buildApplicationPage( $nav, array( 'title' => $title, )); } } diff --git a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php index 15e41df900..6175f57d2f 100644 --- a/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php +++ b/src/applications/config/controller/PhabricatorConfigDatabaseStatusController.php @@ -1,741 +1,737 @@ database = idx($data, 'database'); $this->table = idx($data, 'table'); $this->column = idx($data, 'column'); $this->key = idx($data, 'key'); } public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); $query = $this->buildSchemaQuery(); $actual = $query->loadActualSchema(); $expect = $query->loadExpectedSchema(); $comp = $query->buildComparisonSchema($expect, $actual); if ($this->column) { return $this->renderColumn( $comp, $expect, $actual, $this->database, $this->table, $this->column); } else if ($this->key) { return $this->renderKey( $comp, $expect, $actual, $this->database, $this->table, $this->key); } else if ($this->table) { return $this->renderTable( $comp, $expect, $actual, $this->database, $this->table); } else if ($this->database) { return $this->renderDatabase( $comp, $expect, $actual, $this->database); } else { return $this->renderServer( $comp, $expect, $actual); } } private function buildResponse($title, $body) { $nav = $this->buildSideNavView(); $nav->selectFilter('database/'); $crumbs = $this->buildApplicationCrumbs(); if ($this->database) { $crumbs->addTextCrumb( pht('Database Status'), $this->getApplicationURI('database/')); if ($this->table) { $crumbs->addTextCrumb( $this->database, $this->getApplicationURI('database/'.$this->database.'/')); if ($this->column || $this->key) { $crumbs->addTextCrumb( $this->table, $this->getApplicationURI( 'database/'.$this->database.'/'.$this->table.'/')); if ($this->column) { $crumbs->addTextCrumb($this->column); } else { $crumbs->addTextCrumb($this->key); } } else { $crumbs->addTextCrumb($this->table); } } else { $crumbs->addTextCrumb($this->database); } } else { $crumbs->addTextCrumb(pht('Database Status')); } $nav->setCrumbs($crumbs); $nav->appendChild($body); return $this->buildApplicationPage( $nav, array( 'title' => $title, )); } private function renderServer( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual) { $charset_issue = PhabricatorConfigStorageSchema::ISSUE_CHARSET; $collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION; $rows = array(); foreach ($comp->getDatabases() as $database_name => $database) { $actual_database = $actual->getDatabase($database_name); if ($actual_database) { $charset = $actual_database->getCharacterSet(); $collation = $actual_database->getCollation(); } else { $charset = null; $collation = null; } $status = $database->getStatus(); $issues = $database->getIssues(); $rows[] = array( $this->renderIcon($status), phutil_tag( 'a', array( 'href' => $this->getApplicationURI( '/database/'.$database_name.'/'), ), $database_name), $this->renderAttr($charset, $database->hasIssue($charset_issue)), $this->renderAttr($collation, $database->hasIssue($collation_issue)), ); } $table = id(new AphrontTableView($rows)) ->setHeaders( array( null, pht('Database'), pht('Charset'), pht('Collation'), )) ->setColumnClasses( array( null, 'wide pri', null, null, )); $title = pht('Database Status'); $properties = $this->buildProperties( array( ), $comp->getIssues()); $box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->addPropertyList($properties) ->appendChild($table); return $this->buildResponse($title, $box); } private function renderDatabase( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual, $database_name) { $collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION; $database = $comp->getDatabase($database_name); if (!$database) { return new Aphront404Response(); } $rows = array(); foreach ($database->getTables() as $table_name => $table) { $status = $table->getStatus(); $rows[] = array( $this->renderIcon($status), phutil_tag( 'a', array( 'href' => $this->getApplicationURI( '/database/'.$database_name.'/'.$table_name.'/'), ), $table_name), $this->renderAttr( $table->getCollation(), $table->hasIssue($collation_issue)), ); } $table = id(new AphrontTableView($rows)) ->setHeaders( array( null, pht('Table'), pht('Collation'), )) ->setColumnClasses( array( null, 'wide pri', null, )); $title = pht('Database Status: %s', $database_name); $actual_database = $actual->getDatabase($database_name); if ($actual_database) { $actual_charset = $actual_database->getCharacterSet(); $actual_collation = $actual_database->getCollation(); } else { $actual_charset = null; $actual_collation = null; } $expect_database = $expect->getDatabase($database_name); if ($expect_database) { $expect_charset = $expect_database->getCharacterSet(); $expect_collation = $expect_database->getCollation(); } else { $expect_charset = null; $expect_collation = null; } $properties = $this->buildProperties( array( array( pht('Character Set'), $actual_charset, ), array( pht('Expected Character Set'), $expect_charset, ), array( pht('Collation'), $actual_collation, ), array( pht('Expected Collation'), $expect_collation, ), ), $database->getIssues()); $box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->addPropertyList($properties) ->appendChild($table); return $this->buildResponse($title, $box); } private function renderTable( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual, $database_name, $table_name) { $type_issue = PhabricatorConfigStorageSchema::ISSUE_COLUMNTYPE; $charset_issue = PhabricatorConfigStorageSchema::ISSUE_CHARSET; $collation_issue = PhabricatorConfigStorageSchema::ISSUE_COLLATION; $nullable_issue = PhabricatorConfigStorageSchema::ISSUE_NULLABLE; $unique_issue = PhabricatorConfigStorageSchema::ISSUE_UNIQUE; $columns_issue = PhabricatorConfigStorageSchema::ISSUE_KEYCOLUMNS; $database = $comp->getDatabase($database_name); if (!$database) { return new Aphront404Response(); } $table = $database->getTable($table_name); if (!$table) { return new Aphront404Response(); } $actual_database = $actual->getDatabase($database_name); $actual_table = null; if ($actual_database) { $actual_table = $actual_database->getTable($table_name); } $expect_database = $expect->getDatabase($database_name); $expect_table = null; if ($expect_database) { $expect_table = $expect_database->getTable($table_name); } $rows = array(); foreach ($table->getColumns() as $column_name => $column) { $expect_column = null; if ($expect_table) { $expect_column = $expect_table->getColumn($column_name); } $status = $column->getStatus(); $data_type = null; if ($expect_column) { $data_type = $expect_column->getDataType(); } $rows[] = array( $this->renderIcon($status), phutil_tag( 'a', array( 'href' => $this->getApplicationURI( 'database/'. $database_name.'/'. $table_name.'/'. 'col/'. $column_name.'/'), ), $column_name), $data_type, $this->renderAttr( $column->getColumnType(), $column->hasIssue($type_issue)), $this->renderAttr( $this->renderBoolean($column->getNullable()), $column->hasIssue($nullable_issue)), $this->renderAttr( $column->getCharacterSet(), $column->hasIssue($charset_issue)), $this->renderAttr( $column->getCollation(), $column->hasIssue($collation_issue)), ); } $table_view = id(new AphrontTableView($rows)) ->setHeaders( array( null, pht('Column'), pht('Data Type'), pht('Column Type'), pht('Nullable'), pht('Character Set'), pht('Collation'), )) ->setColumnClasses( array( null, 'wide pri', null, null, null, null )); $key_rows = array(); foreach ($table->getKeys() as $key_name => $key) { $expect_key = null; if ($expect_table) { $expect_key = $expect_table->getKey($key_name); } $status = $key->getStatus(); $size = 0; foreach ($key->getColumnNames() as $column_spec) { list($column_name, $prefix) = $key->getKeyColumnAndPrefix($column_spec); $column = $table->getColumn($column_name); if (!$column) { $size = 0; break; } $size += $column->getKeyByteLength($prefix); } $size_formatted = null; if ($size) { $size_formatted = $this->renderAttr( $size, ($size > self::MAX_INNODB_KEY_LENGTH)); } $key_rows[] = array( $this->renderIcon($status), phutil_tag( 'a', array( 'href' => $this->getApplicationURI( 'database/'. $database_name.'/'. $table_name.'/'. 'key/'. $key_name.'/'), ), $key_name), $this->renderAttr( implode(', ', $key->getColumnNames()), $key->hasIssue($columns_issue)), $this->renderAttr( $this->renderBoolean($key->getUnique()), $key->hasIssue($unique_issue)), $size_formatted, ); } $keys_view = id(new AphrontTableView($key_rows)) ->setHeaders( array( null, pht('Key'), pht('Columns'), pht('Unique'), pht('Size'), )) ->setColumnClasses( array( null, 'wide pri', null, null, null, )); $title = pht('Database Status: %s.%s', $database_name, $table_name); if ($actual_table) { $actual_collation = $actual_table->getCollation(); } else { $actual_collation = null; } if ($expect_table) { $expect_collation = $expect_table->getCollation(); } else { $expect_collation = null; } $properties = $this->buildProperties( array( array( pht('Collation'), $actual_collation, ), array( pht('Expected Collation'), $expect_collation, ), ), $table->getIssues()); $box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->addPropertyList($properties) ->appendChild($table_view) ->appendChild($keys_view); return $this->buildResponse($title, $box); } private function renderColumn( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual, $database_name, $table_name, $column_name) { $database = $comp->getDatabase($database_name); if (!$database) { return new Aphront404Response(); } $table = $database->getTable($table_name); if (!$table) { return new Aphront404Response(); } $column = $table->getColumn($column_name); if (!$column) { return new Aphront404Response(); } $actual_database = $actual->getDatabase($database_name); $actual_table = null; $actual_column = null; if ($actual_database) { $actual_table = $actual_database->getTable($table_name); if ($actual_table) { $actual_column = $actual_table->getColumn($column_name); } } $expect_database = $expect->getDatabase($database_name); $expect_table = null; $expect_column = null; if ($expect_database) { $expect_table = $expect_database->getTable($table_name); if ($expect_table) { $expect_column = $expect_table->getColumn($column_name); } } if ($actual_column) { $actual_coltype = $actual_column->getColumnType(); $actual_charset = $actual_column->getCharacterSet(); $actual_collation = $actual_column->getCollation(); $actual_nullable = $actual_column->getNullable(); } else { $actual_coltype = null; $actual_charset = null; $actual_collation = null; $actual_nullable = null; } if ($expect_column) { $data_type = $expect_column->getDataType(); $expect_coltype = $expect_column->getColumnType(); $expect_charset = $expect_column->getCharacterSet(); $expect_collation = $expect_column->getCollation(); $expect_nullable = $expect_column->getNullable(); } else { $data_type = null; $expect_coltype = null; $expect_charset = null; $expect_collation = null; $expect_nullable = null; } $title = pht( 'Database Status: %s.%s.%s', $database_name, $table_name, $column_name); $properties = $this->buildProperties( array( array( pht('Data Type'), $data_type, ), array( pht('Column Type'), $actual_coltype, ), array( pht('Expected Column Type'), $expect_coltype, ), array( pht('Character Set'), $actual_charset, ), array( pht('Expected Character Set'), $expect_charset, ), array( pht('Collation'), $actual_collation, ), array( pht('Expected Collation'), $expect_collation, ), array( pht('Nullable'), $this->renderBoolean($actual_nullable), ), array( pht('Expected Nullable'), $this->renderBoolean($expect_nullable), ), ), $column->getIssues()); $box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->addPropertyList($properties); return $this->buildResponse($title, $box); } private function renderKey( PhabricatorConfigServerSchema $comp, PhabricatorConfigServerSchema $expect, PhabricatorConfigServerSchema $actual, $database_name, $table_name, $key_name) { $database = $comp->getDatabase($database_name); if (!$database) { return new Aphront404Response(); } $table = $database->getTable($table_name); if (!$table) { return new Aphront404Response(); } $key = $table->getKey($key_name); if (!$key) { return new Aphront404Response(); } $actual_database = $actual->getDatabase($database_name); $actual_table = null; $actual_key = null; if ($actual_database) { $actual_table = $actual_database->getTable($table_name); if ($actual_table) { $actual_key = $actual_table->getKey($key_name); } } $expect_database = $expect->getDatabase($database_name); $expect_table = null; $expect_key = null; if ($expect_database) { $expect_table = $expect_database->getTable($table_name); if ($expect_table) { $expect_key = $expect_table->getKey($key_name); } } if ($actual_key) { $actual_columns = $actual_key->getColumnNames(); $actual_unique = $actual_key->getUnique(); } else { $actual_columns = array(); $actual_unique = null; } if ($expect_key) { $expect_columns = $expect_key->getColumnNames(); $expect_unique = $expect_key->getUnique(); } else { $expect_columns = array(); $expect_unique = null; } $title = pht( 'Database Status: %s.%s (%s)', $database_name, $table_name, $key_name); $properties = $this->buildProperties( array( array( pht('Unique'), $this->renderBoolean($actual_unique), ), array( pht('Expected Unique'), $this->renderBoolean($expect_unique), ), array( pht('Columns'), implode(', ', $actual_columns), ), array( pht('Expected Columns'), implode(', ', $expect_columns), ), ), $key->getIssues()); $box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->addPropertyList($properties); return $this->buildResponse($title, $box); } private function buildProperties(array $properties, array $issues) { $view = id(new PHUIPropertyListView()) ->setUser($this->getRequest()->getUser()); foreach ($properties as $property) { list($key, $value) = $property; $view->addProperty($key, $value); } $status_view = new PHUIStatusListView(); if (!$issues) { $status_view->addItem( id(new PHUIStatusItemView()) ->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green') ->setTarget(pht('No Schema Issues'))); } else { foreach ($issues as $issue) { $note = PhabricatorConfigStorageSchema::getIssueDescription($issue); $status = PhabricatorConfigStorageSchema::getIssueStatus($issue); switch ($status) { - case PhabricatorConfigStorageSchema::STATUS_NOTE: - $icon = PHUIStatusItemView::ICON_INFO; - $color = 'blue'; - break; case PhabricatorConfigStorageSchema::STATUS_WARN: $icon = PHUIStatusItemView::ICON_WARNING; $color = 'yellow'; break; case PhabricatorConfigStorageSchema::STATUS_FAIL: default: $icon = PHUIStatusItemView::ICON_REJECT; $color = 'red'; break; } $item = id(new PHUIStatusItemView()) ->setTarget(PhabricatorConfigStorageSchema::getIssueName($issue)) ->setIcon($icon, $color) ->setNote($note); $status_view->addItem($item); } } $view->addProperty(pht('Schema Status'), $status_view); return $view; } } diff --git a/src/applications/config/schema/PhabricatorConfigStorageSchema.php b/src/applications/config/schema/PhabricatorConfigStorageSchema.php index 61475ae350..367b67f962 100644 --- a/src/applications/config/schema/PhabricatorConfigStorageSchema.php +++ b/src/applications/config/schema/PhabricatorConfigStorageSchema.php @@ -1,219 +1,206 @@ getName() != $expect->getName()) { throw new Exception(pht('Names must match to compare schemata!')); } return $this->compareToSimilarSchema($expect); } public function setName($name) { $this->name = $name; return $this; } public function getName() { return $this->name; } public function setIssues(array $issues) { $this->issues = array_fuse($issues); return $this; } public function getIssues() { $issues = $this->issues; foreach ($this->getSubschemata() as $sub) { switch ($sub->getStatus()) { - case self::STATUS_NOTE: - $issues[self::ISSUE_SUBNOTE] = self::ISSUE_SUBNOTE; - break; case self::STATUS_WARN: $issues[self::ISSUE_SUBWARN] = self::ISSUE_SUBWARN; break; case self::STATUS_FAIL: $issues[self::ISSUE_SUBFAIL] = self::ISSUE_SUBFAIL; break; } } return $issues; } public function getLocalIssues() { return $this->issues; } public function hasIssue($issue) { return (bool)idx($this->getIssues(), $issue); } public function getAllIssues() { $issues = $this->getIssues(); foreach ($this->getSubschemata() as $sub) { $issues += $sub->getAllIssues(); } return $issues; } public function getStatus() { $status = self::STATUS_OKAY; foreach ($this->getAllIssues() as $issue) { $issue_status = self::getIssueStatus($issue); $status = self::getStrongestStatus($status, $issue_status); } return $status; } public static function getIssueName($issue) { switch ($issue) { case self::ISSUE_MISSING: return pht('Missing'); case self::ISSUE_MISSINGKEY: return pht('Missing Key'); case self::ISSUE_SURPLUS: return pht('Surplus'); case self::ISSUE_SURPLUSKEY: return pht('Surplus Key'); case self::ISSUE_CHARSET: return pht('Better Character Set Available'); case self::ISSUE_COLLATION: return pht('Better Collation Available'); case self::ISSUE_COLUMNTYPE: return pht('Wrong Column Type'); case self::ISSUE_NULLABLE: return pht('Wrong Nullable Setting'); case self::ISSUE_KEYCOLUMNS: return pht('Key on Wrong Columns'); case self::ISSUE_UNIQUE: return pht('Key has Wrong Uniqueness'); - case self::ISSUE_SUBNOTE: - return pht('Subschemata Have Notices'); case self::ISSUE_SUBWARN: return pht('Subschemata Have Warnings'); case self::ISSUE_SUBFAIL: return pht('Subschemata Have Failures'); default: throw new Exception(pht('Unknown schema issue "%s"!', $issue)); } } public static function getIssueDescription($issue) { switch ($issue) { case self::ISSUE_MISSING: return pht('This schema is expected to exist, but does not.'); case self::ISSUE_MISSINGKEY: return pht('This key is expected to exist, but does not.'); case self::ISSUE_SURPLUS: return pht('This schema is not expected to exist.'); case self::ISSUE_SURPLUSKEY: return pht('This key is not expected to exist.'); case self::ISSUE_CHARSET: return pht('This schema can use a better character set.'); case self::ISSUE_COLLATION: return pht('This schema can use a better collation.'); case self::ISSUE_COLUMNTYPE: return pht('This schema can use a better column type.'); case self::ISSUE_NULLABLE: return pht('This schema has the wrong nullable setting.'); case self::ISSUE_KEYCOLUMNS: return pht('This schema is on the wrong columns.'); case self::ISSUE_UNIQUE: return pht('This key has the wrong uniqueness setting.'); - case self::ISSUE_SUBNOTE: - return pht('Subschemata have setup notices.'); case self::ISSUE_SUBWARN: return pht('Subschemata have setup warnings.'); case self::ISSUE_SUBFAIL: return pht('Subschemata have setup failures.'); default: throw new Exception(pht('Unknown schema issue "%s"!', $issue)); } } public static function getIssueStatus($issue) { switch ($issue) { case self::ISSUE_MISSING: case self::ISSUE_SURPLUS: - case self::ISSUE_SUBFAIL: case self::ISSUE_NULLABLE: + case self::ISSUE_SUBFAIL: return self::STATUS_FAIL; case self::ISSUE_SUBWARN: case self::ISSUE_COLUMNTYPE: - return self::STATUS_WARN; - case self::ISSUE_SUBNOTE: case self::ISSUE_CHARSET: case self::ISSUE_COLLATION: case self::ISSUE_MISSINGKEY: case self::ISSUE_SURPLUSKEY: case self::ISSUE_UNIQUE: case self::ISSUE_KEYCOLUMNS: - return self::STATUS_NOTE; + return self::STATUS_WARN; default: throw new Exception(pht('Unknown schema issue "%s"!', $issue)); } } public static function getStatusSeverity($status) { switch ($status) { case self::STATUS_FAIL: - return 3; - case self::STATUS_WARN: return 2; - case self::STATUS_NOTE: + case self::STATUS_WARN: return 1; case self::STATUS_OKAY: return 0; default: throw new Exception(pht('Unknown schema status "%s"!', $status)); } } public static function getStrongestStatus($u, $v) { $u_sev = self::getStatusSeverity($u); $v_sev = self::getStatusSeverity($v); if ($u_sev >= $v_sev) { return $u; } else { return $v; } } }