See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 /* 3 * Copyright 2015-present 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 * https://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; 19 20 use Iterator; 21 use MongoDB\Driver\Cursor; 22 use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; 23 use MongoDB\Driver\Manager; 24 use MongoDB\Driver\ReadConcern; 25 use MongoDB\Driver\ReadPreference; 26 use MongoDB\Driver\WriteConcern; 27 use MongoDB\Exception\InvalidArgumentException; 28 use MongoDB\Exception\UnexpectedValueException; 29 use MongoDB\Exception\UnsupportedException; 30 use MongoDB\GridFS\Bucket; 31 use MongoDB\Model\BSONArray; 32 use MongoDB\Model\BSONDocument; 33 use MongoDB\Model\CollectionInfoIterator; 34 use MongoDB\Operation\Aggregate; 35 use MongoDB\Operation\CreateCollection; 36 use MongoDB\Operation\CreateIndexes; 37 use MongoDB\Operation\DatabaseCommand; 38 use MongoDB\Operation\DropCollection; 39 use MongoDB\Operation\DropDatabase; 40 use MongoDB\Operation\ListCollectionNames; 41 use MongoDB\Operation\ListCollections; 42 use MongoDB\Operation\ModifyCollection; 43 use MongoDB\Operation\RenameCollection; 44 use MongoDB\Operation\Watch; 45 use Traversable; 46 47 use function is_array; 48 use function strlen; 49 50 class Database 51 { 52 /** @var array */ 53 private static $defaultTypeMap = [ 54 'array' => BSONArray::class, 55 'document' => BSONDocument::class, 56 'root' => BSONDocument::class, 57 ]; 58 59 /** @var integer */ 60 private static $wireVersionForReadConcernWithWriteStage = 8; 61 62 /** @var string */ 63 private $databaseName; 64 65 /** @var Manager */ 66 private $manager; 67 68 /** @var ReadConcern */ 69 private $readConcern; 70 71 /** @var ReadPreference */ 72 private $readPreference; 73 74 /** @var array */ 75 private $typeMap; 76 77 /** @var WriteConcern */ 78 private $writeConcern; 79 80 /** 81 * Constructs new Database instance. 82 * 83 * This class provides methods for database-specific operations and serves 84 * as a gateway for accessing collections. 85 * 86 * Supported options: 87 * 88 * * readConcern (MongoDB\Driver\ReadConcern): The default read concern to 89 * use for database operations and selected collections. Defaults to the 90 * Manager's read concern. 91 * 92 * * readPreference (MongoDB\Driver\ReadPreference): The default read 93 * preference to use for database operations and selected collections. 94 * Defaults to the Manager's read preference. 95 * 96 * * typeMap (array): Default type map for cursors and BSON documents. 97 * 98 * * writeConcern (MongoDB\Driver\WriteConcern): The default write concern 99 * to use for database operations and selected collections. Defaults to 100 * the Manager's write concern. 101 * 102 * @param Manager $manager Manager instance from the driver 103 * @param string $databaseName Database name 104 * @param array $options Database options 105 * @throws InvalidArgumentException for parameter/option parsing errors 106 */ 107 public function __construct(Manager $manager, string $databaseName, array $options = []) 108 { 109 if (strlen($databaseName) < 1) { 110 throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName); 111 } 112 113 if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { 114 throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class); 115 } 116 117 if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { 118 throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class); 119 } 120 121 if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { 122 throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); 123 } 124 125 if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { 126 throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); 127 } 128 129 $this->manager = $manager; 130 $this->databaseName = $databaseName; 131 $this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern(); 132 $this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference(); 133 $this->typeMap = $options['typeMap'] ?? self::$defaultTypeMap; 134 $this->writeConcern = $options['writeConcern'] ?? $this->manager->getWriteConcern(); 135 } 136 137 /** 138 * Return internal properties for debugging purposes. 139 * 140 * @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo 141 * @return array 142 */ 143 public function __debugInfo() 144 { 145 return [ 146 'databaseName' => $this->databaseName, 147 'manager' => $this->manager, 148 'readConcern' => $this->readConcern, 149 'readPreference' => $this->readPreference, 150 'typeMap' => $this->typeMap, 151 'writeConcern' => $this->writeConcern, 152 ]; 153 } 154 155 /** 156 * Select a collection within this database. 157 * 158 * Note: collections whose names contain special characters (e.g. ".") may 159 * be selected with complex syntax (e.g. $database->{"system.profile"}) or 160 * {@link selectCollection()}. 161 * 162 * @see https://php.net/oop5.overloading#object.get 163 * @see https://php.net/types.string#language.types.string.parsing.complex 164 * @param string $collectionName Name of the collection to select 165 * @return Collection 166 */ 167 public function __get(string $collectionName) 168 { 169 return $this->selectCollection($collectionName); 170 } 171 172 /** 173 * Return the database name. 174 * 175 * @return string 176 */ 177 public function __toString() 178 { 179 return $this->databaseName; 180 } 181 182 /** 183 * Runs an aggregation framework pipeline on the database for pipeline 184 * stages that do not require an underlying collection, such as $currentOp 185 * and $listLocalSessions. Requires MongoDB >= 3.6 186 * 187 * @see Aggregate::__construct() for supported options 188 * @param array $pipeline List of pipeline operations 189 * @param array $options Command options 190 * @return Traversable 191 * @throws UnexpectedValueException if the command response was malformed 192 * @throws UnsupportedException if options are not supported by the selected server 193 * @throws InvalidArgumentException for parameter/option parsing errors 194 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 195 */ 196 public function aggregate(array $pipeline, array $options = []) 197 { 198 $hasWriteStage = is_last_pipeline_operator_write($pipeline); 199 200 if (! isset($options['readPreference']) && ! is_in_transaction($options)) { 201 $options['readPreference'] = $this->readPreference; 202 } 203 204 $server = $hasWriteStage 205 ? select_server_for_aggregate_write_stage($this->manager, $options) 206 : select_server($this->manager, $options); 207 208 /* MongoDB 4.2 and later supports a read concern when an $out stage is 209 * being used, but earlier versions do not. 210 * 211 * A read concern is also not compatible with transactions. 212 */ 213 if ( 214 ! isset($options['readConcern']) && 215 ! is_in_transaction($options) && 216 ( ! $hasWriteStage || server_supports_feature($server, self::$wireVersionForReadConcernWithWriteStage)) 217 ) { 218 $options['readConcern'] = $this->readConcern; 219 } 220 221 if (! isset($options['typeMap'])) { 222 $options['typeMap'] = $this->typeMap; 223 } 224 225 if ($hasWriteStage && ! isset($options['writeConcern']) && ! is_in_transaction($options)) { 226 $options['writeConcern'] = $this->writeConcern; 227 } 228 229 $operation = new Aggregate($this->databaseName, null, $pipeline, $options); 230 231 return $operation->execute($server); 232 } 233 234 /** 235 * Execute a command on this database. 236 * 237 * @see DatabaseCommand::__construct() for supported options 238 * @param array|object $command Command document 239 * @param array $options Options for command execution 240 * @return Cursor 241 * @throws InvalidArgumentException for parameter/option parsing errors 242 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 243 */ 244 public function command($command, array $options = []) 245 { 246 if (! isset($options['typeMap'])) { 247 $options['typeMap'] = $this->typeMap; 248 } 249 250 $operation = new DatabaseCommand($this->databaseName, $command, $options); 251 $server = select_server($this->manager, $options); 252 253 return $operation->execute($server); 254 } 255 256 /** 257 * Create a new collection explicitly. 258 * 259 * @see CreateCollection::__construct() for supported options 260 * @return array|object Command result document 261 * @throws UnsupportedException if options are not supported by the selected server 262 * @throws InvalidArgumentException for parameter/option parsing errors 263 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 264 */ 265 public function createCollection(string $collectionName, array $options = []) 266 { 267 if (! isset($options['typeMap'])) { 268 $options['typeMap'] = $this->typeMap; 269 } 270 271 $server = select_server($this->manager, $options); 272 273 if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { 274 $options['writeConcern'] = $this->writeConcern; 275 } 276 277 $encryptedFields = $options['encryptedFields'] 278 ?? get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager) 279 ?? null; 280 281 if ($encryptedFields !== null) { 282 // encryptedFields is passed to the create command 283 $options['encryptedFields'] = $encryptedFields; 284 285 $encryptedFields = (array) $encryptedFields; 286 $enxcolOptions = ['clusteredIndex' => ['key' => ['_id' => 1], 'unique' => true]]; 287 (new CreateCollection($this->databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc', $enxcolOptions))->execute($server); 288 (new CreateCollection($this->databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc', $enxcolOptions))->execute($server); 289 (new CreateCollection($this->databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc', $enxcolOptions))->execute($server); 290 } 291 292 $operation = new CreateCollection($this->databaseName, $collectionName, $options); 293 294 $result = $operation->execute($server); 295 296 if ($encryptedFields !== null) { 297 (new CreateIndexes($this->databaseName, $collectionName, [['key' => ['__safeContent__' => 1]]]))->execute($server); 298 } 299 300 return $result; 301 } 302 303 /** 304 * Drop this database. 305 * 306 * @see DropDatabase::__construct() for supported options 307 * @param array $options Additional options 308 * @return array|object Command result document 309 * @throws UnsupportedException if options are unsupported on the selected server 310 * @throws InvalidArgumentException for parameter/option parsing errors 311 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 312 */ 313 public function drop(array $options = []) 314 { 315 if (! isset($options['typeMap'])) { 316 $options['typeMap'] = $this->typeMap; 317 } 318 319 $server = select_server($this->manager, $options); 320 321 if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { 322 $options['writeConcern'] = $this->writeConcern; 323 } 324 325 $operation = new DropDatabase($this->databaseName, $options); 326 327 return $operation->execute($server); 328 } 329 330 /** 331 * Drop a collection within this database. 332 * 333 * @see DropCollection::__construct() for supported options 334 * @param string $collectionName Collection name 335 * @param array $options Additional options 336 * @return array|object Command result document 337 * @throws UnsupportedException if options are unsupported on the selected server 338 * @throws InvalidArgumentException for parameter/option parsing errors 339 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 340 */ 341 public function dropCollection(string $collectionName, array $options = []) 342 { 343 if (! isset($options['typeMap'])) { 344 $options['typeMap'] = $this->typeMap; 345 } 346 347 $server = select_server($this->manager, $options); 348 349 if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { 350 $options['writeConcern'] = $this->writeConcern; 351 } 352 353 $encryptedFields = $options['encryptedFields'] 354 ?? get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager) 355 ?? get_encrypted_fields_from_server($this->databaseName, $collectionName, $this->manager, $server) 356 ?? null; 357 358 if ($encryptedFields !== null) { 359 // encryptedFields is not passed to the drop command 360 unset($options['encryptedFields']); 361 362 $encryptedFields = (array) $encryptedFields; 363 (new DropCollection($this->databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc'))->execute($server); 364 (new DropCollection($this->databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc'))->execute($server); 365 (new DropCollection($this->databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc'))->execute($server); 366 } 367 368 $operation = new DropCollection($this->databaseName, $collectionName, $options); 369 370 return $operation->execute($server); 371 } 372 373 /** 374 * Returns the database name. 375 * 376 * @return string 377 */ 378 public function getDatabaseName() 379 { 380 return $this->databaseName; 381 } 382 383 /** 384 * Return the Manager. 385 * 386 * @return Manager 387 */ 388 public function getManager() 389 { 390 return $this->manager; 391 } 392 393 /** 394 * Return the read concern for this database. 395 * 396 * @see https://php.net/manual/en/mongodb-driver-readconcern.isdefault.php 397 * @return ReadConcern 398 */ 399 public function getReadConcern() 400 { 401 return $this->readConcern; 402 } 403 404 /** 405 * Return the read preference for this database. 406 * 407 * @return ReadPreference 408 */ 409 public function getReadPreference() 410 { 411 return $this->readPreference; 412 } 413 414 /** 415 * Return the type map for this database. 416 * 417 * @return array 418 */ 419 public function getTypeMap() 420 { 421 return $this->typeMap; 422 } 423 424 /** 425 * Return the write concern for this database. 426 * 427 * @see https://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php 428 * @return WriteConcern 429 */ 430 public function getWriteConcern() 431 { 432 return $this->writeConcern; 433 } 434 435 /** 436 * Returns the names of all collections in this database 437 * 438 * @see ListCollectionNames::__construct() for supported options 439 * @throws InvalidArgumentException for parameter/option parsing errors 440 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 441 */ 442 public function listCollectionNames(array $options = []): Iterator 443 { 444 $operation = new ListCollectionNames($this->databaseName, $options); 445 $server = select_server($this->manager, $options); 446 447 return $operation->execute($server); 448 } 449 450 /** 451 * Returns information for all collections in this database. 452 * 453 * @see ListCollections::__construct() for supported options 454 * @return CollectionInfoIterator 455 * @throws InvalidArgumentException for parameter/option parsing errors 456 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 457 */ 458 public function listCollections(array $options = []) 459 { 460 $operation = new ListCollections($this->databaseName, $options); 461 $server = select_server($this->manager, $options); 462 463 return $operation->execute($server); 464 } 465 466 /** 467 * Modifies a collection or view. 468 * 469 * @see ModifyCollection::__construct() for supported options 470 * @param string $collectionName Collection or view to modify 471 * @param array $collectionOptions Collection or view options to assign 472 * @param array $options Command options 473 * @return array|object 474 * @throws InvalidArgumentException for parameter/option parsing errors 475 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 476 */ 477 public function modifyCollection(string $collectionName, array $collectionOptions, array $options = []) 478 { 479 if (! isset($options['typeMap'])) { 480 $options['typeMap'] = $this->typeMap; 481 } 482 483 $server = select_server($this->manager, $options); 484 485 if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { 486 $options['writeConcern'] = $this->writeConcern; 487 } 488 489 $operation = new ModifyCollection($this->databaseName, $collectionName, $collectionOptions, $options); 490 491 return $operation->execute($server); 492 } 493 494 /** 495 * Rename a collection within this database. 496 * 497 * @see RenameCollection::__construct() for supported options 498 * @param string $fromCollectionName Collection name 499 * @param string $toCollectionName New name of the collection 500 * @param string|null $toDatabaseName New database name of the collection. Defaults to the original database. 501 * @param array $options Additional options 502 * @return array|object Command result document 503 * @throws UnsupportedException if options are unsupported on the selected server 504 * @throws InvalidArgumentException for parameter/option parsing errors 505 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 506 */ 507 public function renameCollection(string $fromCollectionName, string $toCollectionName, ?string $toDatabaseName = null, array $options = []) 508 { 509 if (! isset($toDatabaseName)) { 510 $toDatabaseName = $this->databaseName; 511 } 512 513 if (! isset($options['typeMap'])) { 514 $options['typeMap'] = $this->typeMap; 515 } 516 517 $server = select_server($this->manager, $options); 518 519 if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { 520 $options['writeConcern'] = $this->writeConcern; 521 } 522 523 $operation = new RenameCollection($this->databaseName, $fromCollectionName, $toDatabaseName, $toCollectionName, $options); 524 525 return $operation->execute($server); 526 } 527 528 /** 529 * Select a collection within this database. 530 * 531 * @see Collection::__construct() for supported options 532 * @param string $collectionName Name of the collection to select 533 * @param array $options Collection constructor options 534 * @return Collection 535 * @throws InvalidArgumentException for parameter/option parsing errors 536 */ 537 public function selectCollection(string $collectionName, array $options = []) 538 { 539 $options += [ 540 'readConcern' => $this->readConcern, 541 'readPreference' => $this->readPreference, 542 'typeMap' => $this->typeMap, 543 'writeConcern' => $this->writeConcern, 544 ]; 545 546 return new Collection($this->manager, $this->databaseName, $collectionName, $options); 547 } 548 549 /** 550 * Select a GridFS bucket within this database. 551 * 552 * @see Bucket::__construct() for supported options 553 * @param array $options Bucket constructor options 554 * @return Bucket 555 * @throws InvalidArgumentException for parameter/option parsing errors 556 */ 557 public function selectGridFSBucket(array $options = []) 558 { 559 $options += [ 560 'readConcern' => $this->readConcern, 561 'readPreference' => $this->readPreference, 562 'typeMap' => $this->typeMap, 563 'writeConcern' => $this->writeConcern, 564 ]; 565 566 return new Bucket($this->manager, $this->databaseName, $options); 567 } 568 569 /** 570 * Create a change stream for watching changes to the database. 571 * 572 * @see Watch::__construct() for supported options 573 * @param array $pipeline List of pipeline operations 574 * @param array $options Command options 575 * @return ChangeStream 576 * @throws InvalidArgumentException for parameter/option parsing errors 577 */ 578 public function watch(array $pipeline = [], array $options = []) 579 { 580 if (! isset($options['readPreference']) && ! is_in_transaction($options)) { 581 $options['readPreference'] = $this->readPreference; 582 } 583 584 $server = select_server($this->manager, $options); 585 586 if (! isset($options['readConcern']) && ! is_in_transaction($options)) { 587 $options['readConcern'] = $this->readConcern; 588 } 589 590 if (! isset($options['typeMap'])) { 591 $options['typeMap'] = $this->typeMap; 592 } 593 594 $operation = new Watch($this->manager, $this->databaseName, null, $pipeline, $options); 595 596 return $operation->execute($server); 597 } 598 599 /** 600 * Get a clone of this database with different options. 601 * 602 * @see Database::__construct() for supported options 603 * @param array $options Database constructor options 604 * @return Database 605 * @throws InvalidArgumentException for parameter/option parsing errors 606 */ 607 public function withOptions(array $options = []) 608 { 609 $options += [ 610 'readConcern' => $this->readConcern, 611 'readPreference' => $this->readPreference, 612 'typeMap' => $this->typeMap, 613 'writeConcern' => $this->writeConcern, 614 ]; 615 616 return new Database($this->manager, $this->databaseName, $options); 617 } 618 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body