database.api.php 23 KB

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