database.api.php 22 KB

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