Upsert.php

Same filename in this branch
  1. 11.x core/modules/sqlite/src/Driver/Database/sqlite/Upsert.php
  2. 11.x core/modules/mysql/src/Driver/Database/mysql/Upsert.php
  3. 11.x core/modules/pgsql/src/Driver/Database/pgsql/Upsert.php
  4. 11.x core/tests/fixtures/database_drivers/module/core_fake/src/Driver/Database/CoreFakeWithAllCustomClasses/Upsert.php
Same filename in other branches
  1. 9 core/modules/sqlite/src/Driver/Database/sqlite/Upsert.php
  2. 9 core/modules/mysql/src/Driver/Database/mysql/Upsert.php
  3. 9 core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysql/Upsert.php
  4. 9 core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Upsert.php
  5. 9 core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestPgsql/Upsert.php
  6. 9 core/modules/pgsql/src/Driver/Database/pgsql/Upsert.php
  7. 9 core/tests/fixtures/database_drivers/module/corefake/src/Driver/Database/corefakeWithAllCustomClasses/Upsert.php
  8. 9 core/lib/Drupal/Core/Database/Driver/sqlite/Upsert.php
  9. 9 core/lib/Drupal/Core/Database/Driver/mysql/Upsert.php
  10. 9 core/lib/Drupal/Core/Database/Driver/pgsql/Upsert.php
  11. 9 core/lib/Drupal/Core/Database/Query/Upsert.php
  12. 8.9.x core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysql/Upsert.php
  13. 8.9.x core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestPgsql/Upsert.php
  14. 8.9.x core/lib/Drupal/Core/Database/Driver/sqlite/Upsert.php
  15. 8.9.x core/lib/Drupal/Core/Database/Driver/mysql/Upsert.php
  16. 8.9.x core/lib/Drupal/Core/Database/Driver/pgsql/Upsert.php
  17. 8.9.x core/lib/Drupal/Core/Database/Query/Upsert.php
  18. 10 core/modules/sqlite/src/Driver/Database/sqlite/Upsert.php
  19. 10 core/modules/mysql/src/Driver/Database/mysql/Upsert.php
  20. 10 core/modules/pgsql/src/Driver/Database/pgsql/Upsert.php
  21. 10 core/tests/fixtures/database_drivers/module/core_fake/src/Driver/Database/CoreFakeWithAllCustomClasses/Upsert.php
  22. 10 core/lib/Drupal/Core/Database/Driver/sqlite/Upsert.php
  23. 10 core/lib/Drupal/Core/Database/Driver/mysql/Upsert.php
  24. 10 core/lib/Drupal/Core/Database/Driver/pgsql/Upsert.php
  25. 10 core/lib/Drupal/Core/Database/Query/Upsert.php

Namespace

Drupal\Core\Database\Query

File

core/lib/Drupal/Core/Database/Query/Upsert.php

View source
<?php

namespace Drupal\Core\Database\Query;

use Drupal\Core\Database\Connection;

/**
 * General class for an abstracted "Upsert" (UPDATE or INSERT) query operation.
 *
 * This class can only be used with a table with a single unique index.
 * Often, this will be the primary key. On such a table this class works like
 * Insert except the rows will be set to the desired values even if the key
 * existed before.
 */
abstract class Upsert extends Query implements \Countable {
    use InsertTrait;
    
    /**
     * The unique or primary key of the table.
     *
     * @var string
     */
    protected $key;
    
    /**
     * 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 to be used as condition for this query.
     *
     * @param string $field
     *   The name of the field to set.
     *
     * @return $this
     */
    public function key($field) {
        $this->key = $field;
        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;
            }
        }
        $stmt = $this->connection
            ->prepareStatement((string) $this, $this->queryOptions, TRUE);
        try {
            $stmt->execute($values, $this->queryOptions);
            $affected_rows = $stmt->rowCount();
        } catch (\Exception $e) {
            $this->connection
                ->exceptionHandler()
                ->handleExecutionException($e, $stmt, $values, $this->queryOptions);
        }
        // Re-initialize the values array so that we can re-use this query.
        $this->insertValues = [];
        return $affected_rows;
    }

}

Classes

Title Deprecated Summary
Upsert General class for an abstracted "Upsert" (UPDATE or INSERT) query operation.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.