Database abstraction layer in Drupal 8
Same name and namespace in other branches
- 4 includes/database.inc \database
- 5 includes/database.inc \database
- 6 includes/database.inc \database
- 7 includes/database/database.inc \database
- 9 core/lib/Drupal/Core/Database/database.api.php \database
Allow the use of different database servers using the same code base.
Overview
Drupal's database abstraction layer provides a unified database query API that can query different underlying databases. It is built upon PHP's PDO (PHP Data Objects) database API, and inherits much of its syntax and semantics. Besides providing a unified API for database queries, the database abstraction layer also provides a structured way to construct complex queries, and it protects the database by using good security practices.
For more detailed information on the database abstraction layer, see https://www.drupal.org/docs/8/api/database-api/database-api-overview.
Querying entities
Any query on Drupal entities or fields should use the Entity Query API. See the entity API topic for more information.
Simple SELECT database queries
For simple SELECT queries that do not involve entities, the Drupal database abstraction layer provides the functions \Drupal::database()->query() and \Drupal::database()->queryRange(), which execute SELECT queries (optionally with range limits) and return result sets that you can iterate over using foreach loops. (The result sets are objects implementing the \Drupal\Core\Database\StatementInterface interface.) You can use the simple query functions for query strings that are not dynamic (except for placeholders, see below), and that you are certain will work in any database engine. See Dynamic SELECT queries below if you have a more complex query, or a query whose syntax would be different in some databases.
Note: \Drupal::database() is used here as a shorthand way to get a reference to the database connection object. In most classes, you should use dependency injection and inject the 'database' service to perform queries. See Database connection objects below for details.
To use the simple database query functions, you will need to make a couple of modifications to your bare SQL query:
- Enclose your table name in {}. Drupal allows site builders to use database table name prefixes, so you cannot be sure what the actual name of the table will be. So, use the name that is in the hook_schema(), enclosed in {}, and Drupal will calculate the right name.
- Instead of putting values for conditions into the query, use placeholders. The placeholders are named and start with :, and they take the place of putting variables directly into the query, to protect against SQL injection attacks.
- LIMIT syntax differs between databases, so if you have a ranged query, use \Drupal::database()->queryRange() instead of \Drupal::database()->query().
For example, if the query you want to run is:
SELECT e.id, e.title, e.created FROM example e WHERE e.uid = $uid
ORDER BY e.created DESC LIMIT 0, 10;
you would do it like this:
$result = \Drupal::database()
->queryRange('SELECT e.id, e.title, e.created
FROM {example} e
WHERE e.uid = :uid
ORDER BY e.created DESC', 0, 10, array(
':uid' => $uid,
));
foreach ($result as $record) {
// Perform operations on $record->title, etc. here.
}
Note that if your query has a string condition, like:
WHERE e.my_field = 'foo'
when you convert it to placeholders, omit the quotes:
WHERE e.my_field = :my_field
... array(':my_field' => 'foo') ...
Dynamic SELECT queries
For SELECT queries where the simple query API described in Simple SELECT database queries will not work well, you need to use the dynamic query API. However, you should still use the Entity Query API if your query involves entities or fields (see the Entity API topic for more on entity queries).
Note: \Drupal::database() is used here as a shorthand way to get a reference to the database connection object. In most classes, you should use dependency injection and inject the 'database' service to perform queries. See Database connection objects below for details.
The dynamic query API lets you build up a query dynamically using method calls. As an illustration, the query example from Simple SELECT database queries above would be:
$result = \Drupal::database()
->select('example', 'e')
->fields('e', array(
'id',
'title',
'created',
))
->condition('e.uid', $uid)
->orderBy('e.created', 'DESC')
->range(0, 10)
->execute();
There are also methods to join to other tables, add fields with aliases, isNull() to query for NULL values, etc. See https://www.drupal.org/developing/api/database for many more details.
One note on chaining: It is common in the dynamic database API to chain method calls (as illustrated here), because most of the query methods modify the query object and then return the modified query as their return value. However, there are some important exceptions; these methods (and some others) do not support chaining:
- join(), innerJoin(), etc.: These methods return the joined table alias.
- addField(): This method returns the field alias.
Check the documentation for the query method you are using to see if it returns the query or something else, and only chain methods that return the query.
INSERT, UPDATE, and DELETE queries
INSERT, UPDATE, and DELETE queries need special care in order to behave consistently across databases; you should never use \Drupal::database()->query() to run an INSERT, UPDATE, or DELETE query. Instead, use functions \Drupal::database()->insert(), \Drupal::database()->update(), and \Drupal::database()->delete() to obtain a base query on your table, and then add dynamic conditions (as illustrated in Dynamic SELECT queries above).
Note: \Drupal::database() is used here as a shorthand way to get a reference to the database connection object. In most classes, you should use dependency injection and inject the 'database' service to perform queries. See Database connection objects below for details.
For example, if your query is:
INSERT INTO example (id, uid, path, name) VALUES (1, 2, 'path', 'Name');
You can execute it via:
$fields = array(
'id' => 1,
'uid' => 2,
'path' => 'path',
'name' => 'Name',
);
\Drupal::database()
->insert('example')
->fields($fields)
->execute();
Transactions
Drupal supports transactions, including a transparent fallback for databases that do not support transactions. To start a new transaction, call startTransaction(), like this:
$transaction = \Drupal::database()
->startTransaction();
The transaction will remain open for as long as the variable $transaction remains in scope; when $transaction is destroyed, the transaction will be committed. If your transaction is nested inside of another then Drupal will track each transaction and only commit the outer-most transaction when the last transaction object goes out out of scope (when all relevant queries have completed successfully).
Example:
function my_transaction_function() {
$connection = \Drupal::database();
// The transaction opens here.
$transaction = $connection
->startTransaction();
try {
$id = $connection
->insert('example')
->fields(array(
'field1' => 'mystring',
'field2' => 5,
))
->execute();
my_other_function($id);
return $id;
} catch (Exception $e) {
// Something went wrong somewhere, so roll back now.
$transaction
->rollBack();
// Log the exception to watchdog.
watchdog_exception('type', $e);
}
// $transaction goes out of scope here. Unless the transaction was rolled
// back, it gets automatically committed here.
}
function my_other_function($id) {
$connection = \Drupal::database();
// The transaction is still open here.
if ($id % 2 == 0) {
$connection
->update('example')
->condition('id', $id)
->fields(array(
'field2' => 10,
))
->execute();
}
}
Database connection objects
The examples here all use functions like \Drupal::database()->select() and \Drupal::database()->query(), which can be called from any Drupal method or function code. In some classes, you may already have a database connection object in a member variable, or it may be passed into a class constructor via dependency injection. If that is the case, you can look at the code for \Drupal::database()->select() and the other functions to see how to get a query object from your connection variable. For example:
$query = $connection
->select('example', 'e');
would be the equivalent of
$query = \Drupal::database()
->select('example', 'e');
if you had a connection object variable $connection available to use. See also the Services and Dependency Injection topic.
See also
https://www.drupal.org/developing/api/database
File
- core/
lib/ Drupal/ Core/ Database/ database.api.php, line 10 - Hooks related to the Database system and the Schema API.
Functions
Name | Location | Description |
---|---|---|
db_and Deprecated |
core/ |
Returns a new DatabaseCondition, set to "AND" all conditions together. |
db_close Deprecated |
core/ |
Closes the active database connection. |
db_condition Deprecated |
core/ |
Returns a new DatabaseCondition, set to the specified conjunction. |
db_delete Deprecated |
core/ |
Returns a new DeleteQuery object for the active database. |
db_driver Deprecated |
core/ |
Retrieves the name of the currently active database driver. |
db_escape_field Deprecated |
core/ |
Restricts a dynamic column or constraint name to safe characters. |
db_escape_table Deprecated |
core/ |
Restricts a dynamic table name to safe characters. |
db_insert Deprecated |
core/ |
Returns a new InsertQuery object for the active database. |
db_like Deprecated |
core/ |
Escapes characters that work as wildcard characters in a LIKE pattern. |
db_merge Deprecated |
core/ |
Returns a new MergeQuery object for the active database. |
db_next_id Deprecated |
core/ |
Retrieves a unique id. |
db_or Deprecated |
core/ |
Returns a new DatabaseCondition, set to "OR" all conditions together. |
db_query Deprecated |
core/ |
Executes an arbitrary query string against the active database. |
db_query_range Deprecated |
core/ |
Executes a query against the active database, restricted to a range. |
db_query_temporary Deprecated |
core/ |
Executes a SELECT query string and saves the result set to a temporary table. |
db_select Deprecated |
core/ |
Returns a new SelectQuery object for the active database. |
db_set_active Deprecated |
core/ |
Sets a new active database. |
db_transaction Deprecated |
core/ |
Returns a new transaction object for the active database. |
db_truncate Deprecated |
core/ |
Returns a new TruncateQuery object for the active database. |
db_update Deprecated |
core/ |
Returns a new UpdateQuery object for the active database. |
db_xor Deprecated |
core/ |
Returns a new DatabaseCondition, set to "XOR" all conditions together. |
hook_query_alter |
core/ |
Perform alterations to a structured query. |
hook_query_TAG_alter |
core/ |
Perform alterations to a structured query for a given tag. |
_db_get_target Deprecated |
core/ |
Get target helper. |
Classes
Name | Location | Description |
---|---|---|
Connection |
core/ |
PostgreSQL implementation of \Drupal\Core\Database\Connection. |
Connection |
core/ |
MySQL implementation of \Drupal\Core\Database\Connection. |
Delete |
core/ |
General class for an abstracted DELETE operation. |
Insert |
core/ |
General class for an abstracted INSERT query. |
Insert |
core/ |
PostgreSQL implementation of \Drupal\Core\Database\Query\Insert. |
Select |
core/ |
Query builder for SELECT statements. |
Select |
core/ |
PostgreSQL implementation of \Drupal\Core\Database\Query\Select. |
Update |
core/ |
General class for an abstracted UPDATE operation. |
Interfaces
Name | Location | Description |
---|---|---|
QueryInterface |
core/ |
Interface for entity queries. |
SelectInterface |
core/ |
Interface definition for a Select Query object. |
StatementInterface |
core/ |
Represents a prepared statement. |
Traits
Name | Location | Description |
---|---|---|
InsertTrait |
core/ |
Provides common functionality for INSERT and UPSERT queries. |