Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 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\Command;
  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 function current;
  28  use function is_array;
  29  use function is_bool;
  30  use function is_integer;
  31  use function is_object;
  32  use function is_string;
  33  use function MongoDB\server_supports_feature;
  34  use function trigger_error;
  35  use const E_USER_DEPRECATED;
  36  
  37  /**
  38   * Operation for the create command.
  39   *
  40   * @api
  41   * @see \MongoDB\Database::createCollection()
  42   * @see http://docs.mongodb.org/manual/reference/command/create/
  43   */
  44  class CreateCollection implements Executable
  45  {
  46      const USE_POWER_OF_2_SIZES = 1;
  47      const NO_PADDING = 2;
  48  
  49      /** @var integer */
  50      private static $wireVersionForCollation = 5;
  51  
  52      /** @var integer */
  53      private static $wireVersionForWriteConcern = 5;
  54  
  55      /** @var string */
  56      private $databaseName;
  57  
  58      /** @var string */
  59      private $collectionName;
  60  
  61      /** @var array */
  62      private $options = [];
  63  
  64      /**
  65       * Constructs a create command.
  66       *
  67       * Supported options:
  68       *
  69       *  * autoIndexId (boolean): Specify false to disable the automatic creation
  70       *    of an index on the _id field. For replica sets, this option cannot be
  71       *    false. The default is true.
  72       *
  73       *    This option has been deprecated since MongoDB 3.2. As of MongoDB 4.0,
  74       *    this option cannot be false when creating a replicated collection
  75       *    (i.e. a collection outside of the local database in any mongod mode).
  76       *
  77       *  * capped (boolean): Specify true to create a capped collection. If set,
  78       *    the size option must also be specified. The default is false.
  79       *
  80       *  * collation (document): Collation specification.
  81       *
  82       *    This is not supported for server versions < 3.4 and will result in an
  83       *    exception at execution time if used.
  84       *
  85       *  * flags (integer): Options for the MMAPv1 storage engine only. Must be a
  86       *    bitwise combination CreateCollection::USE_POWER_OF_2_SIZES and
  87       *    CreateCollection::NO_PADDING. The default is
  88       *    CreateCollection::USE_POWER_OF_2_SIZES.
  89       *
  90       *  * indexOptionDefaults (document): Default configuration for indexes when
  91       *    creating the collection.
  92       *
  93       *  * max (integer): The maximum number of documents allowed in the capped
  94       *    collection. The size option takes precedence over this limit.
  95       *
  96       *  * maxTimeMS (integer): The maximum amount of time to allow the query to
  97       *    run.
  98       *
  99       *  * session (MongoDB\Driver\Session): Client session.
 100       *
 101       *    Sessions are not supported for server versions < 3.6.
 102       *
 103       *  * size (integer): The maximum number of bytes for a capped collection.
 104       *
 105       *  * storageEngine (document): Storage engine options.
 106       *
 107       *  * typeMap (array): Type map for BSON deserialization. This will only be
 108       *    used for the returned command result document.
 109       *
 110       *  * validationAction (string): Validation action.
 111       *
 112       *  * validationLevel (string): Validation level.
 113       *
 114       *  * validator (document): Validation rules or expressions.
 115       *
 116       *  * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
 117       *
 118       *    This is not supported for server versions < 3.4 and will result in an
 119       *    exception at execution time if used.
 120       *
 121       * @see http://source.wiredtiger.com/2.4.1/struct_w_t___s_e_s_s_i_o_n.html#a358ca4141d59c345f401c58501276bbb
 122       * @see https://docs.mongodb.org/manual/core/document-validation/
 123       * @param string $databaseName   Database name
 124       * @param string $collectionName Collection name
 125       * @param array  $options        Command options
 126       * @throws InvalidArgumentException for parameter/option parsing errors
 127       */
 128      public function __construct($databaseName, $collectionName, array $options = [])
 129      {
 130          if (isset($options['autoIndexId']) && ! is_bool($options['autoIndexId'])) {
 131              throw InvalidArgumentException::invalidType('"autoIndexId" option', $options['autoIndexId'], 'boolean');
 132          }
 133  
 134          if (isset($options['capped']) && ! is_bool($options['capped'])) {
 135              throw InvalidArgumentException::invalidType('"capped" option', $options['capped'], 'boolean');
 136          }
 137  
 138          if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) {
 139              throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object');
 140          }
 141  
 142          if (isset($options['flags']) && ! is_integer($options['flags'])) {
 143              throw InvalidArgumentException::invalidType('"flags" option', $options['flags'], 'integer');
 144          }
 145  
 146          if (isset($options['indexOptionDefaults']) && ! is_array($options['indexOptionDefaults']) && ! is_object($options['indexOptionDefaults'])) {
 147              throw InvalidArgumentException::invalidType('"indexOptionDefaults" option', $options['indexOptionDefaults'], 'array or object');
 148          }
 149  
 150          if (isset($options['max']) && ! is_integer($options['max'])) {
 151              throw InvalidArgumentException::invalidType('"max" option', $options['max'], 'integer');
 152          }
 153  
 154          if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
 155              throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
 156          }
 157  
 158          if (isset($options['session']) && ! $options['session'] instanceof Session) {
 159              throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
 160          }
 161  
 162          if (isset($options['size']) && ! is_integer($options['size'])) {
 163              throw InvalidArgumentException::invalidType('"size" option', $options['size'], 'integer');
 164          }
 165  
 166          if (isset($options['storageEngine']) && ! is_array($options['storageEngine']) && ! is_object($options['storageEngine'])) {
 167              throw InvalidArgumentException::invalidType('"storageEngine" option', $options['storageEngine'], 'array or object');
 168          }
 169  
 170          if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
 171              throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
 172          }
 173  
 174          if (isset($options['validationAction']) && ! is_string($options['validationAction'])) {
 175              throw InvalidArgumentException::invalidType('"validationAction" option', $options['validationAction'], 'string');
 176          }
 177  
 178          if (isset($options['validationLevel']) && ! is_string($options['validationLevel'])) {
 179              throw InvalidArgumentException::invalidType('"validationLevel" option', $options['validationLevel'], 'string');
 180          }
 181  
 182          if (isset($options['validator']) && ! is_array($options['validator']) && ! is_object($options['validator'])) {
 183              throw InvalidArgumentException::invalidType('"validator" option', $options['validator'], 'array or object');
 184          }
 185  
 186          if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
 187              throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
 188          }
 189  
 190          if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
 191              unset($options['writeConcern']);
 192          }
 193  
 194          if (isset($options['autoIndexId'])) {
 195              trigger_error('The "autoIndexId" option is deprecated and will be removed in a future release', E_USER_DEPRECATED);
 196          }
 197  
 198          $this->databaseName = (string) $databaseName;
 199          $this->collectionName = (string) $collectionName;
 200          $this->options = $options;
 201      }
 202  
 203      /**
 204       * Execute the operation.
 205       *
 206       * @see Executable::execute()
 207       * @param Server $server
 208       * @return array|object Command result document
 209       * @throws UnsupportedException if collation or write concern is used and unsupported
 210       * @throws DriverRuntimeException for other driver errors (e.g. connection errors)
 211       */
 212      public function execute(Server $server)
 213      {
 214          if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) {
 215              throw UnsupportedException::collationNotSupported();
 216          }
 217  
 218          if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
 219              throw UnsupportedException::writeConcernNotSupported();
 220          }
 221  
 222          $cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions());
 223  
 224          if (isset($this->options['typeMap'])) {
 225              $cursor->setTypeMap($this->options['typeMap']);
 226          }
 227  
 228          return current($cursor->toArray());
 229      }
 230  
 231      /**
 232       * Create the create command.
 233       *
 234       * @return Command
 235       */
 236      private function createCommand()
 237      {
 238          $cmd = ['create' => $this->collectionName];
 239  
 240          foreach (['autoIndexId', 'capped', 'flags', 'max', 'maxTimeMS', 'size', 'validationAction', 'validationLevel'] as $option) {
 241              if (isset($this->options[$option])) {
 242                  $cmd[$option] = $this->options[$option];
 243              }
 244          }
 245  
 246          foreach (['collation', 'indexOptionDefaults', 'storageEngine', 'validator'] as $option) {
 247              if (isset($this->options[$option])) {
 248                  $cmd[$option] = (object) $this->options[$option];
 249              }
 250          }
 251  
 252          return new Command($cmd);
 253      }
 254  
 255      /**
 256       * Create options for executing the command.
 257       *
 258       * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
 259       * @return array
 260       */
 261      private function createOptions()
 262      {
 263          $options = [];
 264  
 265          if (isset($this->options['session'])) {
 266              $options['session'] = $this->options['session'];
 267          }
 268  
 269          if (isset($this->options['writeConcern'])) {
 270              $options['writeConcern'] = $this->options['writeConcern'];
 271          }
 272  
 273          return $options;
 274      }
 275  }