database.api.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. <?php
  2. /**
  3. * @file
  4. * Hooks related to the Database system and the Schema API.
  5. */
  6. use Drupal\Core\Database\Query\Condition;
  7. /**
  8. * @defgroup database Database abstraction layer
  9. * @{
  10. * Allow the use of different database servers using the same code base.
  11. *
  12. * @section sec_intro Overview
  13. * Drupal's database abstraction layer provides a unified database query API
  14. * that can query different underlying databases. It is built upon PHP's
  15. * PDO (PHP Data Objects) database API, and inherits much of its syntax and
  16. * semantics. Besides providing a unified API for database queries, the
  17. * database abstraction layer also provides a structured way to construct
  18. * complex queries, and it protects the database by using good security
  19. * practices.
  20. *
  21. * For more detailed information on the database abstraction layer, see
  22. * https://www.drupal.org/developing/api/database.
  23. *
  24. * @section sec_entity Querying entities
  25. * Any query on Drupal entities or fields should use the Entity Query API. See
  26. * the @link entity_api entity API topic @endlink for more information.
  27. *
  28. * @section sec_simple Simple SELECT database queries
  29. * For simple SELECT queries that do not involve entities, the Drupal database
  30. * abstraction layer provides the functions db_query() and db_query_range(),
  31. * which execute SELECT queries (optionally with range limits) and return result
  32. * sets that you can iterate over using foreach loops. (The result sets are
  33. * objects implementing the \Drupal\Core\Database\StatementInterface interface.)
  34. * You can use the simple query functions for query strings that are not
  35. * dynamic (except for placeholders, see below), and that you are certain will
  36. * work in any database engine. See @ref sec_dynamic below if you have a more
  37. * complex query, or a query whose syntax would be different in some databases.
  38. *
  39. * As a note, db_query() and similar functions are wrappers on connection object
  40. * methods. In most classes, you should use dependency injection and the
  41. * database connection object instead of these wrappers; See @ref sec_connection
  42. * below for details.
  43. *
  44. * To use the simple database query functions, you will need to make a couple of
  45. * modifications to your bare SQL query:
  46. * - Enclose your table name in {}. Drupal allows site builders to use
  47. * database table name prefixes, so you cannot be sure what the actual
  48. * name of the table will be. So, use the name that is in the hook_schema(),
  49. * enclosed in {}, and Drupal will calculate the right name.
  50. * - Instead of putting values for conditions into the query, use placeholders.
  51. * The placeholders are named and start with :, and they take the place of
  52. * putting variables directly into the query, to protect against SQL
  53. * injection attacks.
  54. * - LIMIT syntax differs between databases, so if you have a ranged query,
  55. * use db_query_range() instead of db_query().
  56. *
  57. * For example, if the query you want to run is:
  58. * @code
  59. * SELECT e.id, e.title, e.created FROM example e WHERE e.uid = $uid
  60. * ORDER BY e.created DESC LIMIT 0, 10;
  61. * @endcode
  62. * you would do it like this:
  63. * @code
  64. * $result = db_query_range('SELECT e.id, e.title, e.created
  65. * FROM {example} e
  66. * WHERE e.uid = :uid
  67. * ORDER BY e.created DESC',
  68. * 0, 10, array(':uid' => $uid));
  69. * foreach ($result as $record) {
  70. * // Perform operations on $record->title, etc. here.
  71. * }
  72. * @endcode
  73. *
  74. * Note that if your query has a string condition, like:
  75. * @code
  76. * WHERE e.my_field = 'foo'
  77. * @endcode
  78. * when you convert it to placeholders, omit the quotes:
  79. * @code
  80. * WHERE e.my_field = :my_field
  81. * ... array(':my_field' => 'foo') ...
  82. * @endcode
  83. *
  84. * @section sec_dynamic Dynamic SELECT queries
  85. * For SELECT queries where the simple query API described in @ref sec_simple
  86. * will not work well, you need to use the dynamic query API. However, you
  87. * should still use the Entity Query API if your query involves entities or
  88. * fields (see the @link entity_api Entity API topic @endlink for more on
  89. * entity queries).
  90. *
  91. * As a note, db_select() and similar functions are wrappers on connection
  92. * object methods. In most classes, you should use dependency injection and the
  93. * database connection object instead of these wrappers; See @ref sec_connection
  94. * below for details.
  95. *
  96. * The dynamic query API lets you build up a query dynamically using method
  97. * calls. As an illustration, the query example from @ref sec_simple above
  98. * would be:
  99. * @code
  100. * $result = db_select('example', 'e')
  101. * ->fields('e', array('id', 'title', 'created'))
  102. * ->condition('e.uid', $uid)
  103. * ->orderBy('e.created', 'DESC')
  104. * ->range(0, 10)
  105. * ->execute();
  106. * @endcode
  107. *
  108. * There are also methods to join to other tables, add fields with aliases,
  109. * isNull() to have a @code WHERE e.foo IS NULL @endcode condition, etc. See
  110. * https://www.drupal.org/developing/api/database for many more details.
  111. *
  112. * One note on chaining: It is common in the dynamic database API to chain
  113. * method calls (as illustrated here), because most of the query methods modify
  114. * the query object and then return the modified query as their return
  115. * value. However, there are some important exceptions; these methods (and some
  116. * others) do not support chaining:
  117. * - join(), innerJoin(), etc.: These methods return the joined table alias.
  118. * - addField(): This method returns the field alias.
  119. * Check the documentation for the query method you are using to see if it
  120. * returns the query or something else, and only chain methods that return the
  121. * query.
  122. *
  123. * @section_insert INSERT, UPDATE, and DELETE queries
  124. * INSERT, UPDATE, and DELETE queries need special care in order to behave
  125. * consistently across databases; you should never use db_query() to run
  126. * an INSERT, UPDATE, or DELETE query. Instead, use functions db_insert(),
  127. * db_update(), and db_delete() to obtain a base query on your table, and then
  128. * add dynamic conditions (as illustrated in @ref sec_dynamic above).
  129. *
  130. * As a note, db_insert() and similar functions are wrappers on connection
  131. * object methods. In most classes, you should use dependency injection and the
  132. * database connection object instead of these wrappers; See @ref sec_connection
  133. * below for details.
  134. *
  135. * For example, if your query is:
  136. * @code
  137. * INSERT INTO example (id, uid, path, name) VALUES (1, 2, 'path', 'Name');
  138. * @endcode
  139. * You can execute it via:
  140. * @code
  141. * $fields = array('id' => 1, 'uid' => 2, 'path' => 'path', 'name' => 'Name');
  142. * db_insert('example')
  143. * ->fields($fields)
  144. * ->execute();
  145. * @endcode
  146. *
  147. * @section sec_transaction Transactions
  148. * Drupal supports transactions, including a transparent fallback for
  149. * databases that do not support transactions. To start a new transaction,
  150. * call @code $txn = db_transaction(); @endcode The transaction will
  151. * remain open for as long as the variable $txn remains in scope; when $txn is
  152. * destroyed, the transaction will be committed. If your transaction is nested
  153. * inside of another then Drupal will track each transaction and only commit
  154. * the outer-most transaction when the last transaction object goes out out of
  155. * scope (when all relevant queries have completed successfully).
  156. *
  157. * Example:
  158. * @code
  159. * function my_transaction_function() {
  160. * // The transaction opens here.
  161. * $txn = db_transaction();
  162. *
  163. * try {
  164. * $id = db_insert('example')
  165. * ->fields(array(
  166. * 'field1' => 'mystring',
  167. * 'field2' => 5,
  168. * ))
  169. * ->execute();
  170. *
  171. * my_other_function($id);
  172. *
  173. * return $id;
  174. * }
  175. * catch (Exception $e) {
  176. * // Something went wrong somewhere, so roll back now.
  177. * $txn->rollBack();
  178. * // Log the exception to watchdog.
  179. * watchdog_exception('type', $e);
  180. * }
  181. *
  182. * // $txn goes out of scope here. Unless the transaction was rolled back, it
  183. * // gets automatically committed here.
  184. * }
  185. *
  186. * function my_other_function($id) {
  187. * // The transaction is still open here.
  188. *
  189. * if ($id % 2 == 0) {
  190. * db_update('example')
  191. * ->condition('id', $id)
  192. * ->fields(array('field2' => 10))
  193. * ->execute();
  194. * }
  195. * }
  196. * @endcode
  197. *
  198. * @section sec_connection Database connection objects
  199. * The examples here all use functions like db_select() and db_query(), which
  200. * can be called from any Drupal method or function code. In some classes, you
  201. * may already have a database connection object in a member variable, or it may
  202. * be passed into a class constructor via dependency injection. If that is the
  203. * case, you can look at the code for db_select() and the other functions to see
  204. * how to get a query object from your connection variable. For example:
  205. * @code
  206. * $query = $connection->select('example', 'e');
  207. * @endcode
  208. * would be the equivalent of
  209. * @code
  210. * $query = db_select('example', 'e');
  211. * @endcode
  212. * if you had a connection object variable $connection available to use. See
  213. * also the @link container Services and Dependency Injection topic. @endlink
  214. *
  215. * @see https://www.drupal.org/developing/api/database
  216. * @see entity_api
  217. * @see schemaapi
  218. *
  219. * @}
  220. */
  221. /**
  222. * @defgroup schemaapi Schema API
  223. * @{
  224. * API to handle database schemas.
  225. *
  226. * A Drupal schema definition is an array structure representing one or
  227. * more tables and their related keys and indexes. A schema is defined by
  228. * hook_schema(), which usually lives in a modulename.install file.
  229. *
  230. * By implementing hook_schema() and specifying the tables your module
  231. * declares, you can easily create and drop these tables on all
  232. * supported database engines. You don't have to deal with the
  233. * different SQL dialects for table creation and alteration of the
  234. * supported database engines.
  235. *
  236. * hook_schema() should return an array with a key for each table that
  237. * the module defines.
  238. *
  239. * The following keys are defined:
  240. * - 'description': A string in non-markup plain text describing this table
  241. * and its purpose. References to other tables should be enclosed in
  242. * curly-brackets. For example, the node_field_revision table
  243. * description field might contain "Stores per-revision title and
  244. * body data for each {node}."
  245. * - 'fields': An associative array ('fieldname' => specification)
  246. * that describes the table's database columns. The specification
  247. * is also an array. The following specification parameters are defined:
  248. * - 'description': A string in non-markup plain text describing this field
  249. * and its purpose. References to other tables should be enclosed in
  250. * curly-brackets. For example, the node table vid field
  251. * description might contain "Always holds the largest (most
  252. * recent) {node_field_revision}.vid value for this nid."
  253. * - 'type': The generic datatype: 'char', 'varchar', 'text', 'blob', 'int',
  254. * 'float', 'numeric', or 'serial'. Most types just map to the according
  255. * database engine specific datatypes. Use 'serial' for auto incrementing
  256. * fields. This will expand to 'INT auto_increment' on MySQL.
  257. * A special 'varchar_ascii' type is also available for limiting machine
  258. * name field to US ASCII characters.
  259. * - 'mysql_type', 'pgsql_type', 'sqlite_type', etc.: If you need to
  260. * use a record type not included in the officially supported list
  261. * of types above, you can specify a type for each database
  262. * backend. In this case, you can leave out the type parameter,
  263. * but be advised that your schema will fail to load on backends that
  264. * do not have a type specified. A possible solution can be to
  265. * use the "text" type as a fallback.
  266. * - 'serialize': A boolean indicating whether the field will be stored as
  267. * a serialized string.
  268. * - 'size': The data size: 'tiny', 'small', 'medium', 'normal',
  269. * 'big'. This is a hint about the largest value the field will
  270. * store and determines which of the database engine specific
  271. * datatypes will be used (e.g. on MySQL, TINYINT vs. INT vs. BIGINT).
  272. * 'normal', the default, selects the base type (e.g. on MySQL,
  273. * INT, VARCHAR, BLOB, etc.).
  274. * Not all sizes are available for all data types. See
  275. * DatabaseSchema::getFieldTypeMap() for possible combinations.
  276. * - 'not null': If true, no NULL values will be allowed in this
  277. * database column. Defaults to false.
  278. * - 'default': The field's default value. The PHP type of the
  279. * value matters: '', '0', and 0 are all different. If you
  280. * specify '0' as the default value for a type 'int' field it
  281. * will not work because '0' is a string containing the
  282. * character "zero", not an integer.
  283. * - 'length': The maximal length of a type 'char', 'varchar' or 'text'
  284. * field. Ignored for other field types.
  285. * - 'unsigned': A boolean indicating whether a type 'int', 'float'
  286. * and 'numeric' only is signed or unsigned. Defaults to
  287. * FALSE. Ignored for other field types.
  288. * - 'precision', 'scale': For type 'numeric' fields, indicates
  289. * the precision (total number of significant digits) and scale
  290. * (decimal digits right of the decimal point). Both values are
  291. * mandatory. Ignored for other field types.
  292. * - 'binary': A boolean indicating that MySQL should force 'char',
  293. * 'varchar' or 'text' fields to use case-sensitive binary collation.
  294. * This has no effect on other database types for which case sensitivity
  295. * is already the default behavior.
  296. * All parameters apart from 'type' are optional except that type
  297. * 'numeric' columns must specify 'precision' and 'scale', and type
  298. * 'varchar' must specify the 'length' parameter.
  299. * - 'primary key': An array of one or more key column specifiers (see below)
  300. * that form the primary key.
  301. * - 'unique keys': An associative array of unique keys ('keyname' =>
  302. * specification). Each specification is an array of one or more
  303. * key column specifiers (see below) that form a unique key on the table.
  304. * - 'foreign keys': An associative array of relations ('my_relation' =>
  305. * specification). Each specification is an array containing the name of
  306. * the referenced table ('table'), and an array of column mappings
  307. * ('columns'). Column mappings are defined by key pairs ('source_column' =>
  308. * 'referenced_column'). This key is for documentation purposes only; foreign
  309. * keys are not created in the database, nor are they enforced by Drupal.
  310. * - 'indexes': An associative array of indexes ('indexname' =>
  311. * specification). Each specification is an array of one or more
  312. * key column specifiers (see below) that form an index on the
  313. * table.
  314. *
  315. * A key column specifier is either a string naming a column or an
  316. * array of two elements, column name and length, specifying a prefix
  317. * of the named column.
  318. *
  319. * As an example, here is a SUBSET of the schema definition for
  320. * Drupal's 'node' table. It show four fields (nid, vid, type, and
  321. * title), the primary key on field 'nid', a unique key named 'vid' on
  322. * field 'vid', and two indexes, one named 'nid' on field 'nid' and
  323. * one named 'node_title_type' on the field 'title' and the first four
  324. * bytes of the field 'type':
  325. *
  326. * @code
  327. * $schema['node'] = array(
  328. * 'description' => 'The base table for nodes.',
  329. * 'fields' => array(
  330. * 'nid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
  331. * 'vid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE,'default' => 0),
  332. * 'type' => array('type' => 'varchar','length' => 32,'not null' => TRUE, 'default' => ''),
  333. * 'language' => array('type' => 'varchar','length' => 12,'not null' => TRUE,'default' => ''),
  334. * 'title' => array('type' => 'varchar','length' => 255,'not null' => TRUE, 'default' => ''),
  335. * 'uid' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
  336. * 'status' => array('type' => 'int', 'not null' => TRUE, 'default' => 1),
  337. * 'created' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
  338. * 'changed' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
  339. * 'comment' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
  340. * 'promote' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
  341. * 'moderate' => array('type' => 'int', 'not null' => TRUE,'default' => 0),
  342. * 'sticky' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
  343. * 'translate' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
  344. * ),
  345. * 'indexes' => array(
  346. * 'node_changed' => array('changed'),
  347. * 'node_created' => array('created'),
  348. * 'node_moderate' => array('moderate'),
  349. * 'node_frontpage' => array('promote', 'status', 'sticky', 'created'),
  350. * 'node_status_type' => array('status', 'type', 'nid'),
  351. * 'node_title_type' => array('title', array('type', 4)),
  352. * 'node_type' => array(array('type', 4)),
  353. * 'uid' => array('uid'),
  354. * 'translate' => array('translate'),
  355. * ),
  356. * 'unique keys' => array(
  357. * 'vid' => array('vid'),
  358. * ),
  359. * // For documentation purposes only; foreign keys are not created in the
  360. * // database.
  361. * 'foreign keys' => array(
  362. * 'node_revision' => array(
  363. * 'table' => 'node_field_revision',
  364. * 'columns' => array('vid' => 'vid'),
  365. * ),
  366. * 'node_author' => array(
  367. * 'table' => 'users',
  368. * 'columns' => array('uid' => 'uid'),
  369. * ),
  370. * ),
  371. * 'primary key' => array('nid'),
  372. * );
  373. * @endcode
  374. *
  375. * @see drupal_install_schema()
  376. *
  377. * @}
  378. */
  379. /**
  380. * @addtogroup hooks
  381. * @{
  382. */
  383. /**
  384. * Perform alterations to a structured query.
  385. *
  386. * Structured (aka dynamic) queries that have tags associated may be altered by any module
  387. * before the query is executed.
  388. *
  389. * @param $query
  390. * A Query object describing the composite parts of a SQL query.
  391. *
  392. * @see hook_query_TAG_alter()
  393. * @see node_query_node_access_alter()
  394. * @see AlterableInterface
  395. * @see SelectInterface
  396. *
  397. * @ingroup database
  398. */
  399. function hook_query_alter(Drupal\Core\Database\Query\AlterableInterface $query) {
  400. if ($query->hasTag('micro_limit')) {
  401. $query->range(0, 2);
  402. }
  403. }
  404. /**
  405. * Perform alterations to a structured query for a given tag.
  406. *
  407. * @param $query
  408. * An Query object describing the composite parts of a SQL query.
  409. *
  410. * @see hook_query_alter()
  411. * @see node_query_node_access_alter()
  412. * @see AlterableInterface
  413. * @see SelectInterface
  414. *
  415. * @ingroup database
  416. */
  417. function hook_query_TAG_alter(Drupal\Core\Database\Query\AlterableInterface $query) {
  418. // Skip the extra expensive alterations if site has no node access control modules.
  419. if (!node_access_view_all_nodes()) {
  420. // Prevent duplicates records.
  421. $query->distinct();
  422. // The recognized operations are 'view', 'update', 'delete'.
  423. if (!$op = $query->getMetaData('op')) {
  424. $op = 'view';
  425. }
  426. // Skip the extra joins and conditions for node admins.
  427. if (!\Drupal::currentUser()->hasPermission('bypass node access')) {
  428. // The node_access table has the access grants for any given node.
  429. $access_alias = $query->join('node_access', 'na', '%alias.nid = n.nid');
  430. $or = new Condition('OR');
  431. // If any grant exists for the specified user, then user has access to the node for the specified operation.
  432. foreach (node_access_grants($op, $query->getMetaData('account')) as $realm => $gids) {
  433. foreach ($gids as $gid) {
  434. $or->condition((new Condition('AND'))
  435. ->condition($access_alias . '.gid', $gid)
  436. ->condition($access_alias . '.realm', $realm)
  437. );
  438. }
  439. }
  440. if (count($or->conditions())) {
  441. $query->condition($or);
  442. }
  443. $query->condition($access_alias . 'grant_' . $op, 1, '>=');
  444. }
  445. }
  446. }
  447. /**
  448. * Define the current version of the database schema.
  449. *
  450. * A Drupal schema definition is an array structure representing one or more
  451. * tables and their related keys and indexes. A schema is defined by
  452. * hook_schema() which must live in your module's .install file.
  453. *
  454. * The tables declared by this hook will be automatically created when the
  455. * module is installed, and removed when the module is uninstalled. This happens
  456. * before hook_install() is invoked, and after hook_uninstall() is invoked,
  457. * respectively.
  458. *
  459. * By declaring the tables used by your module via an implementation of
  460. * hook_schema(), these tables will be available on all supported database
  461. * engines. You don't have to deal with the different SQL dialects for table
  462. * creation and alteration of the supported database engines.
  463. *
  464. * See the Schema API Handbook at https://www.drupal.org/node/146843 for details
  465. * on schema definition structures. Note that foreign key definitions are for
  466. * documentation purposes only; foreign keys are not created in the database,
  467. * nor are they enforced by Drupal.
  468. *
  469. * @return array
  470. * A schema definition structure array. For each element of the
  471. * array, the key is a table name and the value is a table structure
  472. * definition.
  473. *
  474. * @ingroup schemaapi
  475. */
  476. function hook_schema() {
  477. $schema['node'] = [
  478. // Example (partial) specification for table "node".
  479. 'description' => 'The base table for nodes.',
  480. 'fields' => [
  481. 'nid' => [
  482. 'description' => 'The primary identifier for a node.',
  483. 'type' => 'serial',
  484. 'unsigned' => TRUE,
  485. 'not null' => TRUE,
  486. ],
  487. 'vid' => [
  488. 'description' => 'The current {node_field_revision}.vid version identifier.',
  489. 'type' => 'int',
  490. 'unsigned' => TRUE,
  491. 'not null' => TRUE,
  492. 'default' => 0,
  493. ],
  494. 'type' => [
  495. 'description' => 'The type of this node.',
  496. 'type' => 'varchar',
  497. 'length' => 32,
  498. 'not null' => TRUE,
  499. 'default' => '',
  500. ],
  501. 'title' => [
  502. 'description' => 'The node title.',
  503. 'type' => 'varchar',
  504. 'length' => 255,
  505. 'not null' => TRUE,
  506. 'default' => '',
  507. ],
  508. ],
  509. 'indexes' => [
  510. 'node_changed' => ['changed'],
  511. 'node_created' => ['created'],
  512. ],
  513. 'unique keys' => [
  514. 'nid_vid' => ['nid', 'vid'],
  515. 'vid' => ['vid'],
  516. ],
  517. // For documentation purposes only; foreign keys are not created in the
  518. // database.
  519. 'foreign keys' => [
  520. 'node_revision' => [
  521. 'table' => 'node_field_revision',
  522. 'columns' => ['vid' => 'vid'],
  523. ],
  524. 'node_author' => [
  525. 'table' => 'users',
  526. 'columns' => ['uid' => 'uid'],
  527. ],
  528. ],
  529. 'primary key' => ['nid'],
  530. ];
  531. return $schema;
  532. }
  533. /**
  534. * @} End of "addtogroup hooks".
  535. */