Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 17 |
CRAP | |
15.97% |
19 / 119 |
| Database | |
0.00% |
0 / 1 |
|
0.00% |
0 / 17 |
2054.25 | |
15.97% |
19 / 119 |
| startLog | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 7 |
|||
| getLog | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 5 |
|||
| getConnection | |
0.00% |
0 / 1 |
5.07 | |
85.71% |
6 / 7 |
|||
| isActiveConnection | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 1 |
|||
| setActiveConnection | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 5 |
|||
| parseConnectionInfo | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 9 |
|||
| addConnectionInfo | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
| getConnectionInfo | |
0.00% |
0 / 1 |
2.15 | |
66.67% |
2 / 3 |
|||
| getAllConnectionInfo | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| setMultipleConnectionInfo | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 4 |
|||
| renameConnection | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 8 |
|||
| removeConnection | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 5 |
|||
| openConnection | |
0.00% |
0 / 1 |
20.74 | |
14.29% |
2 / 14 |
|||
| closeConnection | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 13 |
|||
| ignoreTarget | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| convertDbUrlToConnectionInfo | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 16 |
|||
| getConnectionInfoAsUrl | |
0.00% |
0 / 1 |
9.01 | |
56.25% |
9 / 16 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Core\Database\Database. | |
| */ | |
| namespace Drupal\Core\Database; | |
| /** | |
| * Primary front-controller for the database system. | |
| * | |
| * This class is uninstantiatable and un-extendable. It acts to encapsulate | |
| * all control and shepherding of database connections into a single location | |
| * without the use of globals. | |
| */ | |
| abstract class Database { | |
| /** | |
| * Flag to indicate a query call should simply return NULL. | |
| * | |
| * This is used for queries that have no reasonable return value anyway, such | |
| * as INSERT statements to a table without a serial primary key. | |
| */ | |
| const RETURN_NULL = 0; | |
| /** | |
| * Flag to indicate a query call should return the prepared statement. | |
| */ | |
| const RETURN_STATEMENT = 1; | |
| /** | |
| * Flag to indicate a query call should return the number of affected rows. | |
| */ | |
| const RETURN_AFFECTED = 2; | |
| /** | |
| * Flag to indicate a query call should return the "last insert id". | |
| */ | |
| const RETURN_INSERT_ID = 3; | |
| /** | |
| * An nested array of all active connections. It is keyed by database name | |
| * and target. | |
| * | |
| * @var array | |
| */ | |
| static protected $connections = array(); | |
| /** | |
| * A processed copy of the database connection information from settings.php. | |
| * | |
| * @var array | |
| */ | |
| static protected $databaseInfo = array(); | |
| /** | |
| * A list of key/target credentials to simply ignore. | |
| * | |
| * @var array | |
| */ | |
| static protected $ignoreTargets = array(); | |
| /** | |
| * The key of the currently active database connection. | |
| * | |
| * @var string | |
| */ | |
| static protected $activeKey = 'default'; | |
| /** | |
| * An array of active query log objects. | |
| * | |
| * Every connection has one and only one logger object for all targets and | |
| * logging keys. | |
| * | |
| * array( | |
| * '$db_key' => DatabaseLog object. | |
| * ); | |
| * | |
| * @var array | |
| */ | |
| static protected $logs = array(); | |
| /** | |
| * Starts logging a given logging key on the specified connection. | |
| * | |
| * @param string $logging_key | |
| * The logging key to log. | |
| * @param string $key | |
| * The database connection key for which we want to log. | |
| * | |
| * @return \Drupal\Core\Database\Log | |
| * The query log object. Note that the log object does support richer | |
| * methods than the few exposed through the Database class, so in some | |
| * cases it may be desirable to access it directly. | |
| * | |
| * @see \Drupal\Core\Database\Log | |
| */ | |
| final public static function startLog($logging_key, $key = 'default') { | |
| if (empty(self::$logs[$key])) { | |
| self::$logs[$key] = new Log($key); | |
| // Every target already active for this connection key needs to have the | |
| // logging object associated with it. | |
| if (!empty(self::$connections[$key])) { | |
| foreach (self::$connections[$key] as $connection) { | |
| $connection->setLogger(self::$logs[$key]); | |
| } | |
| } | |
| } | |
| self::$logs[$key]->start($logging_key); | |
| return self::$logs[$key]; | |
| } | |
| /** | |
| * Retrieves the queries logged on for given logging key. | |
| * | |
| * This method also ends logging for the specified key. To get the query log | |
| * to date without ending the logger request the logging object by starting | |
| * it again (which does nothing to an open log key) and call methods on it as | |
| * desired. | |
| * | |
| * @param string $logging_key | |
| * The logging key to log. | |
| * @param string $key | |
| * The database connection key for which we want to log. | |
| * | |
| * @return array | |
| * The query log for the specified logging key and connection. | |
| * | |
| * @see \Drupal\Core\Database\Log | |
| */ | |
| final public static function getLog($logging_key, $key = 'default') { | |
| if (empty(self::$logs[$key])) { | |
| return NULL; | |
| } | |
| $queries = self::$logs[$key]->get($logging_key); | |
| self::$logs[$key]->end($logging_key); | |
| return $queries; | |
| } | |
| /** | |
| * Gets the connection object for the specified database key and target. | |
| * | |
| * @param string $target | |
| * The database target name. | |
| * @param string $key | |
| * The database connection key. Defaults to NULL which means the active key. | |
| * | |
| * @return \Drupal\Core\Database\Connection | |
| * The corresponding connection object. | |
| */ | |
| final public static function getConnection($target = 'default', $key = NULL) { | |
| if (!isset($key)) { | |
| // By default, we want the active connection, set in setActiveConnection. | |
| $key = self::$activeKey; | |
| } | |
| // If the requested target does not exist, or if it is ignored, we fall back | |
| // to the default target. The target is typically either "default" or | |
| // "replica", indicating to use a replica SQL server if one is available. If | |
| // it's not available, then the default/primary server is the correct server | |
| // to use. | |
| if (!empty(self::$ignoreTargets[$key][$target]) || !isset(self::$databaseInfo[$key][$target])) { | |
| $target = 'default'; | |
| } | |
| if (!isset(self::$connections[$key][$target])) { | |
| // If necessary, a new connection is opened. | |
| self::$connections[$key][$target] = self::openConnection($key, $target); | |
| } | |
| return self::$connections[$key][$target]; | |
| } | |
| /** | |
| * Determines if there is an active connection. | |
| * | |
| * Note that this method will return FALSE if no connection has been | |
| * established yet, even if one could be. | |
| * | |
| * @return bool | |
| * TRUE if there is at least one database connection established, FALSE | |
| * otherwise. | |
| */ | |
| final public static function isActiveConnection() { | |
| return !empty(self::$activeKey) && !empty(self::$connections) && !empty(self::$connections[self::$activeKey]); | |
| } | |
| /** | |
| * Sets the active connection to the specified key. | |
| * | |
| * @return string|null | |
| * The previous database connection key. | |
| */ | |
| final public static function setActiveConnection($key = 'default') { | |
| if (!empty(self::$databaseInfo[$key])) { | |
| $old_key = self::$activeKey; | |
| self::$activeKey = $key; | |
| return $old_key; | |
| } | |
| } | |
| /** | |
| * Process the configuration file for database information. | |
| * | |
| * @param array $info | |
| * The database connection information, as defined in settings.php. The | |
| * structure of this array depends on the database driver it is connecting | |
| * to. | |
| */ | |
| final public static function parseConnectionInfo(array $info) { | |
| // If there is no "driver" property, then we assume it's an array of | |
| // possible connections for this target. Pick one at random. That allows | |
| // us to have, for example, multiple replica servers. | |
| if (empty($info['driver'])) { | |
| $info = $info[mt_rand(0, count($info) - 1)]; | |
| } | |
| // Parse the prefix information. | |
| if (!isset($info['prefix'])) { | |
| // Default to an empty prefix. | |
| $info['prefix'] = array( | |
| 'default' => '', | |
| ); | |
| } | |
| elseif (!is_array($info['prefix'])) { | |
| // Transform the flat form into an array form. | |
| $info['prefix'] = array( | |
| 'default' => $info['prefix'], | |
| ); | |
| } | |
| return $info; | |
| } | |
| /** | |
| * Adds database connection information for a given key/target. | |
| * | |
| * This method allows to add new connections at runtime. | |
| * | |
| * Under normal circumstances the preferred way to specify database | |
| * credentials is via settings.php. However, this method allows them to be | |
| * added at arbitrary times, such as during unit tests, when connecting to | |
| * admin-defined third party databases, etc. | |
| * | |
| * If the given key/target pair already exists, this method will be ignored. | |
| * | |
| * @param string $key | |
| * The database key. | |
| * @param string $target | |
| * The database target name. | |
| * @param array $info | |
| * The database connection information, as defined in settings.php. The | |
| * structure of this array depends on the database driver it is connecting | |
| * to. | |
| */ | |
| final public static function addConnectionInfo($key, $target, array $info) { | |
| if (empty(self::$databaseInfo[$key][$target])) { | |
| self::$databaseInfo[$key][$target] = self::parseConnectionInfo($info); | |
| } | |
| } | |
| /** | |
| * Gets information on the specified database connection. | |
| * | |
| * @param string $key | |
| * (optional) The connection key for which to return information. | |
| * | |
| * @return array|null | |
| */ | |
| final public static function getConnectionInfo($key = 'default') { | |
| if (!empty(self::$databaseInfo[$key])) { | |
| return self::$databaseInfo[$key]; | |
| } | |
| } | |
| /** | |
| * Gets connection information for all available databases. | |
| * | |
| * @return array | |
| */ | |
| final public static function getAllConnectionInfo() { | |
| return self::$databaseInfo; | |
| } | |
| /** | |
| * Sets connection information for multiple databases. | |
| * | |
| * @param array $databases | |
| * A multi-dimensional array specifying database connection parameters, as | |
| * defined in settings.php. | |
| */ | |
| final public static function setMultipleConnectionInfo(array $databases) { | |
| foreach ($databases as $key => $targets) { | |
| foreach ($targets as $target => $info) { | |
| self::addConnectionInfo($key, $target, $info); | |
| } | |
| } | |
| } | |
| /** | |
| * Rename a connection and its corresponding connection information. | |
| * | |
| * @param string $old_key | |
| * The old connection key. | |
| * @param string $new_key | |
| * The new connection key. | |
| * | |
| * @return bool | |
| * TRUE in case of success, FALSE otherwise. | |
| */ | |
| final public static function renameConnection($old_key, $new_key) { | |
| if (!empty(self::$databaseInfo[$old_key]) && empty(self::$databaseInfo[$new_key])) { | |
| // Migrate the database connection information. | |
| self::$databaseInfo[$new_key] = self::$databaseInfo[$old_key]; | |
| unset(self::$databaseInfo[$old_key]); | |
| // Migrate over the DatabaseConnection object if it exists. | |
| if (isset(self::$connections[$old_key])) { | |
| self::$connections[$new_key] = self::$connections[$old_key]; | |
| unset(self::$connections[$old_key]); | |
| } | |
| return TRUE; | |
| } | |
| else { | |
| return FALSE; | |
| } | |
| } | |
| /** | |
| * Remove a connection and its corresponding connection information. | |
| * | |
| * @param string $key | |
| * The connection key. | |
| * | |
| * @return bool | |
| * TRUE in case of success, FALSE otherwise. | |
| */ | |
| final public static function removeConnection($key) { | |
| if (isset(self::$databaseInfo[$key])) { | |
| self::closeConnection(NULL, $key); | |
| unset(self::$databaseInfo[$key]); | |
| return TRUE; | |
| } | |
| else { | |
| return FALSE; | |
| } | |
| } | |
| /** | |
| * Opens a connection to the server specified by the given key and target. | |
| * | |
| * @param string $key | |
| * The database connection key, as specified in settings.php. The default is | |
| * "default". | |
| * @param string $target | |
| * The database target to open. | |
| * | |
| * @throws \Drupal\Core\Database\ConnectionNotDefinedException | |
| * @throws \Drupal\Core\Database\DriverNotSpecifiedException | |
| */ | |
| final protected static function openConnection($key, $target) { | |
| // If the requested database does not exist then it is an unrecoverable | |
| // error. | |
| if (!isset(self::$databaseInfo[$key])) { | |
| throw new ConnectionNotDefinedException('The specified database connection is not defined: ' . $key); | |
| } | |
| if (!$driver = self::$databaseInfo[$key][$target]['driver']) { | |
| throw new DriverNotSpecifiedException('Driver not specified for this database connection: ' . $key); | |
| } | |
| if (!empty(self::$databaseInfo[$key][$target]['namespace'])) { | |
| $driver_class = self::$databaseInfo[$key][$target]['namespace'] . '\\Connection'; | |
| } | |
| else { | |
| // Fallback for Drupal 7 settings.php. | |
| $driver_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Connection"; | |
| } | |
| $pdo_connection = $driver_class::open(self::$databaseInfo[$key][$target]); | |
| $new_connection = new $driver_class($pdo_connection, self::$databaseInfo[$key][$target]); | |
| $new_connection->setTarget($target); | |
| $new_connection->setKey($key); | |
| // If we have any active logging objects for this connection key, we need | |
| // to associate them with the connection we just opened. | |
| if (!empty(self::$logs[$key])) { | |
| $new_connection->setLogger(self::$logs[$key]); | |
| } | |
| return $new_connection; | |
| } | |
| /** | |
| * Closes a connection to the server specified by the given key and target. | |
| * | |
| * @param string $target | |
| * The database target name. Defaults to NULL meaning that all target | |
| * connections will be closed. | |
| * @param string $key | |
| * The database connection key. Defaults to NULL which means the active key. | |
| */ | |
| public static function closeConnection($target = NULL, $key = NULL) { | |
| // Gets the active connection by default. | |
| if (!isset($key)) { | |
| $key = self::$activeKey; | |
| } | |
| // To close a connection, it needs to be set to NULL and removed from the | |
| // static variable. In all cases, closeConnection() might be called for a | |
| // connection that was not opened yet, in which case the key is not defined | |
| // yet and we just ensure that the connection key is undefined. | |
| if (isset($target)) { | |
| if (isset(self::$connections[$key][$target])) { | |
| self::$connections[$key][$target]->destroy(); | |
| self::$connections[$key][$target] = NULL; | |
| } | |
| unset(self::$connections[$key][$target]); | |
| } | |
| else { | |
| if (isset(self::$connections[$key])) { | |
| foreach (self::$connections[$key] as $target => $connection) { | |
| self::$connections[$key][$target]->destroy(); | |
| self::$connections[$key][$target] = NULL; | |
| } | |
| } | |
| unset(self::$connections[$key]); | |
| } | |
| } | |
| /** | |
| * Instructs the system to temporarily ignore a given key/target. | |
| * | |
| * At times we need to temporarily disable replica queries. To do so, call this | |
| * method with the database key and the target to disable. That database key | |
| * will then always fall back to 'default' for that key, even if it's defined. | |
| * | |
| * @param string $key | |
| * The database connection key. | |
| * @param string $target | |
| * The target of the specified key to ignore. | |
| */ | |
| public static function ignoreTarget($key, $target) { | |
| self::$ignoreTargets[$key][$target] = TRUE; | |
| } | |
| /** | |
| * Converts a URL to a database connection info array. | |
| * | |
| * @param string $url | |
| * The URL. | |
| * @param string $root | |
| * The root directory of the Drupal installation. | |
| * | |
| * @return array | |
| * The database connection info. | |
| * | |
| * @throws \InvalidArgumentException | |
| * Exception thrown when the provided URL does not meet the minimum | |
| * requirements. | |
| */ | |
| public static function convertDbUrlToConnectionInfo($url, $root) { | |
| $info = parse_url($url); | |
| if (!isset($info['scheme'], $info['host'], $info['path'])) { | |
| throw new \InvalidArgumentException('Minimum requirement: driver://host/database'); | |
| } | |
| $info += array( | |
| 'user' => '', | |
| 'pass' => '', | |
| 'fragment' => '', | |
| ); | |
| // A SQLite database path with two leading slashes indicates a system path. | |
| // Otherwise the path is relative to the Drupal root. | |
| if ($info['path'][0] === '/') { | |
| $info['path'] = substr($info['path'], 1); | |
| } | |
| if ($info['scheme'] === 'sqlite' && $info['path'][0] !== '/') { | |
| $info['path'] = $root . '/' . $info['path']; | |
| } | |
| $database = array( | |
| 'driver' => $info['scheme'], | |
| 'username' => $info['user'], | |
| 'password' => $info['pass'], | |
| 'host' => $info['host'], | |
| 'database' => $info['path'], | |
| ); | |
| if (isset($info['port'])) { | |
| $database['port'] = $info['port']; | |
| } | |
| return $database; | |
| } | |
| /** | |
| * Gets database connection info as a URL. | |
| * | |
| * @param string $key | |
| * (Optional) The database connection key. | |
| * | |
| * @return string | |
| * The connection info as a URL. | |
| */ | |
| public static function getConnectionInfoAsUrl($key = 'default') { | |
| $db_info = static::getConnectionInfo($key); | |
| if ($db_info['default']['driver'] == 'sqlite') { | |
| $db_url = 'sqlite://localhost/' . $db_info['default']['database']; | |
| } | |
| else { | |
| $user = ''; | |
| if ($db_info['default']['username']) { | |
| $user = $db_info['default']['username']; | |
| if ($db_info['default']['password']) { | |
| $user .= ':' . $db_info['default']['password']; | |
| } | |
| $user .= '@'; | |
| } | |
| $db_url = $db_info['default']['driver'] . '://' . $user . $db_info['default']['host']; | |
| if (isset($db_info['default']['port'])) { | |
| $db_url .= ':' . $db_info['default']['port']; | |
| } | |
| $db_url .= '/' . $db_info['default']['database']; | |
| } | |
| if ($db_info['default']['prefix']['default']) { | |
| $db_url .= '#' . $db_info['default']['prefix']['default']; | |
| } | |
| return $db_url; | |
| } | |
| } |