Localisation updates from https://translatewiki.net.
[mediawiki.git] / includes / installer / DatabaseInstaller.php
blob6a849ec78b7cab09dd294f9a46c4bc780494a303
1 <?php
3 /**
4 * DBMS-specific installation helper.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * http://www.gnu.org/copyleft/gpl.html
21 * @file
22 * @ingroup Installer
25 namespace MediaWiki\Installer;
27 use MediaWiki\Installer\Task\ITaskContext;
28 use MediaWiki\Status\Status;
29 use RuntimeException;
30 use Wikimedia\Rdbms\DatabaseDomain;
31 use Wikimedia\Rdbms\IDatabase;
32 use Wikimedia\Rdbms\IMaintainableDatabase;
34 /**
35 * Base class for DBMS-specific installation helper classes.
37 * @ingroup Installer
38 * @since 1.17
40 abstract class DatabaseInstaller implements ITaskContext {
42 /**
43 * The Installer object.
45 * @var Installer
47 public $parent;
49 /**
50 * @var string Set by subclasses
52 public static $minimumVersion;
54 /**
55 * @var string Set by subclasses
57 protected static $notMinimumVersionMessage;
59 /**
60 * @deprecated since 1.43 -- use definitelyGetConnection()
61 * @var IMaintainableDatabase
63 public $db = null;
65 /** @var IMaintainableDatabase|null */
66 private $cachedConn;
67 /** @var string|null */
68 private $cachedConnType;
70 /**
71 * Internal variables for installation.
73 * @var array
75 protected $internalDefaults = [];
77 /**
78 * Array of MW configuration globals this class uses.
80 * @var array
82 protected $globalNames = [];
84 /** @var array */
85 private $provisions = [];
87 /**
88 * Whether the provided version meets the necessary requirements for this type
90 * @param IDatabase $conn
91 * @return Status
92 * @since 1.30
94 public static function meetsMinimumRequirement( IDatabase $conn ) {
95 $serverVersion = $conn->getServerVersion();
96 if ( version_compare( $serverVersion, static::$minimumVersion ) < 0 ) {
97 return Status::newFatal(
98 static::$notMinimumVersionMessage, static::$minimumVersion, $serverVersion
102 return Status::newGood();
106 * Return the internal name, e.g. 'mysql', or 'sqlite'.
108 abstract public function getName();
111 * @return bool Returns true if the client library is compiled in.
113 abstract public function isCompiled();
116 * Checks for installation prerequisites other than those checked by isCompiled()
117 * @since 1.19
118 * @return Status
120 public function checkPrerequisites() {
121 return Status::newGood();
125 * Open a connection to the database using the administrative user/password
126 * currently defined in the session, without any caching. Returns a status
127 * object. On success, the status object will contain a Database object in
128 * its value member.
130 * The database should not be implicitly created.
132 * @param string $type One of the self::CONN_* constants, except CONN_DONT_KNOW
133 * @return ConnectionStatus
135 abstract protected function openConnection( string $type );
138 * Connect to the database using the administrative user/password currently
139 * defined in the session. Returns a status object. On success, the status
140 * object will contain a Database object in its value member.
142 * This will return a cached connection if one is available.
144 * @param string $type One of the self::CONN_* constants. Using CONN_DONT_KNOW
145 * is deprecated and will cause an exception to be thrown in a future release.
146 * @return ConnectionStatus
148 public function getConnection( $type = self::CONN_DONT_KNOW ): ConnectionStatus {
149 if ( $type === self::CONN_DONT_KNOW ) {
150 if ( $this->cachedConnType ) {
151 $type = $this->cachedConnType;
152 } else {
153 $type = self::CONN_CREATE_DATABASE;
156 if ( $this->cachedConn ) {
157 if ( $this->cachedConnType === $type ) {
158 return new ConnectionStatus( $this->cachedConn );
159 } else {
160 return $this->changeConnType( $this->cachedConn, $this->cachedConnType, $type );
163 $status = $this->openConnection( $type );
164 if ( $status->isOK() ) {
165 $this->cachedConn = $status->getDB();
166 $this->cachedConnType = $type;
167 // Assign to $this->db for b/c
168 $this->db = $this->cachedConn;
170 if ( $type === self::CONN_CREATE_SCHEMA || $type === self::CONN_CREATE_TABLES ) {
171 $this->cachedConn->setSchemaVars( $this->getSchemaVars() );
175 return $status;
179 * Get a connection and unwrap it from its Status object, throwing an
180 * exception on failure.
182 * @param string $type
183 * @return IMaintainableDatabase
185 public function definitelyGetConnection( string $type ): IMaintainableDatabase {
186 $status = $this->getConnection( $type );
187 if ( !$status->isOK() ) {
188 throw new RuntimeException( __METHOD__ . ': unexpected DB connection error' );
190 return $status->getDB();
194 * Change the type of a connection.
196 * CONN_CREATE_DATABASE means the domain is indeterminate and irrelevant,
197 * so converting from this type can be done by selecting the domain, and
198 * converting to it is a no-op.
200 * CONN_CREATE_SCHEMA means the domain is correct but tables created by
201 * PostgreSQL will have the incorrect role. So to convert from this to
202 * CONN_CREATE_TABLES, we set the role.
204 * CONN_CREATE_TABLES means a fully-configured connection, suitable for
205 * most tasks, so converting from it is a no-op.
207 * @param IMaintainableDatabase $conn
208 * @param string &$storedType One of the self::CONN_* constants. An in/out
209 * parameter, set to the new type on success. It is set to the "real" new
210 * type, reflecting the highest configuration level reached, to avoid
211 * unnecessary selectDomain() calls when we need to temporarily give an
212 * unconfigured connection.
213 * @param string $newType One of the self::CONN_* constants
214 * @return ConnectionStatus
216 protected function changeConnType( IMaintainableDatabase $conn, &$storedType, $newType ) {
217 // Change type from database to schema, if requested
218 if ( $storedType === self::CONN_CREATE_DATABASE ) {
219 if ( $newType === self::CONN_CREATE_SCHEMA || $newType === self::CONN_CREATE_TABLES ) {
220 // TODO: catch exceptions from selectDomain and report as a Status
221 $conn->selectDomain( new DatabaseDomain(
222 $this->getVar( 'wgDBname' ),
223 $this->getVar( 'wgDBmwschema' ),
224 $this->getVar( 'wgDBprefix' ) ?? ''
225 ) );
226 $conn->setSchemaVars( $this->getSchemaVars() );
227 $storedType = self::CONN_CREATE_SCHEMA;
230 // Change type from schema to tables, if requested
231 if ( $newType === self::CONN_CREATE_TABLES && $storedType === self::CONN_CREATE_SCHEMA ) {
232 $status = $this->changeConnTypeFromSchemaToTables( $conn );
233 if ( $status->isOK() ) {
234 $storedType = self::CONN_CREATE_TABLES;
236 return $status;
238 return new ConnectionStatus( $conn );
242 * Change the type of a connection from CONN_CREATE_SCHEMA to CONN_CREATE_TABLES.
243 * Postgres overrides this.
245 * @param IMaintainableDatabase $conn
246 * @return ConnectionStatus
248 protected function changeConnTypeFromSchemaToTables( IMaintainableDatabase $conn ) {
249 return new ConnectionStatus( $conn );
252 public function getDbType(): string {
253 return $this->getName();
256 public function getConfigVar( string $name ) {
257 return $this->getVar( "wg$name" );
260 public function getOption( string $name ) {
261 return $this->getVar( "_$name" );
264 public function provide( string $name, $value ) {
265 $this->provisions[$name] = $value;
268 public function getProvision( string $name ) {
269 if ( isset( $this->provisions[$name] ) ) {
270 return $this->provisions[$name];
271 } else {
272 throw new \RuntimeException( "Can't find provided data \"$name\"" );
277 * Get the DBMS-specific options for LocalSettings.php generation.
279 * @return string
281 abstract public function getLocalSettings();
284 * Override this to provide DBMS-specific schema variables, to be
285 * substituted into the schema files.
286 * @return array
288 public function getSchemaVars() {
289 return [];
293 * Allow DB installers a chance to make checks before upgrade.
295 public function preUpgrade() {
299 * Get an array of MW configuration globals that will be configured by this class.
300 * @return array
302 public function getGlobalNames() {
303 return $this->globalNames;
307 * Construct and initialise parent.
308 * This is typically only called from Installer::getDBInstaller()
309 * @param Installer $parent
311 public function __construct( $parent ) {
312 $this->parent = $parent;
316 * Convenience function.
317 * Check if a named extension is present.
319 * @param string $name
320 * @return bool
322 protected static function checkExtension( $name ) {
323 return extension_loaded( $name );
327 * Get the internationalised name for this DBMS.
328 * @return string
330 public function getReadableName() {
331 // Messages: config-type-mysql, config-type-postgres, config-type-sqlite
332 return wfMessage( 'config-type-' . $this->getName() )->text();
336 * Get a name=>value map of MW configuration globals for the default values.
337 * @return array
338 * @return-taint none
340 public function getGlobalDefaults() {
341 $defaults = [];
342 foreach ( $this->getGlobalNames() as $var ) {
343 if ( isset( $GLOBALS[$var] ) ) {
344 $defaults[$var] = $GLOBALS[$var];
347 return $defaults;
351 * Get a name=>value map of internal variables used during installation.
352 * @return array
354 public function getInternalDefaults() {
355 return $this->internalDefaults;
359 * Get a variable, taking local defaults into account.
360 * @param string $var
361 * @param mixed|null $default
362 * @return mixed
364 public function getVar( $var, $default = null ) {
365 $defaults = $this->getGlobalDefaults();
366 $internal = $this->getInternalDefaults();
367 if ( isset( $defaults[$var] ) ) {
368 $default = $defaults[$var];
369 } elseif ( isset( $internal[$var] ) ) {
370 $default = $internal[$var];
373 return $this->parent->getVar( $var, $default );
377 * Convenience alias for $this->parent->setVar()
378 * @param string $name
379 * @param mixed $value
381 public function setVar( $name, $value ) {
382 $this->parent->setVar( $name, $value );
385 abstract public function getConnectForm( WebInstaller $webInstaller ): DatabaseConnectForm;
387 abstract public function getSettingsForm( WebInstaller $webInstaller ): DatabaseSettingsForm;
390 * Determine whether an existing installation of MediaWiki is present in
391 * the configured administrative connection. Returns true if there is
392 * such a wiki, false if the database doesn't exist.
394 * Traditionally, this is done by testing for the existence of either
395 * the revision table or the cur table.
397 * @return bool
399 public function needsUpgrade() {
400 $status = $this->getConnection( self::CONN_CREATE_SCHEMA );
401 if ( !$status->isOK() ) {
402 return false;
404 $db = $status->getDB();
405 return $db->tableExists( 'cur', __METHOD__ ) ||
406 $db->tableExists( 'revision', __METHOD__ );