Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 310 and 400] [Versions 39 and 400] [Versions 400 and 401]

   1  <?php
   2  /*
   3   * Copyright 2018 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\ReadPreference;
  22  use MongoDB\Driver\Server;
  23  use MongoDB\Driver\Session;
  24  use MongoDB\Exception\InvalidArgumentException;
  25  use MongoDB\Exception\UnsupportedException;
  26  use function current;
  27  use function is_array;
  28  use function is_string;
  29  use function MongoDB\server_supports_feature;
  30  
  31  /**
  32   * Operation for the explain command.
  33   *
  34   * @api
  35   * @see \MongoDB\Collection::explain()
  36   * @see http://docs.mongodb.org/manual/reference/command/explain/
  37   */
  38  class Explain implements Executable
  39  {
  40      const VERBOSITY_ALL_PLANS = 'allPlansExecution';
  41      const VERBOSITY_EXEC_STATS = 'executionStats';
  42      const VERBOSITY_QUERY = 'queryPlanner';
  43  
  44      /** @var integer */
  45      private static $wireVersionForAggregate = 7;
  46  
  47      /** @var integer */
  48      private static $wireVersionForDistinct = 4;
  49  
  50      /** @var integer */
  51      private static $wireVersionForFindAndModify = 4;
  52  
  53      /** @var string */
  54      private $databaseName;
  55  
  56      /** @var Explainable */
  57      private $explainable;
  58  
  59      /** @var array */
  60      private $options;
  61  
  62      /**
  63       * Constructs an explain command for explainable operations.
  64       *
  65       * Supported options:
  66       *
  67       *  * readPreference (MongoDB\Driver\ReadPreference): Read preference.
  68       *
  69       *  * session (MongoDB\Driver\Session): Client session.
  70       *
  71       *  * typeMap (array): Type map for BSON deserialization. This will be used
  72       *    used for the returned command result document.
  73       *
  74       *  * verbosity (string): The mode in which the explain command will be run.
  75       *
  76       * @param string      $databaseName Database name
  77       * @param Explainable $explainable  Operation to explain
  78       * @param array       $options      Command options
  79       * @throws InvalidArgumentException for parameter/option parsing errors
  80       */
  81      public function __construct($databaseName, Explainable $explainable, array $options = [])
  82      {
  83          if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
  84              throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class);
  85          }
  86  
  87          if (isset($options['session']) && ! $options['session'] instanceof Session) {
  88              throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
  89          }
  90  
  91          if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
  92              throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
  93          }
  94  
  95          if (isset($options['verbosity']) && ! is_string($options['verbosity'])) {
  96              throw InvalidArgumentException::invalidType('"verbosity" option', $options['verbosity'], 'string');
  97          }
  98  
  99          $this->databaseName = $databaseName;
 100          $this->explainable = $explainable;
 101          $this->options = $options;
 102      }
 103  
 104      public function execute(Server $server)
 105      {
 106          if ($this->explainable instanceof Distinct && ! server_supports_feature($server, self::$wireVersionForDistinct)) {
 107              throw UnsupportedException::explainNotSupported();
 108          }
 109  
 110          if ($this->isFindAndModify($this->explainable) && ! server_supports_feature($server, self::$wireVersionForFindAndModify)) {
 111              throw UnsupportedException::explainNotSupported();
 112          }
 113  
 114          if ($this->explainable instanceof Aggregate && ! server_supports_feature($server, self::$wireVersionForAggregate)) {
 115              throw UnsupportedException::explainNotSupported();
 116          }
 117  
 118          $cmd = ['explain' => $this->explainable->getCommandDocument($server)];
 119  
 120          if (isset($this->options['verbosity'])) {
 121              $cmd['verbosity'] = $this->options['verbosity'];
 122          }
 123  
 124          $cursor = $server->executeCommand($this->databaseName, new Command($cmd), $this->createOptions());
 125  
 126          if (isset($this->options['typeMap'])) {
 127              $cursor->setTypeMap($this->options['typeMap']);
 128          }
 129  
 130          return current($cursor->toArray());
 131      }
 132  
 133      /**
 134       * Create options for executing the command.
 135       *
 136       * @see http://php.net/manual/en/mongodb-driver-server.executecommand.php
 137       * @return array
 138       */
 139      private function createOptions()
 140      {
 141          $options = [];
 142  
 143          if (isset($this->options['readPreference'])) {
 144              $options['readPreference'] = $this->options['readPreference'];
 145          }
 146  
 147          if (isset($this->options['session'])) {
 148              $options['session'] = $this->options['session'];
 149          }
 150  
 151          return $options;
 152      }
 153  
 154      private function isFindAndModify($explainable)
 155      {
 156          if ($explainable instanceof FindAndModify || $explainable instanceof FindOneAndDelete || $explainable instanceof FindOneAndReplace || $explainable instanceof FindOneAndUpdate) {
 157              return true;
 158          }
 159  
 160          return false;
 161      }
 162  }