class Upsert
Same name in this branch
- main core/modules/sqlite/src/Driver/Database/sqlite/Upsert.php \Drupal\sqlite\Driver\Database\sqlite\Upsert
- main core/modules/mysql/src/Driver/Database/mysql/Upsert.php \Drupal\mysql\Driver\Database\mysql\Upsert
- main core/modules/pgsql/src/Driver/Database/pgsql/Upsert.php \Drupal\pgsql\Driver\Database\pgsql\Upsert
- main core/tests/fixtures/database_drivers/module/core_fake/src/Driver/Database/CoreFakeWithAllCustomClasses/Upsert.php \Drupal\core_fake\Driver\Database\CoreFakeWithAllCustomClasses\Upsert
Same name and namespace in other branches
- 11.x core/modules/sqlite/src/Driver/Database/sqlite/Upsert.php \Drupal\sqlite\Driver\Database\sqlite\Upsert
- 11.x core/modules/mysql/src/Driver/Database/mysql/Upsert.php \Drupal\mysql\Driver\Database\mysql\Upsert
- 11.x core/modules/pgsql/src/Driver/Database/pgsql/Upsert.php \Drupal\pgsql\Driver\Database\pgsql\Upsert
- 11.x core/tests/fixtures/database_drivers/module/core_fake/src/Driver/Database/CoreFakeWithAllCustomClasses/Upsert.php \Drupal\core_fake\Driver\Database\CoreFakeWithAllCustomClasses\Upsert
- 11.x core/lib/Drupal/Core/Database/Query/Upsert.php \Drupal\Core\Database\Query\Upsert
- 10 core/modules/sqlite/src/Driver/Database/sqlite/Upsert.php \Drupal\sqlite\Driver\Database\sqlite\Upsert
- 10 core/modules/mysql/src/Driver/Database/mysql/Upsert.php \Drupal\mysql\Driver\Database\mysql\Upsert
- 10 core/modules/pgsql/src/Driver/Database/pgsql/Upsert.php \Drupal\pgsql\Driver\Database\pgsql\Upsert
- 10 core/tests/fixtures/database_drivers/module/core_fake/src/Driver/Database/CoreFakeWithAllCustomClasses/Upsert.php \Drupal\core_fake\Driver\Database\CoreFakeWithAllCustomClasses\Upsert
- 10 core/lib/Drupal/Core/Database/Driver/sqlite/Upsert.php \Drupal\Core\Database\Driver\sqlite\Upsert
- 10 core/lib/Drupal/Core/Database/Driver/mysql/Upsert.php \Drupal\Core\Database\Driver\mysql\Upsert
- 10 core/lib/Drupal/Core/Database/Driver/pgsql/Upsert.php \Drupal\Core\Database\Driver\pgsql\Upsert
- 10 core/lib/Drupal/Core/Database/Query/Upsert.php \Drupal\Core\Database\Query\Upsert
- 9 core/modules/sqlite/src/Driver/Database/sqlite/Upsert.php \Drupal\sqlite\Driver\Database\sqlite\Upsert
- 9 core/modules/mysql/src/Driver/Database/mysql/Upsert.php \Drupal\mysql\Driver\Database\mysql\Upsert
- 9 core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysql/Upsert.php \Drupal\driver_test\Driver\Database\DrivertestMysql\Upsert
- 9 core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Upsert.php \Drupal\driver_test\Driver\Database\DrivertestMysqlDeprecatedVersion\Upsert
- 9 core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestPgsql/Upsert.php \Drupal\driver_test\Driver\Database\DrivertestPgsql\Upsert
- 9 core/modules/pgsql/src/Driver/Database/pgsql/Upsert.php \Drupal\pgsql\Driver\Database\pgsql\Upsert
- 9 core/tests/fixtures/database_drivers/module/corefake/src/Driver/Database/corefakeWithAllCustomClasses/Upsert.php \Drupal\corefake\Driver\Database\corefakeWithAllCustomClasses\Upsert
- 9 core/lib/Drupal/Core/Database/Driver/sqlite/Upsert.php \Drupal\Core\Database\Driver\sqlite\Upsert
- 9 core/lib/Drupal/Core/Database/Driver/mysql/Upsert.php \Drupal\Core\Database\Driver\mysql\Upsert
- 9 core/lib/Drupal/Core/Database/Driver/pgsql/Upsert.php \Drupal\Core\Database\Driver\pgsql\Upsert
- 9 core/lib/Drupal/Core/Database/Query/Upsert.php \Drupal\Core\Database\Query\Upsert
- 8.9.x core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysql/Upsert.php \Drupal\driver_test\Driver\Database\DrivertestMysql\Upsert
- 8.9.x core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestPgsql/Upsert.php \Drupal\driver_test\Driver\Database\DrivertestPgsql\Upsert
- 8.9.x core/lib/Drupal/Core/Database/Driver/sqlite/Upsert.php \Drupal\Core\Database\Driver\sqlite\Upsert
- 8.9.x core/lib/Drupal/Core/Database/Driver/mysql/Upsert.php \Drupal\Core\Database\Driver\mysql\Upsert
- 8.9.x core/lib/Drupal/Core/Database/Driver/pgsql/Upsert.php \Drupal\Core\Database\Driver\pgsql\Upsert
- 8.9.x core/lib/Drupal/Core/Database/Query/Upsert.php \Drupal\Core\Database\Query\Upsert
General class for an abstracted "Upsert" (UPDATE or INSERT) query operation.
This class works like Insert except the rows will be set to the desired values even if the key existed before. It supports both single-field and composite (multi-field) unique or primary key constraints.
Hierarchy
- class \Drupal\Core\Database\Query\Query implements \Drupal\Core\Database\Query\PlaceholderInterface
- class \Drupal\Core\Database\Query\Upsert implements \Drupal\Core\Database\Query\Countable uses \Drupal\Core\Database\Query\InsertTrait extends \Drupal\Core\Database\Query\Query
Expanded class hierarchy of Upsert
6 files declare their use of Upsert
- Connection.php in core/
tests/ fixtures/ database_drivers/ custom/ fake/ Connection.php - StubUpsert.php in core/
tests/ Drupal/ Tests/ Core/ Database/ Stub/ StubUpsert.php - Upsert.php in core/
modules/ sqlite/ src/ Driver/ Database/ sqlite/ Upsert.php - Upsert.php in core/
modules/ mysql/ src/ Driver/ Database/ mysql/ Upsert.php - Upsert.php in core/
modules/ pgsql/ src/ Driver/ Database/ pgsql/ Upsert.php
1 string reference to 'Upsert'
- ConnectionTest::providerGetDriverClass in core/
tests/ Drupal/ Tests/ Core/ Database/ ConnectionTest.php - Data provider for testGetDriverClass().
File
-
core/
lib/ Drupal/ Core/ Database/ Query/ Upsert.php, line 14
Namespace
Drupal\Core\Database\QueryView source
abstract class Upsert extends Query implements \Countable {
use InsertTrait;
/**
* The unique or primary key column(s) of the table.
*
* @var string[]
*/
protected $key;
/**
* Explicit updates to be done in case of insert failure.
*
* If the insert part of the upsert fails, the default behavior is to update
* the existing record with the values passed in. However, in some cases you
* may want to see what is the value of a column of the existing record, and
* manipulate that - typically, counters or the like. This array contains
* such overrides.
*
* @var array<string,\Drupal\Core\Database\Query\UpsertUpdateExpression>
*/
protected array $updateExpressions = [];
/**
* Constructs an Upsert object.
*
* @param \Drupal\Core\Database\Connection $connection
* A Connection object.
* @param string $table
* Name of the table to associate with this query.
* @param array $options
* (optional) An array of database options.
*/
public function __construct(Connection $connection, $table, array $options = []) {
parent::__construct($connection, $options);
$this->table = $table;
}
/**
* Sets the unique / primary key field(s) to be used as condition.
*
* @param string|string[] $field
* The name of the field, or an array of field names for a composite key.
*
* @return $this
*/
public function key(string|array $field) {
$this->key = (array) $field;
return $this;
}
/**
* Adds a set of column->value pairs to be inserted.
*
* This method may only be called once. Calling it a second time will be
* ignored. To queue up multiple sets of values to be inserted at once,
* use the values() method.
*
* @param array<string|int,string|\Drupal\Core\Database\Query\UpsertUpdateExpression>|array<string,string|int|float|bool|array> $fields
* An array of columns on which to insert. This array may be indexed or
* associative. If indexed, the array is taken to be the list of columns.
* If associative, the keys of the array are taken to be the columns and
* the values are taken to be corresponding values to insert. If a
* $values argument is provided, $fields must be indexed.
* In the indexed form, an entry may map a column name to an
* UpsertUpdateExpression. When the row already exists, that expression is
* run for the column in place of overwriting it with the insert value.
* @param list<string|int|float|bool|array> $values
* (optional) An array of values to insert into the database. The values
* must be specified in the same order as the $fields array.
*
* @return $this
* The called object.
*
* @throws \InvalidArgumentException
* If an update expression is not keyed by its column name, or if a column
* name maps to an insert value while the $fields array is not fully
* associative.
*/
public function fields(array $fields, array $values = []) : static {
if (empty($this->insertFields)) {
if (empty($values)) {
$isFieldsAssociative = TRUE;
array_walk($fields, function (mixed $value, int|string $key) use (&$isFieldsAssociative) : void {
if (is_numeric($key) || is_string($key) && $value instanceof UpsertUpdateExpression) {
$isFieldsAssociative = FALSE;
}
});
if ($isFieldsAssociative) {
$values = array_values($fields);
$fields = array_keys($fields);
}
}
foreach ($fields as $key => $def) {
if ($def instanceof UpsertUpdateExpression) {
if (!is_string($key)) {
throw new \InvalidArgumentException('An update expression must be keyed by its column name.');
}
$this->insertFields[] = $key;
$this->updateExpressions[$key] = $def;
}
elseif (is_string($key)) {
throw new \InvalidArgumentException(sprintf('The entry for "%s" must be a column name or an update expression keyed by column name. Pass insert values via the $values argument or the values() method.', $key));
}
else {
$this->insertFields[] = $def;
}
}
if (!empty($values)) {
$this->values($values);
}
}
return $this;
}
/**
* Preprocesses and validates the query.
*
* @return bool
* TRUE if the validation was successful, FALSE otherwise.
*
* @throws \Drupal\Core\Database\Query\NoUniqueFieldException
* @throws \Drupal\Core\Database\Query\FieldsOverlapException
* @throws \Drupal\Core\Database\Query\NoFieldsException
*/
protected function preExecute() {
// Confirm that the user set the unique/primary key of the table.
if (!$this->key) {
throw new NoUniqueFieldException('There is no unique field specified.');
}
// Confirm that the user did not try to specify an identical
// field and default field.
if (array_intersect($this->insertFields, $this->defaultFields)) {
throw new FieldsOverlapException('You may not specify the same field to have a value and a schema-default value.');
}
// Don't execute query without fields.
if (count($this->insertFields) + count($this->defaultFields) == 0) {
throw new NoFieldsException('There are no fields available to insert with.');
}
// If no values have been added, silently ignore this query. This can happen
// if values are added conditionally, so we don't want to throw an
// exception.
return isset($this->insertValues[0]) || $this->insertFields;
}
/**
* Executes the UPSERT operation.
*
* @return int
* An integer indicating the number of rows affected by the operation. Do
* not rely on this value as a precise indication of the actual rows
* affected: different database engines return different values.
*/
public function execute() {
if (!$this->preExecute()) {
return NULL;
}
$max_placeholder = 0;
$values = [];
foreach ($this->insertValues as $insert_values) {
foreach ($insert_values as $value) {
$values[':db_insert_placeholder_' . $max_placeholder++] = $value;
}
}
foreach ($this->updateExpressions as $update_expression) {
foreach ($update_expression->arguments as $argument => $value) {
$values[$argument] = $value;
}
}
$stmt = $this->connection
->prepareStatement((string) $this, $this->queryOptions, TRUE);
try {
$stmt->execute($values, $this->queryOptions);
// Re-initialize the values array so that we can re-use this query.
$this->insertValues = [];
return $stmt->rowCount();
} catch (\Exception $e) {
$this->connection
->exceptionHandler()
->handleExecutionException($e, $stmt, $values, $this->queryOptions);
}
}
}
Members
| Title Sort descending | Modifiers | Object type | Summary | Overriden Title | Overrides |
|---|---|---|---|---|---|
| InsertTrait::$defaultFields | protected | property | An array of fields that should be set to their database-defined defaults. | ||
| InsertTrait::$insertFields | protected | property | An array of fields on which to insert. | ||
| InsertTrait::$insertValues | protected | property | A nested array of values to insert. | ||
| InsertTrait::$table | protected | property | The table on which to insert. | ||
| InsertTrait::count | public | function | |||
| InsertTrait::getInsertPlaceholderFragment | protected | function | Returns the query placeholders for values that will be inserted. | ||
| InsertTrait::useDefaults | public | function | Specifies fields for which the database defaults should be used. | ||
| InsertTrait::values | public | function | Adds another set of values to the query to be inserted. | ||
| Query::$comments | protected | property | An array of comments that can be prepended to a query. | ||
| Query::$connection | protected | property | The connection object on which to run this query. | ||
| Query::$connectionKey | protected | property | The key of the connection object. | ||
| Query::$connectionTarget | protected | property | The target of the connection object. | ||
| Query::$nextPlaceholder | protected | property | The placeholder counter. | ||
| Query::$queryOptions | protected | property | The query options to pass on to the connection object. | ||
| Query::$uniqueIdentifier | protected | property | A unique identifier for this query object. | ||
| Query::comment | public | function | Adds a comment to the query. | ||
| Query::getComments | public | function | Returns a reference to the comments array for the query. | ||
| Query::getConnection | public | function | Gets the database connection to be used for the query. | ||
| Query::nextPlaceholder | public | function | Gets the next placeholder value for this query object. | Overrides PlaceholderInterface::nextPlaceholder | |
| Query::uniqueIdentifier | public | function | Returns a unique identifier for this object. | Overrides PlaceholderInterface::uniqueIdentifier | |
| Query::__clone | public | function | Implements the magic __clone function. | 1 | |
| Query::__sleep | public | function | Implements the magic __sleep function to disconnect from the database. | ||
| Query::__toString | abstract public | function | Implements PHP magic __toString method to convert the query to a string. | 11 | |
| Query::__wakeup | public | function | Implements the magic __wakeup function to reconnect to the database. | ||
| Upsert::$key | protected | property | The unique or primary key column(s) of the table. | ||
| Upsert::$updateExpressions | protected | property | Explicit updates to be done in case of insert failure. | ||
| Upsert::execute | public | function | Executes the UPSERT operation. | 2 | |
| Upsert::fields | public | function | Adds a set of column->value pairs to be inserted. | Overrides InsertTrait::fields | |
| Upsert::key | public | function | Sets the unique / primary key field(s) to be used as condition. | ||
| Upsert::preExecute | protected | function | Preprocesses and validates the query. | ||
| Upsert::__construct | public | function | Constructs an Upsert object. | Overrides Query::__construct |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.