diff options
-rw-r--r-- | autoload.php | 9 | ||||
-rw-r--r-- | includes/installer/ConnectionStatus.php | 23 | ||||
-rw-r--r-- | includes/installer/DatabaseConnectForm.php | 71 | ||||
-rw-r--r-- | includes/installer/DatabaseForm.php | 152 | ||||
-rw-r--r-- | includes/installer/DatabaseInstaller.php | 255 | ||||
-rw-r--r-- | includes/installer/DatabaseSettingsForm.php | 89 | ||||
-rw-r--r-- | includes/installer/Installer.php | 3 | ||||
-rw-r--r-- | includes/installer/MysqlConnectForm.php | 74 | ||||
-rw-r--r-- | includes/installer/MysqlInstaller.php | 171 | ||||
-rw-r--r-- | includes/installer/MysqlSettingsForm.php | 100 | ||||
-rw-r--r-- | includes/installer/PostgresConnectForm.php | 104 | ||||
-rw-r--r-- | includes/installer/PostgresInstaller.php | 216 | ||||
-rw-r--r-- | includes/installer/PostgresSettingsForm.php | 96 | ||||
-rw-r--r-- | includes/installer/SqliteConnectForm.php | 46 | ||||
-rw-r--r-- | includes/installer/SqliteInstaller.php | 54 | ||||
-rw-r--r-- | includes/installer/WebInstallerDBConnect.php | 4 | ||||
-rw-r--r-- | includes/installer/WebInstallerDBSettings.php | 9 |
17 files changed, 832 insertions, 644 deletions
diff --git a/autoload.php b/autoload.php index b3046a8b5335..0d06e43da5e6 100644 --- a/autoload.php +++ b/autoload.php @@ -1549,7 +1549,11 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\Http\\MwHttpRequestToResponseInterfaceAdapter' => __DIR__ . '/includes/http/MwHttpRequestToResponseInterfaceAdapter.php', 'MediaWiki\\Http\\Telemetry' => __DIR__ . '/includes/http/Telemetry.php', 'MediaWiki\\Installer\\CliInstaller' => __DIR__ . '/includes/installer/CliInstaller.php', + 'MediaWiki\\Installer\\ConnectionStatus' => __DIR__ . '/includes/installer/ConnectionStatus.php', + 'MediaWiki\\Installer\\DatabaseConnectForm' => __DIR__ . '/includes/installer/DatabaseConnectForm.php', + 'MediaWiki\\Installer\\DatabaseForm' => __DIR__ . '/includes/installer/DatabaseForm.php', 'MediaWiki\\Installer\\DatabaseInstaller' => __DIR__ . '/includes/installer/DatabaseInstaller.php', + 'MediaWiki\\Installer\\DatabaseSettingsForm' => __DIR__ . '/includes/installer/DatabaseSettingsForm.php', 'MediaWiki\\Installer\\DatabaseUpdater' => __DIR__ . '/includes/installer/DatabaseUpdater.php', 'MediaWiki\\Installer\\Hook\\LoadExtensionSchemaUpdatesHook' => __DIR__ . '/includes/installer/Hook/LoadExtensionSchemaUpdatesHook.php', 'MediaWiki\\Installer\\InstallDocFormatter' => __DIR__ . '/includes/installer/InstallDocFormatter.php', @@ -1558,11 +1562,16 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\Installer\\InstallerOverrides' => __DIR__ . '/includes/installer/InstallerOverrides.php', 'MediaWiki\\Installer\\InstallerSessionProvider' => __DIR__ . '/includes/installer/InstallerSessionProvider.php', 'MediaWiki\\Installer\\LocalSettingsGenerator' => __DIR__ . '/includes/installer/LocalSettingsGenerator.php', + 'MediaWiki\\Installer\\MysqlConnectForm' => __DIR__ . '/includes/installer/MysqlConnectForm.php', 'MediaWiki\\Installer\\MysqlInstaller' => __DIR__ . '/includes/installer/MysqlInstaller.php', + 'MediaWiki\\Installer\\MysqlSettingsForm' => __DIR__ . '/includes/installer/MysqlSettingsForm.php', 'MediaWiki\\Installer\\MysqlUpdater' => __DIR__ . '/includes/installer/MysqlUpdater.php', 'MediaWiki\\Installer\\Pingback' => __DIR__ . '/includes/installer/Pingback.php', + 'MediaWiki\\Installer\\PostgresConnectForm' => __DIR__ . '/includes/installer/PostgresConnectForm.php', 'MediaWiki\\Installer\\PostgresInstaller' => __DIR__ . '/includes/installer/PostgresInstaller.php', + 'MediaWiki\\Installer\\PostgresSettingsForm' => __DIR__ . '/includes/installer/PostgresSettingsForm.php', 'MediaWiki\\Installer\\PostgresUpdater' => __DIR__ . '/includes/installer/PostgresUpdater.php', + 'MediaWiki\\Installer\\SqliteConnectForm' => __DIR__ . '/includes/installer/SqliteConnectForm.php', 'MediaWiki\\Installer\\SqliteInstaller' => __DIR__ . '/includes/installer/SqliteInstaller.php', 'MediaWiki\\Installer\\SqliteUpdater' => __DIR__ . '/includes/installer/SqliteUpdater.php', 'MediaWiki\\Installer\\WebInstaller' => __DIR__ . '/includes/installer/WebInstaller.php', diff --git a/includes/installer/ConnectionStatus.php b/includes/installer/ConnectionStatus.php new file mode 100644 index 000000000000..2e255f4204b4 --- /dev/null +++ b/includes/installer/ConnectionStatus.php @@ -0,0 +1,23 @@ +<?php + +namespace MediaWiki\Installer; + +use Status; +use Wikimedia\Rdbms\Database; + +/** + * @internal + */ +class ConnectionStatus extends Status { + public function __construct( Database $db = null ) { + $this->value = $db; + } + + public function setDB( Database $db ) { + $this->value = $db; + } + + public function getDB(): Database { + return $this->value; + } +} diff --git a/includes/installer/DatabaseConnectForm.php b/includes/installer/DatabaseConnectForm.php new file mode 100644 index 000000000000..ccc3bb0dbaeb --- /dev/null +++ b/includes/installer/DatabaseConnectForm.php @@ -0,0 +1,71 @@ +<?php + +namespace MediaWiki\Installer; + +use MediaWiki\Html\Html; +use MediaWiki\Status\Status; + +/** + * @internal + */ +abstract class DatabaseConnectForm extends DatabaseForm { + + /** + * Get HTML for a web form that configures this database. Configuration + * at this time should be the minimum needed to connect and test + * whether install or upgrade is required. + * + * If this is called, $this->parent can be assumed to be a WebInstaller. + */ + abstract public function getHtml(); + + /** + * Set variables based on the request array, assuming it was submitted + * via the form returned by getConnectForm(). Validate the connection + * settings by attempting to connect with them. + * + * If this is called, $this->parent can be assumed to be a WebInstaller. + * + * @return Status + */ + abstract public function submit(); + + /** + * Get a standard install-user fieldset. + * + * @return string + */ + protected function getInstallUserBox() { + return "<span class=\"cdx-card\"><span class=\"cdx-card__text\">" . + Html::element( + 'span', + [ 'class' => 'cdx-card__text__title' ], + wfMessage( 'config-db-install-account' )->text() + ) . + "<span class=\"cdx-card__text__description\">" . + $this->getTextBox( + '_InstallUser', + 'config-db-username', + [ 'dir' => 'ltr' ], + $this->webInstaller->getHelpBox( 'config-db-install-username' ) + ) . + $this->getPasswordBox( + '_InstallPassword', + 'config-db-password', + [ 'dir' => 'ltr' ], + $this->webInstaller->getHelpBox( 'config-db-install-password' ) + ) . + "</span></span></span>"; + } + + /** + * Submit a standard install user fieldset. + * @return Status + */ + protected function submitInstallUserBox() { + $this->setVarsFromRequest( [ '_InstallUser', '_InstallPassword' ] ); + + return Status::newGood(); + } + +} diff --git a/includes/installer/DatabaseForm.php b/includes/installer/DatabaseForm.php new file mode 100644 index 000000000000..ddbc8c5f1721 --- /dev/null +++ b/includes/installer/DatabaseForm.php @@ -0,0 +1,152 @@ +<?php + +namespace MediaWiki\Installer; + +/** + * @internal + */ +abstract class DatabaseForm { + protected WebInstaller $webInstaller; + protected DatabaseInstaller $dbInstaller; + + public function __construct( WebInstaller $webInstaller, DatabaseInstaller $dbInstaller ) { + $this->webInstaller = $webInstaller; + $this->dbInstaller = $dbInstaller; + } + + /** + * Get a variable, taking local defaults into account. + * @param string $var + * @param mixed|null $default + * @return mixed + */ + protected function getVar( $var, $default = null ) { + return $this->dbInstaller->getVar( $var, $default ); + } + + /** + * Set a variable + * @param string $name + * @param mixed $value + */ + protected function setVar( $name, $value ) { + $this->dbInstaller->setVar( $name, $value ); + } + + /** + * Return the internal name, e.g. 'mysql', or 'sqlite'. + * @return string + */ + protected function getName() { + return $this->dbInstaller->getName(); + } + + /** + * Get a labelled text box to configure a local variable. + * + * @param string $var + * @param string $label + * @param array $attribs + * @param string $helpData HTML + * @return string HTML + * @return-taint escaped + */ + protected function getTextBox( $var, $label, $attribs = [], $helpData = "" ) { + $name = $this->getName() . '_' . $var; + $value = $this->getVar( $var ); + if ( !isset( $attribs ) ) { + $attribs = []; + } + + return $this->webInstaller->getTextBox( [ + 'var' => $var, + 'label' => $label, + 'attribs' => $attribs, + 'controlName' => $name, + 'value' => $value, + 'help' => $helpData + ] ); + } + + /** + * Get a labelled password box to configure a local variable. + * Implements password hiding. + * + * @param string $var + * @param string $label + * @param array $attribs + * @param string $helpData HTML + * @return string HTML + * @return-taint escaped + */ + protected function getPasswordBox( $var, $label, $attribs = [], $helpData = "" ) { + $name = $this->getName() . '_' . $var; + $value = $this->getVar( $var ); + if ( !isset( $attribs ) ) { + $attribs = []; + } + + return $this->webInstaller->getPasswordBox( [ + 'var' => $var, + 'label' => $label, + 'attribs' => $attribs, + 'controlName' => $name, + 'value' => $value, + 'help' => $helpData + ] ); + } + + /** + * Get a labelled checkbox to configure a local boolean variable. + * + * @param string $var + * @param string $label + * @param array $attribs Optional. + * @param string $helpData Optional. + * @return string + */ + protected function getCheckBox( $var, $label, $attribs = [], $helpData = "" ) { + $name = $this->getName() . '_' . $var; + $value = $this->getVar( $var ); + + return $this->webInstaller->getCheckBox( [ + 'var' => $var, + 'label' => $label, + 'attribs' => $attribs, + 'controlName' => $name, + 'value' => $value, + 'help' => $helpData + ] ); + } + + /** + * Get a set of labelled radio buttons. + * + * @param array $params Parameters are: + * var: The variable to be configured (required) + * label: The message name for the label (required) + * itemLabelPrefix: The message name prefix for the item labels (required) + * values: List of allowed values (required) + * itemAttribs Array of attribute arrays, outer key is the value name (optional) + * + * @return string + */ + protected function getRadioSet( $params ) { + $params['controlName'] = $this->getName() . '_' . $params['var']; + $params['value'] = $this->getVar( $params['var'] ); + + return $this->webInstaller->getRadioSet( $params ); + } + + /** + * Convenience function to set variables based on form data. + * Assumes that variables containing "password" in the name are (potentially + * fake) passwords. + * @param array $varNames + * @return array + */ + protected function setVarsFromRequest( $varNames ) { + return $this->webInstaller->setVarsFromRequest( $varNames, $this->getName() . '_' ); + } + +} diff --git a/includes/installer/DatabaseInstaller.php b/includes/installer/DatabaseInstaller.php index e680fdaba1ef..c8e319301765 100644 --- a/includes/installer/DatabaseInstaller.php +++ b/includes/installer/DatabaseInstaller.php @@ -25,7 +25,6 @@ namespace MediaWiki\Installer; use Exception; -use MediaWiki\Html\Html; use MediaWiki\Status\Status; use MWException; use MWLBFactory; @@ -49,7 +48,7 @@ abstract class DatabaseInstaller { /** * The Installer object. * - * @var WebInstaller + * @var Installer */ public $parent; @@ -122,53 +121,12 @@ abstract class DatabaseInstaller { } /** - * Get HTML for a web form that configures this database. Configuration - * at this time should be the minimum needed to connect and test - * whether install or upgrade is required. - * - * If this is called, $this->parent can be assumed to be a WebInstaller. - */ - abstract public function getConnectForm(); - - /** - * Set variables based on the request array, assuming it was submitted - * via the form returned by getConnectForm(). Validate the connection - * settings by attempting to connect with them. - * - * If this is called, $this->parent can be assumed to be a WebInstaller. - * - * @return Status - */ - abstract public function submitConnectForm(); - - /** - * Get HTML for a web form that retrieves settings used for installation. - * $this->parent can be assumed to be a WebInstaller. - * If the DB type has no settings beyond those already configured with - * getConnectForm(), this should return false. - * @return string|false - */ - public function getSettingsForm() { - return false; - } - - /** - * Set variables based on the request array, assuming it was submitted via - * the form return by getSettingsForm(). - * - * @return Status - */ - public function submitSettingsForm() { - return Status::newGood(); - } - - /** * Open a connection to the database using the administrative user/password * currently defined in the session, without any caching. Returns a status * object. On success, the status object will contain a Database object in * its value member. * - * @return Status + * @return ConnectionStatus */ abstract public function openConnection(); @@ -187,12 +145,11 @@ abstract class DatabaseInstaller { * * This will return a cached connection if one is available. * - * @return Status - * @suppress PhanUndeclaredMethod + * @return ConnectionStatus */ public function getConnection() { if ( $this->db ) { - return Status::newGood( $this->db ); + return new ConnectionStatus( $this->db ); } $status = $this->openConnection(); @@ -375,8 +332,7 @@ abstract class DatabaseInstaller { public function setupSchemaVars() { $status = $this->getConnection(); if ( $status->isOK() ) { - // @phan-suppress-next-line PhanUndeclaredMethod - $status->value->setSchemaVars( $this->getSchemaVars() ); + $status->getDB()->setSchemaVars( $this->getSchemaVars() ); } else { $msg = __METHOD__ . ': unexpected error while establishing' . ' a database connection with message: ' @@ -543,113 +499,9 @@ abstract class DatabaseInstaller { $this->parent->setVar( $name, $value ); } - /** - * Get a labelled text box to configure a local variable. - * - * @param string $var - * @param string $label - * @param array $attribs - * @param string $helpData HTML - * @return string HTML - * @return-taint escaped - */ - public function getTextBox( $var, $label, $attribs = [], $helpData = "" ) { - $name = $this->getName() . '_' . $var; - $value = $this->getVar( $var ); - if ( !isset( $attribs ) ) { - $attribs = []; - } + abstract public function getConnectForm( WebInstaller $webInstaller ): DatabaseConnectForm; - return $this->parent->getTextBox( [ - 'var' => $var, - 'label' => $label, - 'attribs' => $attribs, - 'controlName' => $name, - 'value' => $value, - 'help' => $helpData - ] ); - } - - /** - * Get a labelled password box to configure a local variable. - * Implements password hiding. - * - * @param string $var - * @param string $label - * @param array $attribs - * @param string $helpData HTML - * @return string HTML - * @return-taint escaped - */ - public function getPasswordBox( $var, $label, $attribs = [], $helpData = "" ) { - $name = $this->getName() . '_' . $var; - $value = $this->getVar( $var ); - if ( !isset( $attribs ) ) { - $attribs = []; - } - - return $this->parent->getPasswordBox( [ - 'var' => $var, - 'label' => $label, - 'attribs' => $attribs, - 'controlName' => $name, - 'value' => $value, - 'help' => $helpData - ] ); - } - - /** - * Get a labelled checkbox to configure a local boolean variable. - * - * @param string $var - * @param string $label - * @param array $attribs Optional. - * @param string $helpData Optional. - * @return string - */ - public function getCheckBox( $var, $label, $attribs = [], $helpData = "" ) { - $name = $this->getName() . '_' . $var; - $value = $this->getVar( $var ); - - return $this->parent->getCheckBox( [ - 'var' => $var, - 'label' => $label, - 'attribs' => $attribs, - 'controlName' => $name, - 'value' => $value, - 'help' => $helpData - ] ); - } - - /** - * Get a set of labelled radio buttons. - * - * @param array $params Parameters are: - * var: The variable to be configured (required) - * label: The message name for the label (required) - * itemLabelPrefix: The message name prefix for the item labels (required) - * values: List of allowed values (required) - * itemAttribs Array of attribute arrays, outer key is the value name (optional) - * - * @return string - */ - public function getRadioSet( $params ) { - $params['controlName'] = $this->getName() . '_' . $params['var']; - $params['value'] = $this->getVar( $params['var'] ); - - return $this->parent->getRadioSet( $params ); - } - - /** - * Convenience function to set variables based on form data. - * Assumes that variables containing "password" in the name are (potentially - * fake) passwords. - * @param array $varNames - * @return array - */ - public function setVarsFromRequest( $varNames ) { - return $this->parent->setVarsFromRequest( $varNames, $this->getName() . '_' ); - } + abstract public function getSettingsForm( WebInstaller $webInstaller ): DatabaseSettingsForm; /** * Determine whether an existing installation of MediaWiki is present in @@ -681,99 +533,6 @@ abstract class DatabaseInstaller { } /** - * Get a standard install-user fieldset. - * - * @return string - */ - public function getInstallUserBox() { - return "<span class=\"cdx-card\"><span class=\"cdx-card__text\">" . - Html::element( - 'span', - [ 'class' => 'cdx-card__text__title' ], - wfMessage( 'config-db-install-account' )->text() - ) . - "<span class=\"cdx-card__text__description\">" . - $this->getTextBox( - '_InstallUser', - 'config-db-username', - [ 'dir' => 'ltr' ], - $this->parent->getHelpBox( 'config-db-install-username' ) - ) . - $this->getPasswordBox( - '_InstallPassword', - 'config-db-password', - [ 'dir' => 'ltr' ], - $this->parent->getHelpBox( 'config-db-install-password' ) - ) . - "</span></span></span>"; - } - - /** - * Submit a standard install user fieldset. - * @return Status - */ - public function submitInstallUserBox() { - $this->setVarsFromRequest( [ '_InstallUser', '_InstallPassword' ] ); - - return Status::newGood(); - } - - /** - * Get a standard web-user fieldset - * @param string|false $noCreateMsg Message to display instead of the creation checkbox. - * Set this to false to show a creation checkbox (default). - * - * @return string - */ - public function getWebUserBox( $noCreateMsg = false ) { - $wrapperStyle = $this->getVar( '_SameAccount' ) ? 'display: none' : ''; - $s = "<span class=\"cdx-card\"><span class=\"cdx-card__text\">" . - Html::element( - 'span', - [ 'class' => 'cdx-card__text__title' ], - wfMessage( 'config-db-web-account' )->text() - ) . - $this->getCheckBox( - '_SameAccount', 'config-db-web-account-same', - [ 'class' => 'hideShowRadio cdx-checkbox__input', 'rel' => 'dbOtherAccount' ] - ) . - Html::openElement( 'div', [ 'id' => 'dbOtherAccount', 'style' => $wrapperStyle ] ) . - $this->getTextBox( 'wgDBuser', 'config-db-username' ) . - $this->getPasswordBox( 'wgDBpassword', 'config-db-password' ) . - $this->parent->getHelpBox( 'config-db-web-help' ); - if ( $noCreateMsg ) { - $s .= Html::warningBox( wfMessage( $noCreateMsg )->plain(), 'config-warning-box' ); - } else { - $s .= $this->getCheckBox( '_CreateDBAccount', 'config-db-web-create' ); - } - $s .= Html::closeElement( 'div' ) . "</span></span></span>"; - - return $s; - } - - /** - * Submit the form from getWebUserBox(). - * - * @return Status - */ - public function submitWebUserBox() { - $this->setVarsFromRequest( - [ 'wgDBuser', 'wgDBpassword', '_SameAccount', '_CreateDBAccount' ] - ); - - if ( $this->getVar( '_SameAccount' ) ) { - $this->setVar( 'wgDBuser', $this->getVar( '_InstallUser' ) ); - $this->setVar( 'wgDBpassword', $this->getVar( '_InstallPassword' ) ); - } - - if ( $this->getVar( '_CreateDBAccount' ) && strval( $this->getVar( 'wgDBpassword' ) ) == '' ) { - return Status::newFatal( 'config-db-password-empty', $this->getVar( 'wgDBuser' ) ); - } - - return Status::newGood(); - } - - /** * Common function for databases that don't understand the MySQLish syntax of interwiki.list. * * @return Status diff --git a/includes/installer/DatabaseSettingsForm.php b/includes/installer/DatabaseSettingsForm.php new file mode 100644 index 000000000000..4ce3dcdf2e8e --- /dev/null +++ b/includes/installer/DatabaseSettingsForm.php @@ -0,0 +1,89 @@ +<?php + +namespace MediaWiki\Installer; + +use MediaWiki\Html\Html; +use MediaWiki\Status\Status; + +/** + * @internal + */ +class DatabaseSettingsForm extends DatabaseForm { + + /** + * Get HTML for a web form that retrieves settings used for installation. + * $this->parent can be assumed to be a WebInstaller. + * If the DB type has no settings beyond those already configured with + * getConnectForm(), this should return false. + * @return string|false + */ + public function getHtml() { + return false; + } + + /** + * Set variables based on the request array, assuming it was submitted via + * the form return by getSettingsForm(). + * + * @return Status + */ + public function submit() { + return Status::newGood(); + } + + /** + * Get a standard web-user fieldset + * @param string|false $noCreateMsg Message to display instead of the creation checkbox. + * Set this to false to show a creation checkbox (default). + * + * @return string + */ + protected function getWebUserBox( $noCreateMsg = false ) { + $wrapperStyle = $this->getVar( '_SameAccount' ) ? 'display: none' : ''; + $s = "<span class=\"cdx-card\"><span class=\"cdx-card__text\">" . + Html::element( + 'span', + [ 'class' => 'cdx-card__text__title' ], + wfMessage( 'config-db-web-account' )->text() + ) . + $this->getCheckBox( + '_SameAccount', 'config-db-web-account-same', + [ 'class' => 'hideShowRadio cdx-checkbox__input', 'rel' => 'dbOtherAccount' ] + ) . + Html::openElement( 'div', [ 'id' => 'dbOtherAccount', 'style' => $wrapperStyle ] ) . + $this->getTextBox( 'wgDBuser', 'config-db-username' ) . + $this->getPasswordBox( 'wgDBpassword', 'config-db-password' ) . + $this->webInstaller->getHelpBox( 'config-db-web-help' ); + if ( $noCreateMsg ) { + $s .= Html::warningBox( wfMessage( $noCreateMsg )->plain(), 'config-warning-box' ); + } else { + $s .= $this->getCheckBox( '_CreateDBAccount', 'config-db-web-create' ); + } + $s .= Html::closeElement( 'div' ) . "</span></span></span>"; + + return $s; + } + + /** + * Submit the form from getWebUserBox(). + * + * @return Status + */ + public function submitWebUserBox() { + $this->setVarsFromRequest( + [ 'wgDBuser', 'wgDBpassword', '_SameAccount', '_CreateDBAccount' ] + ); + + if ( $this->getVar( '_SameAccount' ) ) { + $this->setVar( 'wgDBuser', $this->getVar( '_InstallUser' ) ); + $this->setVar( 'wgDBpassword', $this->getVar( '_InstallPassword' ) ); + } + + if ( $this->getVar( '_CreateDBAccount' ) && strval( $this->getVar( 'wgDBpassword' ) ) == '' ) { + return Status::newFatal( 'config-db-password-empty', $this->getVar( 'wgDBuser' ) ); + } + + return Status::newGood(); + } + +} diff --git a/includes/installer/Installer.php b/includes/installer/Installer.php index 1beb15d854f1..9f605e56191d 100644 --- a/includes/installer/Installer.php +++ b/includes/installer/Installer.php @@ -848,8 +848,7 @@ abstract class Installer { if ( !$status->isOK() ) { return $status; } - // @phan-suppress-next-line PhanUndeclaredMethod - $status->value->insert( + $status->getDB()->insert( 'site_stats', [ 'ss_row_id' => 1, diff --git a/includes/installer/MysqlConnectForm.php b/includes/installer/MysqlConnectForm.php new file mode 100644 index 000000000000..08c24769f024 --- /dev/null +++ b/includes/installer/MysqlConnectForm.php @@ -0,0 +1,74 @@ +<?php + +namespace MediaWiki\Installer; + +use MediaWiki\Html\Html; +use MediaWiki\Status\Status; + +/** + * @internal + */ +class MysqlConnectForm extends DatabaseConnectForm { + /** + * @return string + */ + public function getHtml() { + return $this->getTextBox( + 'wgDBserver', + 'config-db-host', + [], + $this->webInstaller->getHelpBox( 'config-db-host-help' ) + ) . + $this->getCheckBox( 'wgDBssl', 'config-db-ssl' ) . + "<span class=\"cdx-card\"><span class=\"cdx-card__text\">" . + Html::element( + 'span', + [ 'class' => 'cdx-card__text__title' ], + wfMessage( 'config-db-wiki-settings' )->text() + ) . + "<span class=\"cdx-card__text__description\">" . + $this->getTextBox( 'wgDBname', 'config-db-name', [ 'dir' => 'ltr' ], + $this->webInstaller->getHelpBox( 'config-db-name-help' ) ) . + $this->getTextBox( 'wgDBprefix', 'config-db-prefix', [ 'dir' => 'ltr' ], + $this->webInstaller->getHelpBox( 'config-db-prefix-help' ) ) . + "</span></span></span>" . + $this->getInstallUserBox(); + } + + public function submit() { + // Get variables from the request. + $newValues = $this->setVarsFromRequest( [ 'wgDBserver', 'wgDBname', 'wgDBprefix', 'wgDBssl' ] ); + + // Validate them. + $status = Status::newGood(); + if ( !strlen( $newValues['wgDBserver'] ) ) { + $status->fatal( 'config-missing-db-host' ); + } + if ( !strlen( $newValues['wgDBname'] ) ) { + $status->fatal( 'config-missing-db-name' ); + } elseif ( !preg_match( '/^[a-z0-9+_-]+$/i', $newValues['wgDBname'] ) ) { + $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] ); + } + if ( !preg_match( '/^[a-z0-9_-]*$/i', $newValues['wgDBprefix'] ) ) { + $status->fatal( 'config-invalid-db-prefix', $newValues['wgDBprefix'] ); + } + if ( !$status->isOK() ) { + return $status; + } + + // Submit user box + $status = $this->submitInstallUserBox(); + if ( !$status->isOK() ) { + return $status; + } + + // Try to connect + $status = $this->dbInstaller->getConnection(); + if ( !$status->isOK() ) { + return $status; + } + + // Check version + return MysqlInstaller::meetsMinimumRequirement( $status->getDB() ); + } +} diff --git a/includes/installer/MysqlInstaller.php b/includes/installer/MysqlInstaller.php index 71f80a2c9f3a..ca6af464b1b5 100644 --- a/includes/installer/MysqlInstaller.php +++ b/includes/installer/MysqlInstaller.php @@ -24,10 +24,7 @@ namespace MediaWiki\Installer; -use MediaWiki\Html\Html; -use MediaWiki\MediaWikiServices; use MediaWiki\Status\Status; -use Wikimedia\Rdbms\Database; use Wikimedia\Rdbms\DatabaseFactory; use Wikimedia\Rdbms\DatabaseMySQL; use Wikimedia\Rdbms\DBConnectionError; @@ -89,72 +86,12 @@ class MysqlInstaller extends DatabaseInstaller { return self::checkExtension( 'mysqli' ); } - /** - * @return string - */ - public function getConnectForm() { - return $this->getTextBox( - 'wgDBserver', - 'config-db-host', - [], - $this->parent->getHelpBox( 'config-db-host-help' ) - ) . - $this->getCheckBox( 'wgDBssl', 'config-db-ssl' ) . - "<span class=\"cdx-card\"><span class=\"cdx-card__text\">" . - Html::element( - 'span', - [ 'class' => 'cdx-card__text__title' ], - wfMessage( 'config-db-wiki-settings' )->text() - ) . - "<span class=\"cdx-card__text__description\">" . - $this->getTextBox( 'wgDBname', 'config-db-name', [ 'dir' => 'ltr' ], - $this->parent->getHelpBox( 'config-db-name-help' ) ) . - $this->getTextBox( 'wgDBprefix', 'config-db-prefix', [ 'dir' => 'ltr' ], - $this->parent->getHelpBox( 'config-db-prefix-help' ) ) . - "</span></span></span>" . - $this->getInstallUserBox(); + public function getConnectForm( WebInstaller $webInstaller ): DatabaseConnectForm { + return new MysqlConnectForm( $webInstaller, $this ); } - public function submitConnectForm() { - // Get variables from the request. - $newValues = $this->setVarsFromRequest( [ 'wgDBserver', 'wgDBname', 'wgDBprefix', 'wgDBssl' ] ); - - // Validate them. - $status = Status::newGood(); - if ( !strlen( $newValues['wgDBserver'] ) ) { - $status->fatal( 'config-missing-db-host' ); - } - if ( !strlen( $newValues['wgDBname'] ) ) { - $status->fatal( 'config-missing-db-name' ); - } elseif ( !preg_match( '/^[a-z0-9+_-]+$/i', $newValues['wgDBname'] ) ) { - $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] ); - } - if ( !preg_match( '/^[a-z0-9_-]*$/i', $newValues['wgDBprefix'] ) ) { - $status->fatal( 'config-invalid-db-prefix', $newValues['wgDBprefix'] ); - } - if ( !$status->isOK() ) { - return $status; - } - - // Submit user box - $status = $this->submitInstallUserBox(); - if ( !$status->isOK() ) { - return $status; - } - - // Try to connect - $status = $this->getConnection(); - if ( !$status->isOK() ) { - return $status; - } - /** - * @var Database $conn - */ - $conn = $status->value; - '@phan-var Database $conn'; - - // Check version - return static::meetsMinimumRequirement( $conn ); + public function getSettingsForm( WebInstaller $webInstaller ): DatabaseSettingsForm { + return new MysqlSettingsForm( $webInstaller, $this ); } public static function meetsMinimumRequirement( IDatabase $conn ) { @@ -166,10 +103,10 @@ class MysqlInstaller extends DatabaseInstaller { } /** - * @return Status + * @return ConnectionStatus */ public function openConnection() { - $status = Status::newGood(); + $status = new ConnectionStatus; try { /** @var DatabaseMySQL $db */ $db = ( new DatabaseFactory() )->create( 'mysql', [ @@ -180,7 +117,7 @@ class MysqlInstaller extends DatabaseInstaller { 'dbname' => false, 'flags' => 0, 'tablePrefix' => $this->getVar( 'wgDBprefix' ) ] ); - $status->value = $db; + $status->setDB( $db ); } catch ( DBConnectionError $e ) { $status->fatal( 'config-connection-error', $e->getMessage() ); } @@ -197,10 +134,7 @@ class MysqlInstaller extends DatabaseInstaller { return; } - /** - * @var Database $conn - */ - $conn = $status->value; + $conn = $status->getDB(); $this->selectDatabase( $conn, $this->getVar( 'wgDBname' ) ); # Determine existing default character set if ( $conn->tableExists( "revision", __METHOD__ ) ) { @@ -260,11 +194,7 @@ class MysqlInstaller extends DatabaseInstaller { */ public function getEngines() { $status = $this->getConnection(); - - /** - * @var Database $conn - */ - $conn = $status->value; + $conn = $status->getDB(); $engines = []; $res = $conn->query( 'SHOW ENGINES', __METHOD__ ); @@ -297,8 +227,7 @@ class MysqlInstaller extends DatabaseInstaller { if ( !$status->isOK() ) { return false; } - /** @var Database $conn */ - $conn = $status->value; + $conn = $status->getDB(); // Get current account name $currentName = $conn->selectField( '', 'CURRENT_USER()', '', __METHOD__ ); @@ -376,83 +305,6 @@ class MysqlInstaller extends DatabaseInstaller { return "/$r/s"; } - /** - * @return string - */ - public function getSettingsForm() { - if ( $this->canCreateAccounts() ) { - $noCreateMsg = false; - } else { - $noCreateMsg = 'config-db-web-no-create-privs'; - } - $s = $this->getWebUserBox( $noCreateMsg ); - - // Do engine selector - $engines = $this->getEngines(); - // If the current default engine is not supported, use an engine that is - if ( !in_array( $this->getVar( '_MysqlEngine' ), $engines ) ) { - $this->setVar( '_MysqlEngine', reset( $engines ) ); - } - - // If the current default charset is not supported, use a charset that is - $charsets = $this->getCharsets(); - if ( !in_array( $this->getVar( '_MysqlCharset' ), $charsets ) ) { - $this->setVar( '_MysqlCharset', reset( $charsets ) ); - } - - return $s; - } - - /** - * @return Status - */ - public function submitSettingsForm() { - $this->setVarsFromRequest( [ '_MysqlEngine', '_MysqlCharset' ] ); - $status = $this->submitWebUserBox(); - if ( !$status->isOK() ) { - return $status; - } - - // Validate the create checkbox - $canCreate = $this->canCreateAccounts(); - if ( !$canCreate ) { - $this->setVar( '_CreateDBAccount', false ); - $create = false; - } else { - $create = $this->getVar( '_CreateDBAccount' ); - } - - if ( !$create ) { - // Test the web account - try { - MediaWikiServices::getInstance()->getDatabaseFactory()->create( 'mysql', [ - 'host' => $this->getVar( 'wgDBserver' ), - 'user' => $this->getVar( 'wgDBuser' ), - 'password' => $this->getVar( 'wgDBpassword' ), - 'ssl' => $this->getVar( 'wgDBssl' ), - 'dbname' => false, - 'flags' => 0, - 'tablePrefix' => $this->getVar( 'wgDBprefix' ) - ] ); - } catch ( DBConnectionError $e ) { - return Status::newFatal( 'config-connection-error', $e->getMessage() ); - } - } - - // Validate engines and charsets - // This is done pre-submit already, so it's just for security - $engines = $this->getEngines(); - if ( !in_array( $this->getVar( '_MysqlEngine' ), $engines ) ) { - $this->setVar( '_MysqlEngine', reset( $engines ) ); - } - $charsets = $this->getCharsets(); - if ( !in_array( $this->getVar( '_MysqlCharset' ), $charsets ) ) { - $this->setVar( '_MysqlCharset', reset( $charsets ) ); - } - - return Status::newGood(); - } - public function preInstall() { # Add our user callback to installSteps, right before the tables are created. $callback = [ @@ -470,8 +322,7 @@ class MysqlInstaller extends DatabaseInstaller { if ( !$status->isOK() ) { return $status; } - /** @var Database $conn */ - $conn = $status->value; + $conn = $status->getDB(); $dbName = $this->getVar( 'wgDBname' ); if ( !$this->databaseExists( $dbName ) ) { $conn->query( diff --git a/includes/installer/MysqlSettingsForm.php b/includes/installer/MysqlSettingsForm.php new file mode 100644 index 000000000000..19f6727e5995 --- /dev/null +++ b/includes/installer/MysqlSettingsForm.php @@ -0,0 +1,100 @@ +<?php + +namespace MediaWiki\Installer; + +use MediaWiki\MediaWikiServices; +use MediaWiki\Status\Status; +use Wikimedia\Rdbms\DBConnectionError; + +/** + * @internal + */ +class MysqlSettingsForm extends DatabaseSettingsForm { + + /** + * @return string + */ + public function getHtml() { + if ( $this->getMysqlInstaller()->canCreateAccounts() ) { + $noCreateMsg = false; + } else { + $noCreateMsg = 'config-db-web-no-create-privs'; + } + $s = $this->getWebUserBox( $noCreateMsg ); + + // Do engine selector + $engines = $this->getMysqlInstaller()->getEngines(); + // If the current default engine is not supported, use an engine that is + if ( !in_array( $this->getVar( '_MysqlEngine' ), $engines ) ) { + $this->setVar( '_MysqlEngine', reset( $engines ) ); + } + + // If the current default charset is not supported, use a charset that is + $charsets = $this->getMysqlInstaller()->getCharsets(); + if ( !in_array( $this->getVar( '_MysqlCharset' ), $charsets ) ) { + $this->setVar( '_MysqlCharset', reset( $charsets ) ); + } + + return $s; + } + + /** + * @return Status + */ + public function submit() { + $this->setVarsFromRequest( [ '_MysqlEngine', '_MysqlCharset' ] ); + $status = $this->submitWebUserBox(); + if ( !$status->isOK() ) { + return $status; + } + + // Validate the create checkbox + $canCreate = $this->getMysqlInstaller()->canCreateAccounts(); + if ( !$canCreate ) { + $this->setVar( '_CreateDBAccount', false ); + $create = false; + } else { + $create = $this->getVar( '_CreateDBAccount' ); + } + + if ( !$create ) { + // Test the web account + try { + MediaWikiServices::getInstance()->getDatabaseFactory()->create( 'mysql', [ + 'host' => $this->getVar( 'wgDBserver' ), + 'user' => $this->getVar( 'wgDBuser' ), + 'password' => $this->getVar( 'wgDBpassword' ), + 'ssl' => $this->getVar( 'wgDBssl' ), + 'dbname' => false, + 'flags' => 0, + 'tablePrefix' => $this->getVar( 'wgDBprefix' ) + ] ); + } catch ( DBConnectionError $e ) { + return Status::newFatal( 'config-connection-error', $e->getMessage() ); + } + } + + // Validate engines and charsets + // This is done pre-submit already, so it's just for security + $engines = $this->getMysqlInstaller()->getEngines(); + if ( !in_array( $this->getVar( '_MysqlEngine' ), $engines ) ) { + $this->setVar( '_MysqlEngine', reset( $engines ) ); + } + $charsets = $this->getMysqlInstaller()->getCharsets(); + if ( !in_array( $this->getVar( '_MysqlCharset' ), $charsets ) ) { + $this->setVar( '_MysqlCharset', reset( $charsets ) ); + } + + return Status::newGood(); + } + + /** + * Downcast the DatabaseInstaller + * @return MysqlInstaller + */ + private function getMysqlInstaller(): MysqlInstaller { + // @phan-suppress-next-line PhanTypeMismatchReturnSuperType + return $this->dbInstaller; + } + +} diff --git a/includes/installer/PostgresConnectForm.php b/includes/installer/PostgresConnectForm.php new file mode 100644 index 000000000000..bbdc4579fe82 --- /dev/null +++ b/includes/installer/PostgresConnectForm.php @@ -0,0 +1,104 @@ +<?php + +namespace MediaWiki\Installer; + +use MediaWiki\Html\Html; +use MediaWiki\Status\Status; +use Wikimedia\Rdbms\Database; + +/** + * @internal + */ +class PostgresConnectForm extends DatabaseConnectForm { + + public function getHtml() { + return $this->getTextBox( + 'wgDBserver', + 'config-db-host', + [], + $this->webInstaller->getHelpBox( 'config-db-host-help' ) + ) . + $this->getTextBox( 'wgDBport', 'config-db-port' ) . + $this->getCheckBox( 'wgDBssl', 'config-db-ssl' ) . + "<span class=\"cdx-card\"><span class=\"cdx-card__text\">" . + Html::element( + 'span', + [ 'class' => 'cdx-card__text__title' ], + wfMessage( 'config-db-wiki-settings' )->text() + ) . + $this->getTextBox( + 'wgDBname', + 'config-db-name', + [], + $this->webInstaller->getHelpBox( 'config-db-name-help' ) + ) . + $this->getTextBox( + 'wgDBmwschema', + 'config-db-schema', + [], + $this->webInstaller->getHelpBox( 'config-db-schema-help' ) + ) . + "</span></span></span>" . + $this->getInstallUserBox(); + } + + public function submit() { + // Get variables from the request + $newValues = $this->setVarsFromRequest( [ + 'wgDBserver', + 'wgDBport', + 'wgDBssl', + 'wgDBname', + 'wgDBmwschema' + ] ); + + // Validate them + $status = Status::newGood(); + if ( !strlen( $newValues['wgDBname'] ) ) { + $status->fatal( 'config-missing-db-name' ); + } elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) { + $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] ); + } + if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBmwschema'] ) ) { + $status->fatal( 'config-invalid-schema', $newValues['wgDBmwschema'] ); + } + + // Submit user box + if ( $status->isOK() ) { + $status->merge( $this->submitInstallUserBox() ); + } + if ( !$status->isOK() ) { + return $status; + } + + $status = $this->getPostgresInstaller()->getPgConnection( 'create-db' ); + if ( !$status->isOK() ) { + return $status; + } + /** + * @var Database $conn + */ + $conn = $status->value; + + // Check version + $status = PostgresInstaller::meetsMinimumRequirement( $conn ); + if ( !$status->isOK() ) { + return $status; + } + + $this->setVar( 'wgDBuser', $this->getVar( '_InstallUser' ) ); + $this->setVar( 'wgDBpassword', $this->getVar( '_InstallPassword' ) ); + + return Status::newGood(); + } + + /** + * Downcast the DatabaseInstaller + * @return PostgresInstaller + */ + private function getPostgresInstaller(): PostgresInstaller { + // @phan-suppress-next-line PhanTypeMismatchReturnSuperType + return $this->dbInstaller; + } + +} diff --git a/includes/installer/PostgresInstaller.php b/includes/installer/PostgresInstaller.php index 21f69905b10a..e20a3d555690 100644 --- a/includes/installer/PostgresInstaller.php +++ b/includes/installer/PostgresInstaller.php @@ -24,7 +24,6 @@ namespace MediaWiki\Installer; use InvalidArgumentException; -use MediaWiki\Html\Html; use MediaWiki\MediaWikiServices; use MediaWiki\Status\Status; use Wikimedia\Rdbms\Database; @@ -59,6 +58,9 @@ class PostgresInstaller extends DatabaseInstaller { protected static $notMinimumVersionMessage = 'config-postgres-old'; public $maxRoleSearchDepth = 5; + /** + * @var DatabasePostgres[] + */ protected $pgConns = []; public function getName() { @@ -69,85 +71,12 @@ class PostgresInstaller extends DatabaseInstaller { return self::checkExtension( 'pgsql' ); } - public function getConnectForm() { - return $this->getTextBox( - 'wgDBserver', - 'config-db-host', - [], - $this->parent->getHelpBox( 'config-db-host-help' ) - ) . - $this->getTextBox( 'wgDBport', 'config-db-port' ) . - $this->getCheckBox( 'wgDBssl', 'config-db-ssl' ) . - "<span class=\"cdx-card\"><span class=\"cdx-card__text\">" . - Html::element( - 'span', - [ 'class' => 'cdx-card__text__title' ], - wfMessage( 'config-db-wiki-settings' )->text() - ) . - $this->getTextBox( - 'wgDBname', - 'config-db-name', - [], - $this->parent->getHelpBox( 'config-db-name-help' ) - ) . - $this->getTextBox( - 'wgDBmwschema', - 'config-db-schema', - [], - $this->parent->getHelpBox( 'config-db-schema-help' ) - ) . - "</span></span></span>" . - $this->getInstallUserBox(); + public function getConnectForm( WebInstaller $webInstaller ): DatabaseConnectForm { + return new PostgresConnectForm( $webInstaller, $this ); } - public function submitConnectForm() { - // Get variables from the request - $newValues = $this->setVarsFromRequest( [ - 'wgDBserver', - 'wgDBport', - 'wgDBssl', - 'wgDBname', - 'wgDBmwschema' - ] ); - - // Validate them - $status = Status::newGood(); - if ( !strlen( $newValues['wgDBname'] ) ) { - $status->fatal( 'config-missing-db-name' ); - } elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) { - $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] ); - } - if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBmwschema'] ) ) { - $status->fatal( 'config-invalid-schema', $newValues['wgDBmwschema'] ); - } - - // Submit user box - if ( $status->isOK() ) { - $status->merge( $this->submitInstallUserBox() ); - } - if ( !$status->isOK() ) { - return $status; - } - - $status = $this->getPgConnection( 'create-db' ); - if ( !$status->isOK() ) { - return $status; - } - /** - * @var Database $conn - */ - $conn = $status->value; - - // Check version - $status = static::meetsMinimumRequirement( $conn ); - if ( !$status->isOK() ) { - return $status; - } - - $this->setVar( 'wgDBuser', $this->getVar( '_InstallUser' ) ); - $this->setVar( 'wgDBpassword', $this->getVar( '_InstallPassword' ) ); - - return Status::newGood(); + public function getSettingsForm( WebInstaller $webInstaller ): DatabaseSettingsForm { + return new PostgresSettingsForm( $webInstaller, $this ); } public function getConnection() { @@ -169,10 +98,10 @@ class PostgresInstaller extends DatabaseInstaller { * @param string $password * @param string $dbName Database name * @param string $schema Database schema - * @return Status + * @return ConnectionStatus */ protected function openConnectionWithParams( $user, $password, $dbName, $schema ) { - $status = Status::newGood(); + $status = new ConnectionStatus; try { $db = MediaWikiServices::getInstance()->getDatabaseFactory()->create( 'postgres', [ 'host' => $this->getVar( 'wgDBserver' ), @@ -183,7 +112,7 @@ class PostgresInstaller extends DatabaseInstaller { 'dbname' => $dbName, 'schema' => $schema, ] ); - $status->value = $db; + $status->setDB( $db ); } catch ( DBConnectionError $e ) { $status->fatal( 'config-connection-error', $e->getMessage() ); } @@ -194,19 +123,16 @@ class PostgresInstaller extends DatabaseInstaller { /** * Get a special type of connection * @param string $type See openPgConnection() for details. - * @return Status + * @return ConnectionStatus */ - protected function getPgConnection( $type ) { + public function getPgConnection( $type ) { if ( isset( $this->pgConns[$type] ) ) { - return Status::newGood( $this->pgConns[$type] ); + return new ConnectionStatus( $this->pgConns[$type] ); } $status = $this->openPgConnection( $type ); if ( $status->isOK() ) { - /** - * @var Database $conn - */ - $conn = $status->value; + $conn = $status->getDB(); $conn->clearFlag( DBO_TRX ); $conn->commit( __METHOD__ ); $this->pgConns[$type] = $conn; @@ -236,7 +162,7 @@ class PostgresInstaller extends DatabaseInstaller { * - create-schema: A connection to the new DB, for creating schemas and * other similar objects in the new DB. * - create-tables: A connection with a role suitable for creating tables. - * @return Status On success, a connection object will be in the value member. + * @return ConnectionStatus On success, a connection object will be in the value member. */ protected function openPgConnection( $type ) { switch ( $type ) { @@ -253,10 +179,7 @@ class PostgresInstaller extends DatabaseInstaller { case 'create-tables': $status = $this->openPgConnection( 'create-schema' ); if ( $status->isOK() ) { - /** - * @var Database $conn - */ - $conn = $status->value; + $conn = $status->getDB(); $safeRole = $conn->addIdentifierQuotes( $this->getVar( 'wgDBuser' ) ); $conn->query( "SET ROLE $safeRole", __METHOD__ ); } @@ -276,7 +199,7 @@ class PostgresInstaller extends DatabaseInstaller { array_unshift( $dbs, $this->getVar( 'wgDBname' ) ); } $conn = false; - $status = Status::newGood(); + $status = new ConnectionStatus; foreach ( $dbs as $db ) { try { $p = [ @@ -298,7 +221,7 @@ class PostgresInstaller extends DatabaseInstaller { } } if ( $conn !== false ) { - return Status::newGood( $conn ); + return new ConnectionStatus( $conn ); } else { return $status; } @@ -309,10 +232,7 @@ class PostgresInstaller extends DatabaseInstaller { if ( !$status->isOK() ) { return false; } - /** - * @var Database $conn - */ - $conn = $status->value; + $conn = $status->getDB(); $superuser = $this->getVar( '_InstallUser' ); $row = $conn->selectRow( '"pg_catalog"."pg_roles"', '*', @@ -321,7 +241,7 @@ class PostgresInstaller extends DatabaseInstaller { return $row; } - protected function canCreateAccounts() { + public function canCreateAccounts() { $perms = $this->getInstallUserPermissions(); return $perms && $perms->rolsuper || $perms->rolcreaterole; } @@ -331,85 +251,12 @@ class PostgresInstaller extends DatabaseInstaller { return $perms && $perms->rolsuper; } - public function getSettingsForm() { - if ( $this->canCreateAccounts() ) { - $noCreateMsg = false; - } else { - $noCreateMsg = 'config-db-web-no-create-privs'; - } - $s = $this->getWebUserBox( $noCreateMsg ); - - return $s; - } - - public function submitSettingsForm() { - $status = $this->submitWebUserBox(); - if ( !$status->isOK() ) { - return $status; - } - - $same = $this->getVar( 'wgDBuser' ) === $this->getVar( '_InstallUser' ); - - if ( $same ) { - $exists = true; - } else { - // Check if the web user exists - // Connect to the database with the install user - $status = $this->getPgConnection( 'create-db' ); - if ( !$status->isOK() ) { - return $status; - } - // @phan-suppress-next-line PhanUndeclaredMethod - $exists = $status->value->roleExists( $this->getVar( 'wgDBuser' ) ); - } - - // Validate the create checkbox - if ( $this->canCreateAccounts() && !$same && !$exists ) { - $create = $this->getVar( '_CreateDBAccount' ); - } else { - $this->setVar( '_CreateDBAccount', false ); - $create = false; - } - - if ( !$create && !$exists ) { - if ( $this->canCreateAccounts() ) { - $msg = 'config-install-user-missing-create'; - } else { - $msg = 'config-install-user-missing'; - } - - return Status::newFatal( $msg, $this->getVar( 'wgDBuser' ) ); - } - - if ( !$exists ) { - // No more checks to do - return Status::newGood(); - } - - // Existing web account. Test the connection. - $status = $this->openConnectionToAnyDB( - $this->getVar( 'wgDBuser' ), - $this->getVar( 'wgDBpassword' ) ); - if ( !$status->isOK() ) { - return $status; - } - - // The web user is conventionally the table owner in PostgreSQL - // installations. Make sure the install user is able to create - // objects on behalf of the web user. - if ( $same || $this->canCreateObjectsForWebUser() ) { - return Status::newGood(); - } else { - return Status::newFatal( 'config-pg-not-in-role' ); - } - } - /** * Returns true if the install user is able to create objects owned * by the web user, false otherwise. * @return bool */ - protected function canCreateObjectsForWebUser() { + public function canCreateObjectsForWebUser() { if ( $this->isSuperUser() ) { return true; } @@ -512,9 +359,8 @@ class PostgresInstaller extends DatabaseInstaller { if ( !$status->isOK() ) { return $status; } - /** @var DatabasePostgres $conn */ - $conn = $status->value; - '@phan-var DatabasePostgres $conn'; + $conn = $status->getDB(); + '@phan-var DatabasePostgres $conn'; /** @var DatabasePostgres $conn */ // Create the schema if necessary $schema = $this->getVar( 'wgDBmwschema' ); @@ -550,9 +396,8 @@ class PostgresInstaller extends DatabaseInstaller { if ( !$status->isOK() ) { return $status; } - /** @var DatabasePostgres $conn */ - $conn = $status->value; - '@phan-var DatabasePostgres $conn'; + $conn = $status->getDB(); + '@phan-var DatabasePostgres $conn'; /** @var DatabasePostgres $conn */ $safeuser = $conn->addIdentifierQuotes( $this->getVar( 'wgDBuser' ) ); $safepass = $conn->addQuotes( $this->getVar( 'wgDBpassword' ) ); @@ -608,10 +453,8 @@ class PostgresInstaller extends DatabaseInstaller { if ( !$status->isOK() ) { return $status; } - - /** @var DatabasePostgres $conn */ - $conn = $status->value; - '@phan-var DatabasePostgres $conn'; + $conn = $status->getDB(); + '@phan-var DatabasePostgres $conn'; /** @var DatabasePostgres $conn */ if ( $conn->tableExists( 'archive', __METHOD__ ) ) { $status->warning( 'config-install-tables-exist' ); @@ -671,10 +514,7 @@ class PostgresInstaller extends DatabaseInstaller { if ( !$status->isOK() ) { return $status; } - /** - * @var Database $conn - */ - $conn = $status->value; + $conn = $status->getDB(); $exists = (bool)$conn->selectField( '"pg_catalog"."pg_language"', '1', [ 'lanname' => 'plpgsql' ], __METHOD__ ); diff --git a/includes/installer/PostgresSettingsForm.php b/includes/installer/PostgresSettingsForm.php new file mode 100644 index 000000000000..370f893e1047 --- /dev/null +++ b/includes/installer/PostgresSettingsForm.php @@ -0,0 +1,96 @@ +<?php + +namespace MediaWiki\Installer; + +use MediaWiki\Status\Status; +use Wikimedia\Rdbms\DatabasePostgres; + +/** + * @internal + */ +class PostgresSettingsForm extends DatabaseSettingsForm { + + public function getHtml() { + if ( $this->getPostgresInstaller()->canCreateAccounts() ) { + $noCreateMsg = false; + } else { + $noCreateMsg = 'config-db-web-no-create-privs'; + } + $s = $this->getWebUserBox( $noCreateMsg ); + + return $s; + } + + public function submit() { + $status = $this->submitWebUserBox(); + if ( !$status->isOK() ) { + return $status; + } + + $same = $this->getVar( 'wgDBuser' ) === $this->getVar( '_InstallUser' ); + + if ( $same ) { + $exists = true; + } else { + // Check if the web user exists + // Connect to the database with the install user + $status = $this->getPostgresInstaller()->getPgConnection( 'create-db' ); + if ( !$status->isOK() ) { + return $status; + } + $conn = $status->getDB(); + '@phan-var DatabasePostgres $conn'; /** @var DatabasePostgres $conn */ + $exists = $conn->roleExists( $this->getVar( 'wgDBuser' ) ); + } + + // Validate the create checkbox + if ( $this->getPostgresInstaller()->canCreateAccounts() && !$same && !$exists ) { + $create = $this->getVar( '_CreateDBAccount' ); + } else { + $this->setVar( '_CreateDBAccount', false ); + $create = false; + } + + if ( !$create && !$exists ) { + if ( $this->getPostgresInstaller()->canCreateAccounts() ) { + $msg = 'config-install-user-missing-create'; + } else { + $msg = 'config-install-user-missing'; + } + + return Status::newFatal( $msg, $this->getVar( 'wgDBuser' ) ); + } + + if ( !$exists ) { + // No more checks to do + return Status::newGood(); + } + + // Existing web account. Test the connection. + $status = $this->getPostgresInstaller()->openConnectionToAnyDB( + $this->getVar( 'wgDBuser' ), + $this->getVar( 'wgDBpassword' ) ); + if ( !$status->isOK() ) { + return $status; + } + + // The web user is conventionally the table owner in PostgreSQL + // installations. Make sure the install user is able to create + // objects on behalf of the web user. + if ( $same || $this->getPostgresInstaller()->canCreateObjectsForWebUser() ) { + return Status::newGood(); + } else { + return Status::newFatal( 'config-pg-not-in-role' ); + } + } + + /** + * Downcast the DatabaseInstaller + * @return PostgresInstaller + */ + private function getPostgresInstaller(): PostgresInstaller { + // @phan-suppress-next-line PhanTypeMismatchReturnSuperType + return $this->dbInstaller; + } + +} diff --git a/includes/installer/SqliteConnectForm.php b/includes/installer/SqliteConnectForm.php new file mode 100644 index 000000000000..1eeedeeea1ef --- /dev/null +++ b/includes/installer/SqliteConnectForm.php @@ -0,0 +1,46 @@ +<?php + +namespace MediaWiki\Installer; + +use MediaWiki\Status\Status; + +/** + * @internal + */ +class SqliteConnectForm extends DatabaseConnectForm { + + public function getHtml() { + return $this->getTextBox( + 'wgSQLiteDataDir', + 'config-sqlite-dir', [], + $this->webInstaller->getHelpBox( 'config-sqlite-dir-help' ) + ) . + $this->getTextBox( + 'wgDBname', + 'config-db-name', + [], + $this->webInstaller->getHelpBox( 'config-sqlite-name-help' ) + ); + } + + /** + * @return Status + */ + public function submit() { + $this->setVarsFromRequest( [ 'wgSQLiteDataDir', 'wgDBname' ] ); + + # Try realpath() if the directory already exists + $dir = SqliteInstaller::realpath( $this->getVar( 'wgSQLiteDataDir' ) ); + $result = SqliteInstaller::checkDataDir( $dir ); + if ( $result->isOK() ) { + # Try expanding again in case we've just created it + $dir = SqliteInstaller::realpath( $dir ); + $this->setVar( 'wgSQLiteDataDir', $dir ); + } + # Table prefix is not used on SQLite, keep it empty + $this->setVar( 'wgDBprefix', '' ); + + return $result; + } + +} diff --git a/includes/installer/SqliteInstaller.php b/includes/installer/SqliteInstaller.php index 1d7dcda3967a..de553ae0747c 100644 --- a/includes/installer/SqliteInstaller.php +++ b/includes/installer/SqliteInstaller.php @@ -60,6 +60,14 @@ class SqliteInstaller extends DatabaseInstaller { return self::checkExtension( 'pdo_sqlite' ); } + public function getConnectForm( WebInstaller $webInstaller ): DatabaseConnectForm { + return new SqliteConnectForm( $webInstaller, $this ); + } + + public function getSettingsForm( WebInstaller $webInstaller ): DatabaseSettingsForm { + return new DatabaseSettingsForm( $webInstaller, $this ); + } + /** * @return Status */ @@ -92,20 +100,6 @@ class SqliteInstaller extends DatabaseInstaller { return $defaults; } - public function getConnectForm() { - return $this->getTextBox( - 'wgSQLiteDataDir', - 'config-sqlite-dir', [], - $this->parent->getHelpBox( 'config-sqlite-dir-help' ) - ) . - $this->getTextBox( - 'wgDBname', - 'config-db-name', - [], - $this->parent->getHelpBox( 'config-sqlite-name-help' ) - ); - } - /** * Safe wrapper for PHP's realpath() that fails gracefully if it's unable to canonicalize the path. * @@ -113,36 +107,16 @@ class SqliteInstaller extends DatabaseInstaller { * * @return string */ - private static function realpath( $path ) { + public static function realpath( $path ) { return realpath( $path ) ?: $path; } /** - * @return Status - */ - public function submitConnectForm() { - $this->setVarsFromRequest( [ 'wgSQLiteDataDir', 'wgDBname' ] ); - - # Try realpath() if the directory already exists - $dir = self::realpath( $this->getVar( 'wgSQLiteDataDir' ) ); - $result = self::checkDataDir( $dir ); - if ( $result->isOK() ) { - # Try expanding again in case we've just created it - $dir = self::realpath( $dir ); - $this->setVar( 'wgSQLiteDataDir', $dir ); - } - # Table prefix is not used on SQLite, keep it empty - $this->setVar( 'wgDBprefix', '' ); - - return $result; - } - - /** * Check if the data directory is writable or can be created * @param string $dir Path to the data directory * @return Status Return fatal Status if $dir un-writable or no permission to create a directory */ - private static function checkDataDir( $dir ): Status { + public static function checkDataDir( $dir ): Status { if ( is_dir( $dir ) ) { if ( !is_readable( $dir ) ) { return Status::newFatal( 'config-sqlite-dir-unwritable', $dir ); @@ -185,17 +159,17 @@ class SqliteInstaller extends DatabaseInstaller { } /** - * @return Status + * @return ConnectionStatus */ public function openConnection() { - $status = Status::newGood(); + $status = new ConnectionStatus; $dir = $this->getVar( 'wgSQLiteDataDir' ); $dbName = $this->getVar( 'wgDBname' ); try { $db = MediaWikiServices::getInstance()->getDatabaseFactory()->create( 'sqlite', [ 'dbname' => $dbName, 'dbDirectory' => $dir ] ); - $status->value = $db; + $status->setDB( $db ); } catch ( DBConnectionError $e ) { $status->fatal( 'config-sqlite-connection-error', $e->getMessage() ); } @@ -314,7 +288,7 @@ EOT; // when the DB is being read and written concurrently. // This causes the DB to be created in this mode // so we only have to do this on creation. - $mainConnStatus->value->query( "PRAGMA journal_mode=WAL", __METHOD__ ); + $mainConnStatus->getDB()->query( "PRAGMA journal_mode=WAL", __METHOD__ ); return $mainConnStatus; } diff --git a/includes/installer/WebInstallerDBConnect.php b/includes/installer/WebInstallerDBConnect.php index be54d08cf3c5..add5895c0238 100644 --- a/includes/installer/WebInstallerDBConnect.php +++ b/includes/installer/WebInstallerDBConnect.php @@ -98,7 +98,7 @@ class WebInstallerDBConnect extends WebInstallerPage { ] ) . Html::element( 'h3', [], wfMessage( 'config-header-' . $type )->text() ) . - $installer->getConnectForm() . + $installer->getConnectForm( $this->parent )->getHtml() . "</div>\n"; } @@ -126,7 +126,7 @@ class WebInstallerDBConnect extends WebInstallerPage { return Status::newFatal( 'config-invalid-db-type' ); } - return $installer->submitConnectForm(); + return $installer->getConnectForm( $this->parent )->submit(); } } diff --git a/includes/installer/WebInstallerDBSettings.php b/includes/installer/WebInstallerDBSettings.php index 1fd93811b393..b2cf463731c4 100644 --- a/includes/installer/WebInstallerDBSettings.php +++ b/includes/installer/WebInstallerDBSettings.php @@ -28,10 +28,11 @@ class WebInstallerDBSettings extends WebInstallerPage { */ public function execute() { $installer = $this->parent->getDBInstaller( $this->getVar( 'wgDBtype' ) ); + $form = $installer->getSettingsForm( $this->parent ); $r = $this->parent->request; if ( $r->wasPosted() ) { - $status = $installer->submitSettingsForm(); + $status = $form->submit(); if ( $status === false ) { return 'skip'; } elseif ( $status->isGood() ) { @@ -41,13 +42,13 @@ class WebInstallerDBSettings extends WebInstallerPage { } } - $form = $installer->getSettingsForm(); - if ( $form === false ) { + $formHtml = $form->getHtml(); + if ( $formHtml === false ) { return 'skip'; } $this->startForm(); - $this->addHTML( $form ); + $this->addHTML( $formHtml ); $this->endForm(); return null; |