MediaWiki  master
DatabaseFactory.php
Go to the documentation of this file.
1 <?php
20 namespace Wikimedia\Rdbms;
21 
22 use HashBagOStuff;
23 use InvalidArgumentException;
24 use Psr\Log\NullLogger;
25 use Throwable;
26 
34 
86  public function create( $type, $params = [], $connect = Database::NEW_CONNECTED ) {
87  $class = $this->getClass( $type, $params['driver'] ?? null );
88 
89  if ( class_exists( $class ) && is_subclass_of( $class, IDatabase::class ) ) {
90  $params += [
91  // Default configuration
92  'host' => null,
93  'user' => null,
94  'password' => null,
95  'dbname' => null,
96  'schema' => null,
97  'tablePrefix' => '',
98  'flags' => 0,
99  'variables' => [],
100  'lbInfo' => [],
101  'cliMode' => ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' ),
102  'agent' => '',
103  'serverName' => null,
104  'topologyRole' => null,
105  // Objects and callbacks
106  'srvCache' => $params['srvCache'] ?? new HashBagOStuff(),
107  'profiler' => $params['profiler'] ?? null,
108  'trxProfiler' => $params['trxProfiler'] ?? new TransactionProfiler(),
109  'logger' => $params['logger'] ?? new NullLogger(),
110  'errorLogger' => $params['errorLogger'] ?? static function ( Throwable $e ) {
111  trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
112  },
113  'deprecationLogger' => $params['deprecationLogger'] ?? static function ( $msg ) {
114  trigger_error( $msg, E_USER_DEPRECATED );
115  }
116  ];
117 
119  $conn = new $class( $params );
120  if ( $connect === Database::NEW_CONNECTED ) {
121  $conn->initConnection();
122  }
123  } else {
124  $conn = null;
125  }
126 
127  return $conn;
128  }
129 
136  public function attributesFromType( $dbType, $driver = null ) {
137  static $defaults = [
138  Database::ATTR_DB_IS_FILE => false,
139  Database::ATTR_DB_LEVEL_LOCKING => false,
140  Database::ATTR_SCHEMAS_AS_TABLE_GROUPS => false
141  ];
142 
143  $class = $this->getClass( $dbType, $driver );
144  if ( class_exists( $class ) ) {
145  return call_user_func( [ $class, 'getAttributes' ] ) + $defaults;
146  } else {
147  throw new DBUnexpectedError( null, "$dbType is not a supported database type." );
148  }
149  }
150 
157  protected function getClass( $dbType, $driver = null ) {
158  // For database types with built-in support, the below maps type to IDatabase
159  // implementations. For types with multiple driver implementations (PHP extensions),
160  // an array can be used, keyed by extension name. In case of an array, the
161  // optional 'driver' parameter can be used to force a specific driver. Otherwise,
162  // we auto-detect the first available driver. For types without built-in support,
163  // a class named "Database<Type>" is used, eg. DatabaseFoo for type 'foo'.
164  static $builtinTypes = [
165  'mysql' => [ 'mysqli' => DatabaseMysqli::class ],
166  'sqlite' => DatabaseSqlite::class,
167  'postgres' => DatabasePostgres::class,
168  ];
169 
170  $dbType = strtolower( $dbType );
171 
172  if ( !isset( $builtinTypes[$dbType] ) ) {
173  // Not a built in type, assume standard naming scheme
174  return 'Database' . ucfirst( $dbType );
175  }
176 
177  $class = false;
178  $possibleDrivers = $builtinTypes[$dbType];
179  if ( is_string( $possibleDrivers ) ) {
180  $class = $possibleDrivers;
181  } elseif ( (string)$driver !== '' ) {
182  if ( !isset( $possibleDrivers[$driver] ) ) {
183  throw new InvalidArgumentException( __METHOD__ .
184  " type '$dbType' does not support driver '{$driver}'" );
185  }
186 
187  $class = $possibleDrivers[$driver];
188  } else {
189  foreach ( $possibleDrivers as $posDriver => $possibleClass ) {
190  if ( extension_loaded( $posDriver ) ) {
191  $class = $possibleClass;
192  break;
193  }
194  }
195  }
196 
197  if ( $class === false ) {
198  throw new InvalidArgumentException( __METHOD__ .
199  " no viable database extension found for type '$dbType'" );
200  }
201 
202  return $class;
203  }
204 }
Simple store for keeping values in an associative array for the current process.
Constructs Database objects.
attributesFromType( $dbType, $driver=null)
getClass( $dbType, $driver=null)
create( $type, $params=[], $connect=Database::NEW_CONNECTED)
Construct a Database subclass instance given a database type and parameters.
Detect high-contention DB queries via profiling calls.