Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401]
1 <?php 2 /* 3 * Copyright 2015-2017 MongoDB, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 namespace MongoDB\Operation; 19 20 use MongoDB\Driver\BulkWrite as Bulk; 21 use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; 22 use MongoDB\Driver\Server; 23 use MongoDB\Driver\Session; 24 use MongoDB\Driver\WriteConcern; 25 use MongoDB\Exception\InvalidArgumentException; 26 use MongoDB\Exception\UnsupportedException; 27 use MongoDB\UpdateResult; 28 use function is_array; 29 use function is_bool; 30 use function is_object; 31 use function MongoDB\is_first_key_operator; 32 use function MongoDB\is_pipeline; 33 use function MongoDB\server_supports_feature; 34 35 /** 36 * Operation for the update command. 37 * 38 * This class is used internally by the ReplaceOne, UpdateMany, and UpdateOne 39 * operation classes. 40 * 41 * @internal 42 * @see http://docs.mongodb.org/manual/reference/command/update/ 43 */ 44 class Update implements Executable, Explainable 45 { 46 /** @var integer */ 47 private static $wireVersionForArrayFilters = 6; 48 49 /** @var integer */ 50 private static $wireVersionForCollation = 5; 51 52 /** @var integer */ 53 private static $wireVersionForDocumentLevelValidation = 4; 54 55 /** @var string */ 56 private $databaseName; 57 58 /** @var string */ 59 private $collectionName; 60 61 /** @var array|object */ 62 private $filter; 63 64 /** @var array|object */ 65 private $update; 66 67 /** @var array */ 68 private $options; 69 70 /** 71 * Constructs a update command. 72 * 73 * Supported options: 74 * 75 * * arrayFilters (document array): A set of filters specifying to which 76 * array elements an update should apply. 77 * 78 * This is not supported for server versions < 3.6 and will result in an 79 * exception at execution time if used. 80 * 81 * * bypassDocumentValidation (boolean): If true, allows the write to 82 * circumvent document level validation. 83 * 84 * For servers < 3.2, this option is ignored as document level validation 85 * is not available. 86 * 87 * * collation (document): Collation specification. 88 * 89 * This is not supported for server versions < 3.4 and will result in an 90 * exception at execution time if used. 91 * 92 * * multi (boolean): When true, updates all documents matching the query. 93 * This option cannot be true if the $update argument is a replacement 94 * document (i.e. contains no update operators). The default is false. 95 * 96 * * session (MongoDB\Driver\Session): Client session. 97 * 98 * Sessions are not supported for server versions < 3.6. 99 * 100 * * upsert (boolean): When true, a new document is created if no document 101 * matches the query. The default is false. 102 * 103 * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. 104 * 105 * @param string $databaseName Database name 106 * @param string $collectionName Collection name 107 * @param array|object $filter Query by which to delete documents 108 * @param array|object $update Update to apply to the matched 109 * document(s) or a replacement document 110 * @param array $options Command options 111 * @throws InvalidArgumentException for parameter/option parsing errors 112 */ 113 public function __construct($databaseName, $collectionName, $filter, $update, array $options = []) 114 { 115 if (! is_array($filter) && ! is_object($filter)) { 116 throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); 117 } 118 119 if (! is_array($update) && ! is_object($update)) { 120 throw InvalidArgumentException::invalidType('$update', $filter, 'array or object'); 121 } 122 123 $options += [ 124 'multi' => false, 125 'upsert' => false, 126 ]; 127 128 if (isset($options['arrayFilters']) && ! is_array($options['arrayFilters'])) { 129 throw InvalidArgumentException::invalidType('"arrayFilters" option', $options['arrayFilters'], 'array'); 130 } 131 132 if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) { 133 throw InvalidArgumentException::invalidType('"bypassDocumentValidation" option', $options['bypassDocumentValidation'], 'boolean'); 134 } 135 136 if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { 137 throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); 138 } 139 140 if (! is_bool($options['multi'])) { 141 throw InvalidArgumentException::invalidType('"multi" option', $options['multi'], 'boolean'); 142 } 143 144 if ($options['multi'] && ! is_first_key_operator($update) && ! is_pipeline($update)) { 145 throw new InvalidArgumentException('"multi" option cannot be true if $update is a replacement document'); 146 } 147 148 if (isset($options['session']) && ! $options['session'] instanceof Session) { 149 throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); 150 } 151 152 if (! is_bool($options['upsert'])) { 153 throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean'); 154 } 155 156 if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { 157 throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); 158 } 159 160 if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { 161 unset($options['writeConcern']); 162 } 163 164 $this->databaseName = (string) $databaseName; 165 $this->collectionName = (string) $collectionName; 166 $this->filter = $filter; 167 $this->update = $update; 168 $this->options = $options; 169 } 170 171 /** 172 * Execute the operation. 173 * 174 * @see Executable::execute() 175 * @param Server $server 176 * @return UpdateResult 177 * @throws UnsupportedException if array filters or collation is used and unsupported 178 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 179 */ 180 public function execute(Server $server) 181 { 182 if (isset($this->options['arrayFilters']) && ! server_supports_feature($server, self::$wireVersionForArrayFilters)) { 183 throw UnsupportedException::arrayFiltersNotSupported(); 184 } 185 186 if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { 187 throw UnsupportedException::collationNotSupported(); 188 } 189 190 $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); 191 if ($inTransaction && isset($this->options['writeConcern'])) { 192 throw UnsupportedException::writeConcernNotSupportedInTransaction(); 193 } 194 195 $bulkOptions = []; 196 197 if (! empty($this->options['bypassDocumentValidation']) && 198 server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) 199 ) { 200 $bulkOptions['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; 201 } 202 203 $bulk = new Bulk($bulkOptions); 204 $bulk->update($this->filter, $this->update, $this->createUpdateOptions()); 205 206 $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createExecuteOptions()); 207 208 return new UpdateResult($writeResult); 209 } 210 211 public function getCommandDocument(Server $server) 212 { 213 $cmd = ['update' => $this->collectionName, 'updates' => [['q' => $this->filter, 'u' => $this->update] + $this->createUpdateOptions()]]; 214 215 if (isset($this->options['writeConcern'])) { 216 $cmd['writeConcern'] = $this->options['writeConcern']; 217 } 218 219 if (! empty($this->options['bypassDocumentValidation']) && 220 server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) 221 ) { 222 $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; 223 } 224 225 return $cmd; 226 } 227 228 /** 229 * Create options for executing the bulk write. 230 * 231 * @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php 232 * @return array 233 */ 234 private function createExecuteOptions() 235 { 236 $options = []; 237 238 if (isset($this->options['session'])) { 239 $options['session'] = $this->options['session']; 240 } 241 242 if (isset($this->options['writeConcern'])) { 243 $options['writeConcern'] = $this->options['writeConcern']; 244 } 245 246 return $options; 247 } 248 249 /** 250 * Create options for the update command. 251 * 252 * Note that these options are different from the bulk write options, which 253 * are created in createExecuteOptions(). 254 * 255 * @return array 256 */ 257 private function createUpdateOptions() 258 { 259 $updateOptions = [ 260 'multi' => $this->options['multi'], 261 'upsert' => $this->options['upsert'], 262 ]; 263 264 if (isset($this->options['arrayFilters'])) { 265 $updateOptions['arrayFilters'] = $this->options['arrayFilters']; 266 } 267 268 if (isset($this->options['collation'])) { 269 $updateOptions['collation'] = (object) $this->options['collation']; 270 } 271 272 return $updateOptions; 273 } 274 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body