3 namespace Drupal\Core\Database\Query;
5 use Drupal\Core\Database\Database;
6 use Drupal\Core\Database\Connection;
9 * General class for an abstracted UPDATE operation.
13 class Update extends Query implements ConditionInterface {
15 use QueryConditionTrait;
18 * The table to update.
25 * An array of fields that will be updated.
29 protected $fields = [];
32 * An array of values to update to.
36 protected $arguments = [];
39 * Array of fields to update to an expression in case of a duplicate record.
41 * This variable is a nested array in the following format:
43 * <some field> => array(
44 * 'condition' => <condition to execute, as a string>,
45 * 'arguments' => <array of arguments for condition, or NULL for none>,
51 protected $expressionFields = [];
54 * Constructs an Update query object.
56 * @param \Drupal\Core\Database\Connection $connection
57 * A Connection object.
58 * @param string $table
59 * Name of the table to associate with this query.
60 * @param array $options
61 * Array of database options.
63 public function __construct(Connection $connection, $table, array $options = []) {
64 $options['return'] = Database::RETURN_AFFECTED;
65 parent::__construct($connection, $options);
66 $this->table = $table;
68 $this->condition = new Condition('AND');
72 * Adds a set of field->value pairs to be updated.
75 * An associative array of fields to write into the database. The array keys
76 * are the field names and the values are the values to which to set them.
78 * @return \Drupal\Core\Database\Query\Update
81 public function fields(array $fields) {
82 $this->fields = $fields;
87 * Specifies fields to be updated as an expression.
89 * Expression fields are cases such as counter=counter+1. This method takes
90 * precedence over fields().
95 * The field will be set to the value of this expression. This parameter
96 * may include named placeholders.
98 * If specified, this is an array of key/value pairs for named placeholders
99 * corresponding to the expression.
101 * @return \Drupal\Core\Database\Query\Update
104 public function expression($field, $expression, array $arguments = NULL) {
105 $this->expressionFields[$field] = [
106 'expression' => $expression,
107 'arguments' => $arguments,
114 * Executes the UPDATE query.
117 * The number of rows matched by the update query. This includes rows that
118 * actually didn't have to be updated because the values didn't change.
120 public function execute() {
121 // Expressions take priority over literal fields, so we process those first
122 // and remove any literal fields that conflict.
123 $fields = $this->fields;
125 foreach ($this->expressionFields as $field => $data) {
126 if (!empty($data['arguments'])) {
127 $update_values += $data['arguments'];
129 if ($data['expression'] instanceof SelectInterface) {
130 $data['expression']->compile($this->connection, $this);
131 $update_values += $data['expression']->arguments();
133 unset($fields[$field]);
136 // Because we filter $fields the same way here and in __toString(), the
137 // placeholders will all match up properly.
138 $max_placeholder = 0;
139 foreach ($fields as $value) {
140 $update_values[':db_update_placeholder_' . ($max_placeholder++)] = $value;
143 if (count($this->condition)) {
144 $this->condition->compile($this->connection, $this);
145 $update_values = array_merge($update_values, $this->condition->arguments());
148 return $this->connection->query((string) $this, $update_values, $this->queryOptions);
152 * Implements PHP magic __toString method to convert the query to a string.
155 * The prepared statement.
157 public function __toString() {
158 // Create a sanitized comment string to prepend to the query.
159 $comments = $this->connection->makeComment($this->comments);
161 // Expressions take priority over literal fields, so we process those first
162 // and remove any literal fields that conflict.
163 $fields = $this->fields;
165 foreach ($this->expressionFields as $field => $data) {
166 if ($data['expression'] instanceof SelectInterface) {
167 // Compile and cast expression subquery to a string.
168 $data['expression']->compile($this->connection, $this);
169 $data['expression'] = ' (' . $data['expression'] . ')';
171 $update_fields[] = $this->connection->escapeField($field) . '=' . $data['expression'];
172 unset($fields[$field]);
175 $max_placeholder = 0;
176 foreach ($fields as $field => $value) {
177 $update_fields[] = $this->connection->escapeField($field) . '=:db_update_placeholder_' . ($max_placeholder++);
180 $query = $comments . 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields);
182 if (count($this->condition)) {
183 $this->condition->compile($this->connection, $this);
184 // There is an implicit string cast on $this->condition.
185 $query .= "\nWHERE " . $this->condition;