X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;ds=sidebyside;f=includes%2Finstaller%2FDatabaseInstaller.php;h=ec7a5efdd1ad20c1895d8aad05d44db29068125c;hb=8fcd602c89b7872f5f3c94949e258935267fba5e;hp=45ad9abf4329c5a12d081b66b6f62d884f8df4f1;hpb=7b4d4d34801ac601b21206bac5a14432aa83ef45;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/installer/DatabaseInstaller.php b/includes/installer/DatabaseInstaller.php index 45ad9abf43..ec7a5efdd1 100644 --- a/includes/installer/DatabaseInstaller.php +++ b/includes/installer/DatabaseInstaller.php @@ -1,88 +1,108 @@ globalNames; - } + public abstract function isCompiled(); /** * Get HTML for a web form that configures this database. Configuration - * at this time should be the minimum needed to connect and test + * 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 + * If this is called, $this->parent can be assumed to be a WebInstaller. */ - abstract function getConnectForm(); + public abstract function getConnectForm(); /** * Set variables based on the request array, assuming it was submitted - * via the form returned by getConnectForm(). Validate the connection + * 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 + * If this is called, $this->parent can be assumed to be a WebInstaller. * * @return Status */ - abstract function submitConnectForm(); + public abstract 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 + * If the DB type has no settings beyond those already configured with * getConnectForm(), this should return false. */ - abstract function getSettingsForm(); + public function getSettingsForm() { + return false; + } /** * Set variables based on the request array, assuming it was submitted via * the form return by getSettingsForm(). + * * @return Status */ - abstract function submitSettingsForm(); + public function submitSettingsForm() { + return Status::newGood(); + } /** - * Connect to the database using the administrative user/password currently - * defined in the session. On success, return the connection, on failure, - * return a Status object. + * 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. * - * This may be called multiple times, so the result should be cached. - */ - abstract function getConnection(); - - /** - * Allow DB installers a chance to make last-minute changes before installation - * occurs. This happens before setupDatabase() or createTables() is called, but - * long after the constructor. Helpful for things like modifying setup steps :) + * @return Status */ - public function preInstall() {} + public abstract function openConnection(); /** * Create the database and return a Status object indicating success or @@ -90,48 +110,203 @@ abstract class DatabaseInstaller { * * @return Status */ - abstract function setupDatabase(); + public abstract function setupDatabase(); /** - * Create database tables from scratch - * @return \type Status + * Connect to the database using the administrative user/password currently + * defined in the session. Returns a status object. On success, the status + * object will contain a Database object in its value member. + * + * This will return a cached connection if one is available. + * + * @return Status */ - abstract function createTables(); + public function getConnection() { + if ( $this->db ) { + return Status::newGood( $this->db ); + } + $status = $this->openConnection(); + if ( $status->isOK() ) { + $this->db = $status->value; + // Enable autocommit + $this->db->clearFlag( DBO_TRX ); + $this->db->commit(); + } + return $status; + } /** - * Perform database upgrades - * @todo make abstract + * Create database tables from scratch. + * + * @return Status */ - /*abstract*/ function doUpgrade() { - return false; + public function createTables() { + $status = $this->getConnection(); + if ( !$status->isOK() ) { + return $status; + } + $this->db->selectDB( $this->getVar( 'wgDBname' ) ); + + if( $this->db->tableExists( 'user' ) ) { + $status->warning( 'config-install-tables-exist' ); + return $status; + } + + $this->db->setFlag( DBO_DDLMODE ); // For Oracle's handling of schema files + $this->db->begin( __METHOD__ ); + + $error = $this->db->sourceFile( $this->db->getSchema() ); + if( $error !== true ) { + $this->db->reportQueryError( $error, 0, '', __METHOD__ ); + $this->db->rollback( __METHOD__ ); + $status->fatal( 'config-install-tables-failed', $error ); + } else { + $this->db->commit( __METHOD__ ); + } + // Resume normal operations + if( $status->isOk() ) { + $this->enableLB(); + } + return $status; } /** - * Return any table options to be applied to all tables that don't - * override them - * @return Array + * Create the tables for each extension the user enabled + * @return Status */ - function getTableOptions() { - return array(); + public function createExtensionTables() { + $status = $this->getConnection(); + if ( !$status->isOK() ) { + return $status; + } + $updater = DatabaseUpdater::newForDB( $this->db ); + $extensionUpdates = $updater->getNewExtensions(); + + // No extensions need tables (or haven't updated to new installer support) + if( !count( $extensionUpdates ) ) { + return $status; + } + + $ourExtensions = array_map( 'strtolower', $this->getVar( '_Extensions' ) ); + + foreach( $ourExtensions as $ext ) { + if( isset( $extensionUpdates[$ext] ) ) { + $this->db->begin( __METHOD__ ); + $error = $this->db->sourceFile( $extensionUpdates[$ext] ); + if( $error !== true ) { + $this->db->rollback( __METHOD__ ); + $status->warning( 'config-install-tables-failed', $error ); + } else { + $this->db->commit( __METHOD__ ); + } + } + } + return $status; } /** * Get the DBMS-specific options for LocalSettings.php generation. + * * @return String */ - abstract function getLocalSettings(); + public abstract function getLocalSettings(); - /** + /** + * Override this to provide DBMS-specific schema variables, to be + * substituted into tables.sql and other schema files. + */ + public function getSchemaVars() { + return array(); + } + + /** + * Set appropriate schema variables in the current database connection. + * + * This should be called after any request data has been imported, but before + * any write operations to the database. + */ + public function setupSchemaVars() { + $status = $this->getConnection(); + if ( $status->isOK() ) { + $status->value->setSchemaVars( $this->getSchemaVars() ); + } else { + throw new MWException( __METHOD__.': unexpected DB connection error' ); + } + } + + /** + * Set up LBFactory so that wfGetDB() etc. works. + * We set up a special LBFactory instance which returns the current + * installer connection. + */ + public function enableLB() { + $status = $this->getConnection(); + if ( !$status->isOK() ) { + throw new MWException( __METHOD__.': unexpected DB connection error' ); + } + LBFactory::setInstance( new LBFactory_Single( array( + 'connection' => $status->value ) ) ); + } + + /** + * Perform database upgrades + * + * @return Boolean + */ + public function doUpgrade() { + $this->setupSchemaVars(); + $this->enableLB(); + + $ret = true; + ob_start( array( $this, 'outputHandler' ) ); + try { + $up = DatabaseUpdater::newForDB( $this->db ); + $up->doUpdates(); + } catch ( MWException $e ) { + echo "\nAn error occured:\n"; + echo $e->getText(); + $ret = false; + } + ob_end_flush(); + return $ret; + } + + /** + * Allow DB installers a chance to make last-minute changes before installation + * occurs. This happens before setupDatabase() or createTables() is called, but + * long after the constructor. Helpful for things like modifying setup steps :) + */ + public function preInstall() { + + } + + /** + * Allow DB installers a chance to make checks before upgrade. + */ + public function preUpgrade() { + + } + + /** + * Get an array of MW configuration globals that will be configured by this class. + */ + public function getGlobalNames() { + return $this->globalNames; + } + + /** * Construct and initialise parent. * This is typically only called from Installer::getDBInstaller() */ - function __construct( $parent ) { + public function __construct( $parent ) { $this->parent = $parent; } /** - * Convenience function - * Check if a named extension is present + * Convenience function. + * Check if a named extension is present. + * + * @see wfDl */ protected static function checkExtension( $name ) { wfSuppressWarnings(); @@ -141,31 +316,31 @@ abstract class DatabaseInstaller { } /** - * Get the internationalised name for this DBMS + * Get the internationalised name for this DBMS. */ - function getReadableName() { + public function getReadableName() { return wfMsg( 'config-type-' . $this->getName() ); } - + /** - * Get a name=>value map of MW configuration globals that overrides + * Get a name=>value map of MW configuration globals that overrides. * DefaultSettings.php */ - function getGlobalDefaults() { + public function getGlobalDefaults() { return array(); } /** - * Get a name=>value map of internal variables used during installation + * Get a name=>value map of internal variables used during installation. */ public function getInternalDefaults() { return $this->internalDefaults; } /** - * Get a variable, taking local defaults into account + * Get a variable, taking local defaults into account. */ - function getVar( $var, $default = null ) { + public function getVar( $var, $default = null ) { $defaults = $this->getGlobalDefaults(); $internal = $this->getInternalDefaults(); if ( isset( $defaults[$var] ) ) { @@ -179,45 +354,53 @@ abstract class DatabaseInstaller { /** * Convenience alias for $this->parent->setVar() */ - function setVar( $name, $value ) { + public function setVar( $name, $value ) { $this->parent->setVar( $name, $value ); } /** - * Get a labelled text box to configure a local variable + * Get a labelled text box to configure a local variable. */ - function getTextBox( $var, $label, $attribs = array() ) { + public function getTextBox( $var, $label, $attribs = array(), $helpData = "" ) { $name = $this->getName() . '_' . $var; $value = $this->getVar( $var ); + if ( !isset( $attribs ) ) { + $attribs = array(); + } return $this->parent->getTextBox( array( 'var' => $var, 'label' => $label, 'attribs' => $attribs, 'controlName' => $name, - 'value' => $value + 'value' => $value, + 'help' => $helpData ) ); } /** - * Get a labelled password box to configure a local variable - * Implements password hiding + * Get a labelled password box to configure a local variable. + * Implements password hiding. */ - function getPasswordBox( $var, $label, $attribs = array() ) { + public function getPasswordBox( $var, $label, $attribs = array(), $helpData = "" ) { $name = $this->getName() . '_' . $var; $value = $this->getVar( $var ); + if ( !isset( $attribs ) ) { + $attribs = array(); + } return $this->parent->getPasswordBox( array( 'var' => $var, 'label' => $label, 'attribs' => $attribs, 'controlName' => $name, - 'value' => $value + 'value' => $value, + 'help' => $helpData ) ); } /** - * Get a labelled checkbox to configure a local boolean variable + * Get a labelled checkbox to configure a local boolean variable. */ - function getCheckBox( $var, $label, $attribs = array() ) { + public function getCheckBox( $var, $label, $attribs = array(), $helpData = "" ) { $name = $this->getName() . '_' . $var; $value = $this->getVar( $var ); return $this->parent->getCheckBox( array( @@ -226,11 +409,12 @@ abstract class DatabaseInstaller { 'attribs' => $attribs, 'controlName' => $name, 'value' => $value, + 'help' => $helpData )); } /** - * Get a set of labelled radio buttons + * Get a set of labelled radio buttons. * * @param $params Array: * Parameters are: @@ -241,7 +425,7 @@ abstract class DatabaseInstaller { * itemAttribs Array of attribute arrays, outer key is the value name (optional) * */ - function getRadioSet( $params ) { + public function getRadioSet( $params ) { $params['controlName'] = $this->getName() . '_' . $params['var']; $params['value'] = $this->getVar( $params['var'] ); return $this->parent->getRadioSet( $params ); @@ -253,49 +437,50 @@ abstract class DatabaseInstaller { * fake) passwords. * @param $varNames Array */ - function setVarsFromRequest( $varNames ) { + public function setVarsFromRequest( $varNames ) { return $this->parent->setVarsFromRequest( $varNames, $this->getName() . '_' ); } /** - * Determine whether an existing installation of MediaWiki is present in - * the configured administrative connection. Returns true if there is + * Determine whether an existing installation of MediaWiki is present in + * the configured administrative connection. Returns true if there is * such a wiki, false if the database doesn't exist. * - * Traditionally, this is done by testing for the existence of either + * Traditionally, this is done by testing for the existence of either * the revision table or the cur table. * * @return Boolean */ - function needsUpgrade() { + public function needsUpgrade() { $status = $this->getConnection(); if ( !$status->isOK() ) { return false; } - $conn = $status->value; - if ( !$conn->selectDB( $this->getVar( 'wgDBname' ) ) ) { + + if ( !$this->db->selectDB( $this->getVar( 'wgDBname' ) ) ) { return false; } - return $conn->tableExists( 'cur' ) || $conn->tableExists( 'revision' ); + return $this->db->tableExists( 'cur' ) || $this->db->tableExists( 'revision' ); } /** - * Get a standard install-user fieldset + * Get a standard install-user fieldset. + * + * @return String */ - function getInstallUserBox() { + public function getInstallUserBox() { return - Xml::openElement( 'fieldset' ) . - Xml::element( 'legend', array(), wfMsg( 'config-db-install-account' ) ) . - $this->getTextBox( '_InstallUser', 'config-db-username' ) . - $this->getPasswordBox( '_InstallPassword', 'config-db-password' ) . - $this->parent->getHelpBox( 'config-db-install-help' ) . - Xml::closeElement( 'fieldset' ); + Html::openElement( 'fieldset' ) . + Html::element( 'legend', array(), wfMsg( 'config-db-install-account' ) ) . + $this->getTextBox( '_InstallUser', 'config-db-username', array(), $this->parent->getHelpBox( 'config-db-install-username' ) ) . + $this->getPasswordBox( '_InstallPassword', 'config-db-password', array(), $this->parent->getHelpBox( 'config-db-install-password' ) ) . + Html::closeElement( 'fieldset' ); } /** - * Submit a standard install user fieldset + * Submit a standard install user fieldset. */ - function submitInstallUserBox() { + public function submitInstallUserBox() { $this->setVarsFromRequest( array( '_InstallUser', '_InstallPassword' ) ); return Status::newGood(); } @@ -304,16 +489,17 @@ abstract class DatabaseInstaller { * Get a standard web-user fieldset * @param $noCreateMsg String: Message to display instead of the creation checkbox. * Set this to false to show a creation checkbox. + * + * @return String */ - function getWebUserBox( $noCreateMsg = false ) { - $name = $this->getName(); - $s = Xml::openElement( 'fieldset' ) . - Xml::element( 'legend', array(), wfMsg( 'config-db-web-account' ) ) . - $this->getCheckBox( + public function getWebUserBox( $noCreateMsg = false ) { + $s = Html::openElement( 'fieldset' ) . + Html::element( 'legend', array(), wfMsg( 'config-db-web-account' ) ) . + $this->getCheckBox( '_SameAccount', 'config-db-web-account-same', array( 'class' => 'hideShowRadio', 'rel' => 'dbOtherAccount' ) ) . - Xml::openElement( 'div', array( 'id' => 'dbOtherAccount', 'style' => 'display: none;' ) ) . + Html::openElement( 'div', array( 'id' => 'dbOtherAccount', 'style' => 'display: none;' ) ) . $this->getTextBox( 'wgDBuser', 'config-db-username' ) . $this->getPasswordBox( 'wgDBpassword', 'config-db-password' ) . $this->parent->getHelpBox( 'config-db-web-help' ); @@ -322,26 +508,36 @@ abstract class DatabaseInstaller { } else { $s .= $this->getCheckBox( '_CreateDBAccount', 'config-db-web-create' ); } - $s .= Xml::closeElement( 'div' ) . Xml::closeElement( 'fieldset' ); + $s .= Html::closeElement( 'div' ) . Html::closeElement( 'fieldset' ); return $s; } /** * Submit the form from getWebUserBox(). + * * @return Status */ - function submitWebUserBox() { - $this->setVarsFromRequest( array( 'wgDBuser', 'wgDBpassword', - '_SameAccount', '_CreateDBAccount' ) ); + public function submitWebUserBox() { + $this->setVarsFromRequest( + array( '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.sql + * Common function for databases that don't understand the MySQLish syntax of interwiki.sql. + * + * @return Status */ public function populateInterwikiTable() { $status = $this->getConnection(); @@ -355,17 +551,20 @@ abstract class DatabaseInstaller { return $status; } global $IP; + wfSuppressWarnings(); $rows = file( "$IP/maintenance/interwiki.list", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES ); + wfRestoreWarnings(); $interwikis = array(); if ( !$rows ) { - return Status::newFatal( 'config-install-interwiki-sql' ); + return Status::newFatal( 'config-install-interwiki-list' ); } foreach( $rows as $row ) { $row = preg_replace( '/^\s*([^#]*?)\s*(#.*)?$/', '\\1', $row ); // strip comments - whee if ( $row == "" ) continue; + $row .= "||"; $interwikis[] = array_combine( - array( 'iw_prefix', 'iw_url', 'iw_local' ), + array( 'iw_prefix', 'iw_url', 'iw_local', 'iw_api', 'iw_wikiid' ), explode( '|', $row ) ); } @@ -373,5 +572,7 @@ abstract class DatabaseInstaller { return Status::newGood(); } + public function outputHandler( $string ) { + return htmlspecialchars( $string ); + } } -