Upgraded drupal core with security updates
[yaffs-website] / web / core / lib / Drupal / Core / Database / Query / Update.php
1 <?php
2
3 namespace Drupal\Core\Database\Query;
4
5 use Drupal\Core\Database\Database;
6 use Drupal\Core\Database\Connection;
7
8 /**
9  * General class for an abstracted UPDATE operation.
10  *
11  * @ingroup database
12  */
13 class Update extends Query implements ConditionInterface {
14
15   use QueryConditionTrait;
16
17   /**
18    * The table to update.
19    *
20    * @var string
21    */
22   protected $table;
23
24   /**
25    * An array of fields that will be updated.
26    *
27    * @var array
28    */
29   protected $fields = [];
30
31   /**
32    * An array of values to update to.
33    *
34    * @var array
35    */
36   protected $arguments = [];
37
38   /**
39    * Array of fields to update to an expression in case of a duplicate record.
40    *
41    * This variable is a nested array in the following format:
42    * @code
43    * <some field> => array(
44    *  'condition' => <condition to execute, as a string>,
45    *  'arguments' => <array of arguments for condition, or NULL for none>,
46    * );
47    * @endcode
48    *
49    * @var array
50    */
51   protected $expressionFields = [];
52
53   /**
54    * Constructs an Update query object.
55    *
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.
62    */
63   public function __construct(Connection $connection, $table, array $options = []) {
64     $options['return'] = Database::RETURN_AFFECTED;
65     parent::__construct($connection, $options);
66     $this->table = $table;
67
68     $this->condition = new Condition('AND');
69   }
70
71   /**
72    * Adds a set of field->value pairs to be updated.
73    *
74    * @param $fields
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.
77    *
78    * @return \Drupal\Core\Database\Query\Update
79    *   The called object.
80    */
81   public function fields(array $fields) {
82     $this->fields = $fields;
83     return $this;
84   }
85
86   /**
87    * Specifies fields to be updated as an expression.
88    *
89    * Expression fields are cases such as counter=counter+1. This method takes
90    * precedence over fields().
91    *
92    * @param $field
93    *   The field to set.
94    * @param $expression
95    *   The field will be set to the value of this expression. This parameter
96    *   may include named placeholders.
97    * @param $arguments
98    *   If specified, this is an array of key/value pairs for named placeholders
99    *   corresponding to the expression.
100    *
101    * @return \Drupal\Core\Database\Query\Update
102    *   The called object.
103    */
104   public function expression($field, $expression, array $arguments = NULL) {
105     $this->expressionFields[$field] = [
106       'expression' => $expression,
107       'arguments' => $arguments,
108     ];
109
110     return $this;
111   }
112
113   /**
114    * Executes the UPDATE query.
115    *
116    * @return
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.
119    */
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;
124     $update_values = [];
125     foreach ($this->expressionFields as $field => $data) {
126       if (!empty($data['arguments'])) {
127         $update_values += $data['arguments'];
128       }
129       if ($data['expression'] instanceof SelectInterface) {
130         $data['expression']->compile($this->connection, $this);
131         $update_values += $data['expression']->arguments();
132       }
133       unset($fields[$field]);
134     }
135
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;
141     }
142
143     if (count($this->condition)) {
144       $this->condition->compile($this->connection, $this);
145       $update_values = array_merge($update_values, $this->condition->arguments());
146     }
147
148     return $this->connection->query((string) $this, $update_values, $this->queryOptions);
149   }
150
151   /**
152    * Implements PHP magic __toString method to convert the query to a string.
153    *
154    * @return string
155    *   The prepared statement.
156    */
157   public function __toString() {
158     // Create a sanitized comment string to prepend to the query.
159     $comments = $this->connection->makeComment($this->comments);
160
161     // Expressions take priority over literal fields, so we process those first
162     // and remove any literal fields that conflict.
163     $fields = $this->fields;
164     $update_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'] . ')';
170       }
171       $update_fields[] = $this->connection->escapeField($field) . '=' . $data['expression'];
172       unset($fields[$field]);
173     }
174
175     $max_placeholder = 0;
176     foreach ($fields as $field => $value) {
177       $update_fields[] = $this->connection->escapeField($field) . '=:db_update_placeholder_' . ($max_placeholder++);
178     }
179
180     $query = $comments . 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields);
181
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;
186     }
187
188     return $query;
189   }
190
191 }