PageRenderTime 99ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/core/lib/Drupal/Core/Database/Database.php

https://bitbucket.org/aswinvk28/smartpan-stock-drupal
PHP | 450 lines | 178 code | 43 blank | 229 comment | 36 complexity | 69dbc4d7509f7334835393822ae627d5 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * @file
  4. * Definition of Drupal\Core\Database\Database
  5. */
  6. namespace Drupal\Core\Database;
  7. /**
  8. * Primary front-controller for the database system.
  9. *
  10. * This class is uninstantiatable and un-extendable. It acts to encapsulate
  11. * all control and shepherding of database connections into a single location
  12. * without the use of globals.
  13. */
  14. abstract class Database {
  15. /**
  16. * Flag to indicate a query call should simply return NULL.
  17. *
  18. * This is used for queries that have no reasonable return value anyway, such
  19. * as INSERT statements to a table without a serial primary key.
  20. */
  21. const RETURN_NULL = 0;
  22. /**
  23. * Flag to indicate a query call should return the prepared statement.
  24. */
  25. const RETURN_STATEMENT = 1;
  26. /**
  27. * Flag to indicate a query call should return the number of affected rows.
  28. */
  29. const RETURN_AFFECTED = 2;
  30. /**
  31. * Flag to indicate a query call should return the "last insert id".
  32. */
  33. const RETURN_INSERT_ID = 3;
  34. /**
  35. * An nested array of all active connections. It is keyed by database name
  36. * and target.
  37. *
  38. * @var array
  39. */
  40. static protected $connections = array();
  41. /**
  42. * A processed copy of the database connection information from settings.php.
  43. *
  44. * @var array
  45. */
  46. static protected $databaseInfo = NULL;
  47. /**
  48. * A list of key/target credentials to simply ignore.
  49. *
  50. * @var array
  51. */
  52. static protected $ignoreTargets = array();
  53. /**
  54. * The key of the currently active database connection.
  55. *
  56. * @var string
  57. */
  58. static protected $activeKey = 'default';
  59. /**
  60. * An array of active query log objects.
  61. *
  62. * Every connection has one and only one logger object for all targets and
  63. * logging keys.
  64. *
  65. * array(
  66. * '$db_key' => DatabaseLog object.
  67. * );
  68. *
  69. * @var array
  70. */
  71. static protected $logs = array();
  72. /**
  73. * Starts logging a given logging key on the specified connection.
  74. *
  75. * @param $logging_key
  76. * The logging key to log.
  77. * @param $key
  78. * The database connection key for which we want to log.
  79. *
  80. * @return \Drupal\Core\Database\Log
  81. * The query log object. Note that the log object does support richer
  82. * methods than the few exposed through the Database class, so in some
  83. * cases it may be desirable to access it directly.
  84. *
  85. * @see \Drupal\Core\Database\Log
  86. */
  87. final public static function startLog($logging_key, $key = 'default') {
  88. if (empty(self::$logs[$key])) {
  89. self::$logs[$key] = new Log($key);
  90. // Every target already active for this connection key needs to have the
  91. // logging object associated with it.
  92. if (!empty(self::$connections[$key])) {
  93. foreach (self::$connections[$key] as $connection) {
  94. $connection->setLogger(self::$logs[$key]);
  95. }
  96. }
  97. }
  98. self::$logs[$key]->start($logging_key);
  99. return self::$logs[$key];
  100. }
  101. /**
  102. * Retrieves the queries logged on for given logging key.
  103. *
  104. * This method also ends logging for the specified key. To get the query log
  105. * to date without ending the logger request the logging object by starting
  106. * it again (which does nothing to an open log key) and call methods on it as
  107. * desired.
  108. *
  109. * @param $logging_key
  110. * The logging key to log.
  111. * @param $key
  112. * The database connection key for which we want to log.
  113. *
  114. * @return array
  115. * The query log for the specified logging key and connection.
  116. *
  117. * @see \Drupal\Core\Database\Log
  118. */
  119. final public static function getLog($logging_key, $key = 'default') {
  120. if (empty(self::$logs[$key])) {
  121. return NULL;
  122. }
  123. $queries = self::$logs[$key]->get($logging_key);
  124. self::$logs[$key]->end($logging_key);
  125. return $queries;
  126. }
  127. /**
  128. * Gets the connection object for the specified database key and target.
  129. *
  130. * @param $target
  131. * The database target name.
  132. * @param $key
  133. * The database connection key. Defaults to NULL which means the active key.
  134. *
  135. * @return \Drupal\Core\Database\Connection
  136. * The corresponding connection object.
  137. */
  138. final public static function getConnection($target = 'default', $key = NULL) {
  139. if (!isset($key)) {
  140. // By default, we want the active connection, set in setActiveConnection.
  141. $key = self::$activeKey;
  142. }
  143. // If the requested target does not exist, or if it is ignored, we fall back
  144. // to the default target. The target is typically either "default" or
  145. // "slave", indicating to use a slave SQL server if one is available. If
  146. // it's not available, then the default/master server is the correct server
  147. // to use.
  148. if (!empty(self::$ignoreTargets[$key][$target]) || !isset(self::$databaseInfo[$key][$target])) {
  149. $target = 'default';
  150. }
  151. if (!isset(self::$connections[$key][$target])) {
  152. // If necessary, a new connection is opened.
  153. self::$connections[$key][$target] = self::openConnection($key, $target);
  154. }
  155. return self::$connections[$key][$target];
  156. }
  157. /**
  158. * Determines if there is an active connection.
  159. *
  160. * Note that this method will return FALSE if no connection has been
  161. * established yet, even if one could be.
  162. *
  163. * @return
  164. * TRUE if there is at least one database connection established, FALSE
  165. * otherwise.
  166. */
  167. final public static function isActiveConnection() {
  168. return !empty(self::$activeKey) && !empty(self::$connections) && !empty(self::$connections[self::$activeKey]);
  169. }
  170. /**
  171. * Sets the active connection to the specified key.
  172. *
  173. * @return
  174. * The previous database connection key.
  175. */
  176. final public static function setActiveConnection($key = 'default') {
  177. if (empty(self::$databaseInfo)) {
  178. self::parseConnectionInfo();
  179. }
  180. if (!empty(self::$databaseInfo[$key])) {
  181. $old_key = self::$activeKey;
  182. self::$activeKey = $key;
  183. return $old_key;
  184. }
  185. }
  186. /**
  187. * Process the configuration file for database information.
  188. */
  189. final public static function parseConnectionInfo() {
  190. global $databases;
  191. $database_info = is_array($databases) ? $databases : array();
  192. foreach ($database_info as $index => $info) {
  193. foreach ($database_info[$index] as $target => $value) {
  194. // If there is no "driver" property, then we assume it's an array of
  195. // possible connections for this target. Pick one at random. That allows
  196. // us to have, for example, multiple slave servers.
  197. if (empty($value['driver'])) {
  198. $database_info[$index][$target] = $database_info[$index][$target][mt_rand(0, count($database_info[$index][$target]) - 1)];
  199. }
  200. // Parse the prefix information.
  201. if (!isset($database_info[$index][$target]['prefix'])) {
  202. // Default to an empty prefix.
  203. $database_info[$index][$target]['prefix'] = array(
  204. 'default' => '',
  205. );
  206. }
  207. elseif (!is_array($database_info[$index][$target]['prefix'])) {
  208. // Transform the flat form into an array form.
  209. $database_info[$index][$target]['prefix'] = array(
  210. 'default' => $database_info[$index][$target]['prefix'],
  211. );
  212. }
  213. }
  214. }
  215. if (!is_array(self::$databaseInfo)) {
  216. self::$databaseInfo = $database_info;
  217. }
  218. // Merge the new $database_info into the existing.
  219. // array_merge_recursive() cannot be used, as it would make multiple
  220. // database, user, and password keys in the same database array.
  221. else {
  222. foreach ($database_info as $database_key => $database_values) {
  223. foreach ($database_values as $target => $target_values) {
  224. self::$databaseInfo[$database_key][$target] = $target_values;
  225. }
  226. }
  227. }
  228. }
  229. /**
  230. * Adds database connection information for a given key/target.
  231. *
  232. * This method allows the addition of new connection credentials at runtime.
  233. * Under normal circumstances the preferred way to specify database
  234. * credentials is via settings.php. However, this method allows them to be
  235. * added at arbitrary times, such as during unit tests, when connecting to
  236. * admin-defined third party databases, etc.
  237. *
  238. * If the given key/target pair already exists, this method will be ignored.
  239. *
  240. * @param $key
  241. * The database key.
  242. * @param $target
  243. * The database target name.
  244. * @param $info
  245. * The database connection information, as it would be defined in
  246. * settings.php. Note that the structure of this array will depend on the
  247. * database driver it is connecting to.
  248. */
  249. public static function addConnectionInfo($key, $target, $info) {
  250. if (empty(self::$databaseInfo[$key][$target])) {
  251. self::$databaseInfo[$key][$target] = $info;
  252. }
  253. }
  254. /**
  255. * Gets information on the specified database connection.
  256. *
  257. * @param $connection
  258. * The connection key for which we want information.
  259. */
  260. final public static function getConnectionInfo($key = 'default') {
  261. if (empty(self::$databaseInfo)) {
  262. self::parseConnectionInfo();
  263. }
  264. if (!empty(self::$databaseInfo[$key])) {
  265. return self::$databaseInfo[$key];
  266. }
  267. }
  268. /**
  269. * Rename a connection and its corresponding connection information.
  270. *
  271. * @param $old_key
  272. * The old connection key.
  273. * @param $new_key
  274. * The new connection key.
  275. * @return
  276. * TRUE in case of success, FALSE otherwise.
  277. */
  278. final public static function renameConnection($old_key, $new_key) {
  279. if (empty(self::$databaseInfo)) {
  280. self::parseConnectionInfo();
  281. }
  282. if (!empty(self::$databaseInfo[$old_key]) && empty(self::$databaseInfo[$new_key])) {
  283. // Migrate the database connection information.
  284. self::$databaseInfo[$new_key] = self::$databaseInfo[$old_key];
  285. unset(self::$databaseInfo[$old_key]);
  286. // Migrate over the DatabaseConnection object if it exists.
  287. if (isset(self::$connections[$old_key])) {
  288. self::$connections[$new_key] = self::$connections[$old_key];
  289. unset(self::$connections[$old_key]);
  290. }
  291. return TRUE;
  292. }
  293. else {
  294. return FALSE;
  295. }
  296. }
  297. /**
  298. * Remove a connection and its corresponding connection information.
  299. *
  300. * @param $key
  301. * The connection key.
  302. * @return
  303. * TRUE in case of success, FALSE otherwise.
  304. */
  305. final public static function removeConnection($key) {
  306. if (isset(self::$databaseInfo[$key])) {
  307. self::closeConnection(NULL, $key);
  308. unset(self::$databaseInfo[$key]);
  309. return TRUE;
  310. }
  311. else {
  312. return FALSE;
  313. }
  314. }
  315. /**
  316. * Opens a connection to the server specified by the given key and target.
  317. *
  318. * @param $key
  319. * The database connection key, as specified in settings.php. The default is
  320. * "default".
  321. * @param $target
  322. * The database target to open.
  323. *
  324. * @throws \Drupal\Core\Database\ConnectionNotDefinedException
  325. * @throws \Drupal\Core\Database\DriverNotSpecifiedException
  326. */
  327. final protected static function openConnection($key, $target) {
  328. if (empty(self::$databaseInfo)) {
  329. self::parseConnectionInfo();
  330. }
  331. // If the requested database does not exist then it is an unrecoverable
  332. // error.
  333. if (!isset(self::$databaseInfo[$key])) {
  334. throw new ConnectionNotDefinedException('The specified database connection is not defined: ' . $key);
  335. }
  336. if (!$driver = self::$databaseInfo[$key][$target]['driver']) {
  337. throw new DriverNotSpecifiedException('Driver not specified for this database connection: ' . $key);
  338. }
  339. if (!empty(self::$databaseInfo[$key][$target]['namespace'])) {
  340. $driver_class = self::$databaseInfo[$key][$target]['namespace'] . '\\Connection';
  341. }
  342. else {
  343. // Fallback for Drupal 7 settings.php.
  344. $driver_class = "Drupal\\Core\\Database\\Driver\\{$driver}\\Connection";
  345. }
  346. $pdo_connection = $driver_class::open(self::$databaseInfo[$key][$target]);
  347. $new_connection = new $driver_class($pdo_connection, self::$databaseInfo[$key][$target]);
  348. $new_connection->setTarget($target);
  349. $new_connection->setKey($key);
  350. // If we have any active logging objects for this connection key, we need
  351. // to associate them with the connection we just opened.
  352. if (!empty(self::$logs[$key])) {
  353. $new_connection->setLogger(self::$logs[$key]);
  354. }
  355. return $new_connection;
  356. }
  357. /**
  358. * Closes a connection to the server specified by the given key and target.
  359. *
  360. * @param $target
  361. * The database target name. Defaults to NULL meaning that all target
  362. * connections will be closed.
  363. * @param $key
  364. * The database connection key. Defaults to NULL which means the active key.
  365. */
  366. public static function closeConnection($target = NULL, $key = NULL) {
  367. // Gets the active connection by default.
  368. if (!isset($key)) {
  369. $key = self::$activeKey;
  370. }
  371. // To close a connection, it needs to be set to NULL and removed from the
  372. // static variable. In all cases, closeConnection() might be called for a
  373. // connection that was not opened yet, in which case the key is not defined
  374. // yet and we just ensure that the connection key is undefined.
  375. if (isset($target)) {
  376. if (isset(self::$connections[$key][$target])) {
  377. self::$connections[$key][$target]->destroy();
  378. self::$connections[$key][$target] = NULL;
  379. }
  380. unset(self::$connections[$key][$target]);
  381. }
  382. else {
  383. if (isset(self::$connections[$key])) {
  384. foreach (self::$connections[$key] as $target => $connection) {
  385. self::$connections[$key][$target]->destroy();
  386. self::$connections[$key][$target] = NULL;
  387. }
  388. }
  389. unset(self::$connections[$key]);
  390. }
  391. }
  392. /**
  393. * Instructs the system to temporarily ignore a given key/target.
  394. *
  395. * At times we need to temporarily disable slave queries. To do so, call this
  396. * method with the database key and the target to disable. That database key
  397. * will then always fall back to 'default' for that key, even if it's defined.
  398. *
  399. * @param $key
  400. * The database connection key.
  401. * @param $target
  402. * The target of the specified key to ignore.
  403. */
  404. public static function ignoreTarget($key, $target) {
  405. self::$ignoreTargets[$key][$target] = TRUE;
  406. }
  407. }