Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Core\Database;
|
Chris@0
|
4
|
Chris@0
|
5 /**
|
Chris@0
|
6 * Primary front-controller for the database system.
|
Chris@0
|
7 *
|
Chris@0
|
8 * This class is uninstantiatable and un-extendable. It acts to encapsulate
|
Chris@0
|
9 * all control and shepherding of database connections into a single location
|
Chris@0
|
10 * without the use of globals.
|
Chris@0
|
11 */
|
Chris@0
|
12 abstract class Database {
|
Chris@0
|
13
|
Chris@0
|
14 /**
|
Chris@0
|
15 * Flag to indicate a query call should simply return NULL.
|
Chris@0
|
16 *
|
Chris@0
|
17 * This is used for queries that have no reasonable return value anyway, such
|
Chris@0
|
18 * as INSERT statements to a table without a serial primary key.
|
Chris@0
|
19 */
|
Chris@0
|
20 const RETURN_NULL = 0;
|
Chris@0
|
21
|
Chris@0
|
22 /**
|
Chris@0
|
23 * Flag to indicate a query call should return the prepared statement.
|
Chris@0
|
24 */
|
Chris@0
|
25 const RETURN_STATEMENT = 1;
|
Chris@0
|
26
|
Chris@0
|
27 /**
|
Chris@0
|
28 * Flag to indicate a query call should return the number of affected rows.
|
Chris@0
|
29 */
|
Chris@0
|
30 const RETURN_AFFECTED = 2;
|
Chris@0
|
31
|
Chris@0
|
32 /**
|
Chris@0
|
33 * Flag to indicate a query call should return the "last insert id".
|
Chris@0
|
34 */
|
Chris@0
|
35 const RETURN_INSERT_ID = 3;
|
Chris@0
|
36
|
Chris@0
|
37 /**
|
Chris@0
|
38 * An nested array of all active connections. It is keyed by database name
|
Chris@0
|
39 * and target.
|
Chris@0
|
40 *
|
Chris@0
|
41 * @var array
|
Chris@0
|
42 */
|
Chris@18
|
43 protected static $connections = [];
|
Chris@0
|
44
|
Chris@0
|
45 /**
|
Chris@0
|
46 * A processed copy of the database connection information from settings.php.
|
Chris@0
|
47 *
|
Chris@0
|
48 * @var array
|
Chris@0
|
49 */
|
Chris@18
|
50 protected static $databaseInfo = [];
|
Chris@0
|
51
|
Chris@0
|
52 /**
|
Chris@0
|
53 * A list of key/target credentials to simply ignore.
|
Chris@0
|
54 *
|
Chris@0
|
55 * @var array
|
Chris@0
|
56 */
|
Chris@18
|
57 protected static $ignoreTargets = [];
|
Chris@0
|
58
|
Chris@0
|
59 /**
|
Chris@0
|
60 * The key of the currently active database connection.
|
Chris@0
|
61 *
|
Chris@0
|
62 * @var string
|
Chris@0
|
63 */
|
Chris@18
|
64 protected static $activeKey = 'default';
|
Chris@0
|
65
|
Chris@0
|
66 /**
|
Chris@0
|
67 * An array of active query log objects.
|
Chris@0
|
68 *
|
Chris@0
|
69 * Every connection has one and only one logger object for all targets and
|
Chris@0
|
70 * logging keys.
|
Chris@0
|
71 *
|
Chris@0
|
72 * array(
|
Chris@0
|
73 * '$db_key' => DatabaseLog object.
|
Chris@0
|
74 * );
|
Chris@0
|
75 *
|
Chris@0
|
76 * @var array
|
Chris@0
|
77 */
|
Chris@18
|
78 protected static $logs = [];
|
Chris@0
|
79
|
Chris@0
|
80 /**
|
Chris@0
|
81 * Starts logging a given logging key on the specified connection.
|
Chris@0
|
82 *
|
Chris@0
|
83 * @param string $logging_key
|
Chris@0
|
84 * The logging key to log.
|
Chris@0
|
85 * @param string $key
|
Chris@0
|
86 * The database connection key for which we want to log.
|
Chris@0
|
87 *
|
Chris@0
|
88 * @return \Drupal\Core\Database\Log
|
Chris@0
|
89 * The query log object. Note that the log object does support richer
|
Chris@0
|
90 * methods than the few exposed through the Database class, so in some
|
Chris@0
|
91 * cases it may be desirable to access it directly.
|
Chris@0
|
92 *
|
Chris@0
|
93 * @see \Drupal\Core\Database\Log
|
Chris@0
|
94 */
|
Chris@0
|
95 final public static function startLog($logging_key, $key = 'default') {
|
Chris@0
|
96 if (empty(self::$logs[$key])) {
|
Chris@0
|
97 self::$logs[$key] = new Log($key);
|
Chris@0
|
98
|
Chris@0
|
99 // Every target already active for this connection key needs to have the
|
Chris@0
|
100 // logging object associated with it.
|
Chris@0
|
101 if (!empty(self::$connections[$key])) {
|
Chris@0
|
102 foreach (self::$connections[$key] as $connection) {
|
Chris@0
|
103 $connection->setLogger(self::$logs[$key]);
|
Chris@0
|
104 }
|
Chris@0
|
105 }
|
Chris@0
|
106 }
|
Chris@0
|
107
|
Chris@0
|
108 self::$logs[$key]->start($logging_key);
|
Chris@0
|
109 return self::$logs[$key];
|
Chris@0
|
110 }
|
Chris@0
|
111
|
Chris@0
|
112 /**
|
Chris@0
|
113 * Retrieves the queries logged on for given logging key.
|
Chris@0
|
114 *
|
Chris@0
|
115 * This method also ends logging for the specified key. To get the query log
|
Chris@0
|
116 * to date without ending the logger request the logging object by starting
|
Chris@0
|
117 * it again (which does nothing to an open log key) and call methods on it as
|
Chris@0
|
118 * desired.
|
Chris@0
|
119 *
|
Chris@0
|
120 * @param string $logging_key
|
Chris@0
|
121 * The logging key to log.
|
Chris@0
|
122 * @param string $key
|
Chris@0
|
123 * The database connection key for which we want to log.
|
Chris@0
|
124 *
|
Chris@0
|
125 * @return array
|
Chris@0
|
126 * The query log for the specified logging key and connection.
|
Chris@0
|
127 *
|
Chris@0
|
128 * @see \Drupal\Core\Database\Log
|
Chris@0
|
129 */
|
Chris@0
|
130 final public static function getLog($logging_key, $key = 'default') {
|
Chris@0
|
131 if (empty(self::$logs[$key])) {
|
Chris@0
|
132 return [];
|
Chris@0
|
133 }
|
Chris@0
|
134 $queries = self::$logs[$key]->get($logging_key);
|
Chris@0
|
135 self::$logs[$key]->end($logging_key);
|
Chris@0
|
136 return $queries;
|
Chris@0
|
137 }
|
Chris@0
|
138
|
Chris@0
|
139 /**
|
Chris@0
|
140 * Gets the connection object for the specified database key and target.
|
Chris@0
|
141 *
|
Chris@0
|
142 * @param string $target
|
Chris@0
|
143 * The database target name.
|
Chris@0
|
144 * @param string $key
|
Chris@0
|
145 * The database connection key. Defaults to NULL which means the active key.
|
Chris@0
|
146 *
|
Chris@0
|
147 * @return \Drupal\Core\Database\Connection
|
Chris@0
|
148 * The corresponding connection object.
|
Chris@0
|
149 */
|
Chris@0
|
150 final public static function getConnection($target = 'default', $key = NULL) {
|
Chris@0
|
151 if (!isset($key)) {
|
Chris@0
|
152 // By default, we want the active connection, set in setActiveConnection.
|
Chris@0
|
153 $key = self::$activeKey;
|
Chris@0
|
154 }
|
Chris@0
|
155 // If the requested target does not exist, or if it is ignored, we fall back
|
Chris@0
|
156 // to the default target. The target is typically either "default" or
|
Chris@0
|
157 // "replica", indicating to use a replica SQL server if one is available. If
|
Chris@0
|
158 // it's not available, then the default/primary server is the correct server
|
Chris@0
|
159 // to use.
|
Chris@0
|
160 if (!empty(self::$ignoreTargets[$key][$target]) || !isset(self::$databaseInfo[$key][$target])) {
|
Chris@0
|
161 $target = 'default';
|
Chris@0
|
162 }
|
Chris@0
|
163
|
Chris@0
|
164 if (!isset(self::$connections[$key][$target])) {
|
Chris@0
|
165 // If necessary, a new connection is opened.
|
Chris@0
|
166 self::$connections[$key][$target] = self::openConnection($key, $target);
|
Chris@0
|
167 }
|
Chris@0
|
168 return self::$connections[$key][$target];
|
Chris@0
|
169 }
|
Chris@0
|
170
|
Chris@0
|
171 /**
|
Chris@0
|
172 * Determines if there is an active connection.
|
Chris@0
|
173 *
|
Chris@0
|
174 * Note that this method will return FALSE if no connection has been
|
Chris@0
|
175 * established yet, even if one could be.
|
Chris@0
|
176 *
|
Chris@0
|
177 * @return bool
|
Chris@0
|
178 * TRUE if there is at least one database connection established, FALSE
|
Chris@0
|
179 * otherwise.
|
Chris@0
|
180 */
|
Chris@0
|
181 final public static function isActiveConnection() {
|
Chris@0
|
182 return !empty(self::$activeKey) && !empty(self::$connections) && !empty(self::$connections[self::$activeKey]);
|
Chris@0
|
183 }
|
Chris@0
|
184
|
Chris@0
|
185 /**
|
Chris@0
|
186 * Sets the active connection to the specified key.
|
Chris@0
|
187 *
|
Chris@0
|
188 * @return string|null
|
Chris@0
|
189 * The previous database connection key.
|
Chris@0
|
190 */
|
Chris@0
|
191 final public static function setActiveConnection($key = 'default') {
|
Chris@0
|
192 if (!empty(self::$databaseInfo[$key])) {
|
Chris@0
|
193 $old_key = self::$activeKey;
|
Chris@0
|
194 self::$activeKey = $key;
|
Chris@0
|
195 return $old_key;
|
Chris@0
|
196 }
|
Chris@0
|
197 }
|
Chris@0
|
198
|
Chris@0
|
199 /**
|
Chris@0
|
200 * Process the configuration file for database information.
|
Chris@0
|
201 *
|
Chris@0
|
202 * @param array $info
|
Chris@0
|
203 * The database connection information, as defined in settings.php. The
|
Chris@0
|
204 * structure of this array depends on the database driver it is connecting
|
Chris@0
|
205 * to.
|
Chris@0
|
206 */
|
Chris@0
|
207 final public static function parseConnectionInfo(array $info) {
|
Chris@0
|
208 // If there is no "driver" property, then we assume it's an array of
|
Chris@0
|
209 // possible connections for this target. Pick one at random. That allows
|
Chris@0
|
210 // us to have, for example, multiple replica servers.
|
Chris@0
|
211 if (empty($info['driver'])) {
|
Chris@0
|
212 $info = $info[mt_rand(0, count($info) - 1)];
|
Chris@0
|
213 }
|
Chris@0
|
214 // Parse the prefix information.
|
Chris@0
|
215 if (!isset($info['prefix'])) {
|
Chris@0
|
216 // Default to an empty prefix.
|
Chris@0
|
217 $info['prefix'] = [
|
Chris@0
|
218 'default' => '',
|
Chris@0
|
219 ];
|
Chris@0
|
220 }
|
Chris@0
|
221 elseif (!is_array($info['prefix'])) {
|
Chris@0
|
222 // Transform the flat form into an array form.
|
Chris@0
|
223 $info['prefix'] = [
|
Chris@0
|
224 'default' => $info['prefix'],
|
Chris@0
|
225 ];
|
Chris@0
|
226 }
|
Chris@0
|
227 return $info;
|
Chris@0
|
228 }
|
Chris@0
|
229
|
Chris@0
|
230 /**
|
Chris@0
|
231 * Adds database connection information for a given key/target.
|
Chris@0
|
232 *
|
Chris@0
|
233 * This method allows to add new connections at runtime.
|
Chris@0
|
234 *
|
Chris@0
|
235 * Under normal circumstances the preferred way to specify database
|
Chris@0
|
236 * credentials is via settings.php. However, this method allows them to be
|
Chris@0
|
237 * added at arbitrary times, such as during unit tests, when connecting to
|
Chris@0
|
238 * admin-defined third party databases, etc.
|
Chris@0
|
239 *
|
Chris@0
|
240 * If the given key/target pair already exists, this method will be ignored.
|
Chris@0
|
241 *
|
Chris@0
|
242 * @param string $key
|
Chris@0
|
243 * The database key.
|
Chris@0
|
244 * @param string $target
|
Chris@0
|
245 * The database target name.
|
Chris@0
|
246 * @param array $info
|
Chris@0
|
247 * The database connection information, as defined in settings.php. The
|
Chris@0
|
248 * structure of this array depends on the database driver it is connecting
|
Chris@0
|
249 * to.
|
Chris@0
|
250 */
|
Chris@0
|
251 final public static function addConnectionInfo($key, $target, array $info) {
|
Chris@0
|
252 if (empty(self::$databaseInfo[$key][$target])) {
|
Chris@0
|
253 self::$databaseInfo[$key][$target] = self::parseConnectionInfo($info);
|
Chris@0
|
254 }
|
Chris@0
|
255 }
|
Chris@0
|
256
|
Chris@0
|
257 /**
|
Chris@0
|
258 * Gets information on the specified database connection.
|
Chris@0
|
259 *
|
Chris@0
|
260 * @param string $key
|
Chris@0
|
261 * (optional) The connection key for which to return information.
|
Chris@0
|
262 *
|
Chris@0
|
263 * @return array|null
|
Chris@0
|
264 */
|
Chris@0
|
265 final public static function getConnectionInfo($key = 'default') {
|
Chris@0
|
266 if (!empty(self::$databaseInfo[$key])) {
|
Chris@0
|
267 return self::$databaseInfo[$key];
|
Chris@0
|
268 }
|
Chris@0
|
269 }
|
Chris@0
|
270
|
Chris@0
|
271 /**
|
Chris@0
|
272 * Gets connection information for all available databases.
|
Chris@0
|
273 *
|
Chris@0
|
274 * @return array
|
Chris@0
|
275 */
|
Chris@0
|
276 final public static function getAllConnectionInfo() {
|
Chris@0
|
277 return self::$databaseInfo;
|
Chris@0
|
278 }
|
Chris@0
|
279
|
Chris@0
|
280 /**
|
Chris@0
|
281 * Sets connection information for multiple databases.
|
Chris@0
|
282 *
|
Chris@0
|
283 * @param array $databases
|
Chris@0
|
284 * A multi-dimensional array specifying database connection parameters, as
|
Chris@0
|
285 * defined in settings.php.
|
Chris@0
|
286 */
|
Chris@0
|
287 final public static function setMultipleConnectionInfo(array $databases) {
|
Chris@0
|
288 foreach ($databases as $key => $targets) {
|
Chris@0
|
289 foreach ($targets as $target => $info) {
|
Chris@0
|
290 self::addConnectionInfo($key, $target, $info);
|
Chris@0
|
291 }
|
Chris@0
|
292 }
|
Chris@0
|
293 }
|
Chris@0
|
294
|
Chris@0
|
295 /**
|
Chris@0
|
296 * Rename a connection and its corresponding connection information.
|
Chris@0
|
297 *
|
Chris@0
|
298 * @param string $old_key
|
Chris@0
|
299 * The old connection key.
|
Chris@0
|
300 * @param string $new_key
|
Chris@0
|
301 * The new connection key.
|
Chris@0
|
302 *
|
Chris@0
|
303 * @return bool
|
Chris@0
|
304 * TRUE in case of success, FALSE otherwise.
|
Chris@0
|
305 */
|
Chris@0
|
306 final public static function renameConnection($old_key, $new_key) {
|
Chris@0
|
307 if (!empty(self::$databaseInfo[$old_key]) && empty(self::$databaseInfo[$new_key])) {
|
Chris@0
|
308 // Migrate the database connection information.
|
Chris@0
|
309 self::$databaseInfo[$new_key] = self::$databaseInfo[$old_key];
|
Chris@0
|
310 unset(self::$databaseInfo[$old_key]);
|
Chris@0
|
311
|
Chris@0
|
312 // Migrate over the DatabaseConnection object if it exists.
|
Chris@0
|
313 if (isset(self::$connections[$old_key])) {
|
Chris@0
|
314 self::$connections[$new_key] = self::$connections[$old_key];
|
Chris@0
|
315 unset(self::$connections[$old_key]);
|
Chris@0
|
316 }
|
Chris@0
|
317
|
Chris@0
|
318 return TRUE;
|
Chris@0
|
319 }
|
Chris@0
|
320 else {
|
Chris@0
|
321 return FALSE;
|
Chris@0
|
322 }
|
Chris@0
|
323 }
|
Chris@0
|
324
|
Chris@0
|
325 /**
|
Chris@0
|
326 * Remove a connection and its corresponding connection information.
|
Chris@0
|
327 *
|
Chris@0
|
328 * @param string $key
|
Chris@0
|
329 * The connection key.
|
Chris@0
|
330 *
|
Chris@0
|
331 * @return bool
|
Chris@0
|
332 * TRUE in case of success, FALSE otherwise.
|
Chris@0
|
333 */
|
Chris@0
|
334 final public static function removeConnection($key) {
|
Chris@0
|
335 if (isset(self::$databaseInfo[$key])) {
|
Chris@0
|
336 self::closeConnection(NULL, $key);
|
Chris@0
|
337 unset(self::$databaseInfo[$key]);
|
Chris@0
|
338 return TRUE;
|
Chris@0
|
339 }
|
Chris@0
|
340 else {
|
Chris@0
|
341 return FALSE;
|
Chris@0
|
342 }
|
Chris@0
|
343 }
|
Chris@0
|
344
|
Chris@0
|
345 /**
|
Chris@0
|
346 * Opens a connection to the server specified by the given key and target.
|
Chris@0
|
347 *
|
Chris@0
|
348 * @param string $key
|
Chris@0
|
349 * The database connection key, as specified in settings.php. The default is
|
Chris@0
|
350 * "default".
|
Chris@0
|
351 * @param string $target
|
Chris@0
|
352 * The database target to open.
|
Chris@0
|
353 *
|
Chris@0
|
354 * @throws \Drupal\Core\Database\ConnectionNotDefinedException
|
Chris@0
|
355 * @throws \Drupal\Core\Database\DriverNotSpecifiedException
|
Chris@0
|
356 */
|
Chris@0
|
357 final protected static function openConnection($key, $target) {
|
Chris@0
|
358 // If the requested database does not exist then it is an unrecoverable
|
Chris@0
|
359 // error.
|
Chris@0
|
360 if (!isset(self::$databaseInfo[$key])) {
|
Chris@0
|
361 throw new ConnectionNotDefinedException('The specified database connection is not defined: ' . $key);
|
Chris@0
|
362 }
|
Chris@0
|
363
|
Chris@0
|
364 if (!$driver = self::$databaseInfo[$key][$target]['driver']) {
|
Chris@0
|
365 throw new DriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
|
Chris@0
|
366 }
|
Chris@0
|
367
|
Chris@17
|
368 $namespace = static::getDatabaseDriverNamespace(self::$databaseInfo[$key][$target]);
|
Chris@17
|
369 $driver_class = $namespace . '\\Connection';
|
Chris@0
|
370
|
Chris@0
|
371 $pdo_connection = $driver_class::open(self::$databaseInfo[$key][$target]);
|
Chris@0
|
372 $new_connection = new $driver_class($pdo_connection, self::$databaseInfo[$key][$target]);
|
Chris@0
|
373 $new_connection->setTarget($target);
|
Chris@0
|
374 $new_connection->setKey($key);
|
Chris@0
|
375
|
Chris@0
|
376 // If we have any active logging objects for this connection key, we need
|
Chris@0
|
377 // to associate them with the connection we just opened.
|
Chris@0
|
378 if (!empty(self::$logs[$key])) {
|
Chris@0
|
379 $new_connection->setLogger(self::$logs[$key]);
|
Chris@0
|
380 }
|
Chris@0
|
381
|
Chris@0
|
382 return $new_connection;
|
Chris@0
|
383 }
|
Chris@0
|
384
|
Chris@0
|
385 /**
|
Chris@0
|
386 * Closes a connection to the server specified by the given key and target.
|
Chris@0
|
387 *
|
Chris@0
|
388 * @param string $target
|
Chris@0
|
389 * The database target name. Defaults to NULL meaning that all target
|
Chris@0
|
390 * connections will be closed.
|
Chris@0
|
391 * @param string $key
|
Chris@0
|
392 * The database connection key. Defaults to NULL which means the active key.
|
Chris@0
|
393 */
|
Chris@0
|
394 public static function closeConnection($target = NULL, $key = NULL) {
|
Chris@0
|
395 // Gets the active connection by default.
|
Chris@0
|
396 if (!isset($key)) {
|
Chris@0
|
397 $key = self::$activeKey;
|
Chris@0
|
398 }
|
Chris@0
|
399 // To close a connection, it needs to be set to NULL and removed from the
|
Chris@0
|
400 // static variable. In all cases, closeConnection() might be called for a
|
Chris@0
|
401 // connection that was not opened yet, in which case the key is not defined
|
Chris@0
|
402 // yet and we just ensure that the connection key is undefined.
|
Chris@0
|
403 if (isset($target)) {
|
Chris@0
|
404 if (isset(self::$connections[$key][$target])) {
|
Chris@0
|
405 self::$connections[$key][$target]->destroy();
|
Chris@0
|
406 self::$connections[$key][$target] = NULL;
|
Chris@0
|
407 }
|
Chris@0
|
408 unset(self::$connections[$key][$target]);
|
Chris@0
|
409 }
|
Chris@0
|
410 else {
|
Chris@0
|
411 if (isset(self::$connections[$key])) {
|
Chris@0
|
412 foreach (self::$connections[$key] as $target => $connection) {
|
Chris@0
|
413 self::$connections[$key][$target]->destroy();
|
Chris@0
|
414 self::$connections[$key][$target] = NULL;
|
Chris@0
|
415 }
|
Chris@0
|
416 }
|
Chris@0
|
417 unset(self::$connections[$key]);
|
Chris@0
|
418 }
|
Chris@0
|
419 }
|
Chris@0
|
420
|
Chris@0
|
421 /**
|
Chris@0
|
422 * Instructs the system to temporarily ignore a given key/target.
|
Chris@0
|
423 *
|
Chris@0
|
424 * At times we need to temporarily disable replica queries. To do so, call this
|
Chris@0
|
425 * method with the database key and the target to disable. That database key
|
Chris@0
|
426 * will then always fall back to 'default' for that key, even if it's defined.
|
Chris@0
|
427 *
|
Chris@0
|
428 * @param string $key
|
Chris@0
|
429 * The database connection key.
|
Chris@0
|
430 * @param string $target
|
Chris@0
|
431 * The target of the specified key to ignore.
|
Chris@0
|
432 */
|
Chris@0
|
433 public static function ignoreTarget($key, $target) {
|
Chris@0
|
434 self::$ignoreTargets[$key][$target] = TRUE;
|
Chris@0
|
435 }
|
Chris@0
|
436
|
Chris@0
|
437 /**
|
Chris@0
|
438 * Converts a URL to a database connection info array.
|
Chris@0
|
439 *
|
Chris@0
|
440 * @param string $url
|
Chris@0
|
441 * The URL.
|
Chris@0
|
442 * @param string $root
|
Chris@0
|
443 * The root directory of the Drupal installation.
|
Chris@0
|
444 *
|
Chris@0
|
445 * @return array
|
Chris@0
|
446 * The database connection info.
|
Chris@0
|
447 *
|
Chris@0
|
448 * @throws \InvalidArgumentException
|
Chris@0
|
449 * Exception thrown when the provided URL does not meet the minimum
|
Chris@0
|
450 * requirements.
|
Chris@0
|
451 */
|
Chris@0
|
452 public static function convertDbUrlToConnectionInfo($url, $root) {
|
Chris@17
|
453 // Check that the URL is well formed, starting with 'scheme://', where
|
Chris@17
|
454 // 'scheme' is a database driver name.
|
Chris@17
|
455 if (preg_match('/^(.*):\/\//', $url, $matches) !== 1) {
|
Chris@17
|
456 throw new \InvalidArgumentException("Missing scheme in URL '$url'");
|
Chris@0
|
457 }
|
Chris@17
|
458 $driver = $matches[1];
|
Chris@0
|
459
|
Chris@17
|
460 // Discover if the URL has a valid driver scheme. Try with core drivers
|
Chris@17
|
461 // first.
|
Chris@17
|
462 $connection_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Connection";
|
Chris@17
|
463 if (!class_exists($connection_class)) {
|
Chris@17
|
464 // If the URL is not relative to a core driver, try with custom ones.
|
Chris@17
|
465 $connection_class = "Drupal\\Driver\\Database\\{$driver}\\Connection";
|
Chris@17
|
466 if (!class_exists($connection_class)) {
|
Chris@17
|
467 throw new \InvalidArgumentException("Can not convert '$url' to a database connection, class '$connection_class' does not exist");
|
Chris@17
|
468 }
|
Chris@0
|
469 }
|
Chris@0
|
470
|
Chris@17
|
471 return $connection_class::createConnectionOptionsFromUrl($url, $root);
|
Chris@0
|
472 }
|
Chris@0
|
473
|
Chris@0
|
474 /**
|
Chris@0
|
475 * Gets database connection info as a URL.
|
Chris@0
|
476 *
|
Chris@0
|
477 * @param string $key
|
Chris@0
|
478 * (Optional) The database connection key.
|
Chris@0
|
479 *
|
Chris@0
|
480 * @return string
|
Chris@0
|
481 * The connection info as a URL.
|
Chris@17
|
482 *
|
Chris@17
|
483 * @throws \RuntimeException
|
Chris@17
|
484 * When the database connection is not defined.
|
Chris@0
|
485 */
|
Chris@0
|
486 public static function getConnectionInfoAsUrl($key = 'default') {
|
Chris@0
|
487 $db_info = static::getConnectionInfo($key);
|
Chris@17
|
488 if (empty($db_info) || empty($db_info['default'])) {
|
Chris@17
|
489 throw new \RuntimeException("Database connection $key not defined or missing the 'default' settings");
|
Chris@0
|
490 }
|
Chris@17
|
491 $connection_class = static::getDatabaseDriverNamespace($db_info['default']) . '\\Connection';
|
Chris@17
|
492 return $connection_class::createUrlFromConnectionOptions($db_info['default']);
|
Chris@17
|
493 }
|
Chris@0
|
494
|
Chris@17
|
495 /**
|
Chris@17
|
496 * Gets the PHP namespace of a database driver from the connection info.
|
Chris@17
|
497 *
|
Chris@17
|
498 * @param array $connection_info
|
Chris@17
|
499 * The database connection information, as defined in settings.php. The
|
Chris@17
|
500 * structure of this array depends on the database driver it is connecting
|
Chris@17
|
501 * to.
|
Chris@17
|
502 *
|
Chris@17
|
503 * @return string
|
Chris@17
|
504 * The PHP namespace of the driver's database.
|
Chris@17
|
505 */
|
Chris@17
|
506 protected static function getDatabaseDriverNamespace(array $connection_info) {
|
Chris@17
|
507 if (isset($connection_info['namespace'])) {
|
Chris@17
|
508 return $connection_info['namespace'];
|
Chris@0
|
509 }
|
Chris@17
|
510 // Fallback for Drupal 7 settings.php.
|
Chris@17
|
511 return 'Drupal\\Core\\Database\\Driver\\' . $connection_info['driver'];
|
Chris@0
|
512 }
|
Chris@0
|
513
|
Chris@0
|
514 }
|