MDL-54592 cachestore_mongodb: MongoDB cache store use new driver.
authorVíctor Déniz Falcón <victor@moodle.com>
Thu, 14 Mar 2019 11:14:31 +0000 (11:14 +0000)
committerVíctor Déniz Falcón <victor@moodle.com>
Fri, 15 Mar 2019 13:50:51 +0000 (13:50 +0000)
The scope of this change is limited to modifying the MongoDB cache
plugin to use the new version of the driver that accepts PHP 7.x
versions. Following the instructions in the official MongoDB
documentation, https://docs.mongodb.com/php-library/current/, the
MongoDB PHP Library was included and used.

.eslintignore
.stylelintignore
cache/stores/mongodb/MongoDB/readme_moodle.txt [new file with mode: 0644]
cache/stores/mongodb/addinstanceform.php
cache/stores/mongodb/lib.php
cache/stores/mongodb/thirdpartylibs.xml [new file with mode: 0644]
cache/upgrade.txt
lib/classes/component.php

index 420eb21..9153e18 100644 (file)
@@ -6,6 +6,7 @@ vendor/
 admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
 admin/tool/usertours/amd/src/tour.js
 auth/cas/CAS/
+cache/stores/mongodb/MongoDB/
 enrol/lti/ims-blti/
 filter/algebra/AlgParser.pm
 filter/tex/mimetex.*
index be8cec8..55b87b5 100644 (file)
@@ -9,6 +9,7 @@ vendor/
 admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
 admin/tool/usertours/amd/src/tour.js
 auth/cas/CAS/
+cache/stores/mongodb/MongoDB/
 enrol/lti/ims-blti/
 filter/algebra/AlgParser.pm
 filter/tex/mimetex.*
diff --git a/cache/stores/mongodb/MongoDB/readme_moodle.txt b/cache/stores/mongodb/MongoDB/readme_moodle.txt
new file mode 100644 (file)
index 0000000..456d3fd
--- /dev/null
@@ -0,0 +1,14 @@
+MongoDB PHP
+-----------
+
+Downloaded from https://github.com/mongodb/mongo-php-library
+
+Last commit on download: aac8e54009196f6544e50baf9b63dcf0eab3bbdf
+
+This version (1.4) requires PHP mongodb extension >= 1.5
+
+Import procedure:
+
+- Copy all the files and folders from the folder mongodb/src in this directory.
+- Copy the license file from the project root.
+
index c7d3104..95d45b9 100644 (file)
@@ -51,7 +51,7 @@ class cachestore_mongodb_addinstance_form extends cachestore_addinstance_form {
         global $OUTPUT;
         $form = $this->_form;
 
-        if (!class_exists('MongoClient')) {
+        if (!version_compare(phpversion('mongodb'), '1.5', 'ge')) {
             $form->addElement('html', $OUTPUT->notification(get_string('pleaseupgrademongo', 'cachestore_mongodb')));
         }
 
index 0f1d352..302828f 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
+require_once('MongoDB/functions.php');
+
 /**
  * The MongoDB Cache store.
  *
- * This cache store uses the MongoDB Native Driver.
+ * This cache store uses the MongoDB Native Driver and the MongoDB PHP Library.
  * For installation instructions have a look at the following two links:
- *  - {@link http://www.php.net/manual/en/mongo.installation.php}
- *  - {@link http://www.mongodb.org/display/DOCS/PHP+Language+Center}
+ *  - {@link http://php.net/manual/en/set.mongodb.php}
+ *  - {@link https://docs.mongodb.com/ecosystem/drivers/php/}
  *
  * @copyright  2012 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -65,19 +67,19 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
 
     /**
      * The Connection object
-     * @var Mongo
+     * @var MongoDB/Client
      */
     protected $connection = false;
 
     /**
      * The Database Object
-     * @var MongoDB
+     * @var MongoDB/Database
      */
     protected $database;
 
     /**
      * The Collection object
-     * @var MongoCollection
+     * @var MongoDB/Collection
      */
     protected $collection;
 
@@ -105,14 +107,6 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
      */
     protected $isready = false;
 
-    /**
-     * Set to true if the Mongo extension is < version 1.3.
-     * If this is the case we must use the legacy Mongo class instead of MongoClient.
-     * Mongo is backwards compatible, although obviously deprecated.
-     * @var bool
-     */
-    protected $legacymongo = false;
-
     /**
      * Constructs a new instance of the Mongo store.
      *
@@ -148,16 +142,11 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
             $this->extendedmode = $configuration['extendedmode'];
         }
 
-        // Test if the MongoClient class exists, if not we need to switch to legacy classes.
-        $this->legacymongo = (!class_exists('MongoClient'));
-
-        // MongoClient from Mongo 1.3 onwards. Mongo for earlier versions.
-        $class = ($this->legacymongo) ? 'Mongo' : 'MongoClient';
         try {
-            $this->connection = new $class($this->server, $this->options);
+            $this->connection = new MongoDB\Client($this->server, $this->options);
             $this->isready = true;
-        } catch (MongoConnectionException $e) {
-            // We only want to catch MongoConnectionExceptions here.
+        } catch (MongoDB\Driver\Exception\RuntimeException $e) {
+            // We only want to catch RuntimeException here.
         }
     }
 
@@ -166,7 +155,7 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
      * @return bool
      */
     public static function are_requirements_met() {
-        return class_exists('MongoClient') || class_exists('Mongo');
+        return version_compare(phpversion('mongodb'), '1.5', 'ge');
     }
 
     /**
@@ -203,17 +192,18 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
         if ($this->is_initialised()) {
             throw new coding_exception('This mongodb instance has already been initialised.');
         }
-        $this->database = $this->connection->selectDB($this->databasename);
+        $this->database = $this->connection->selectDatabase($this->databasename);
         $this->definitionhash = 'm'.$definition->generate_definition_hash();
         $this->collection = $this->database->selectCollection($this->definitionhash);
 
         $options = array('name' => 'idx_key');
-        if ($this->legacymongo) {
-            $options['safe'] = $this->usesafe;
-        } else {
-            $options['w'] = $this->usesafe ? 1 : 0;
-        }
-        $this->collection->ensureIndex(array('key' => 1), $options);
+
+        $w = $this->usesafe ? 1 : 0;
+        $wc = new MongoDB\Driver\WriteConcern($w);
+
+        $options['writeConcern'] = $wc;
+
+        $this->collection->createIndex(array('key' => 1), $options);
     }
 
     /**
@@ -221,7 +211,7 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
      * @return bool
      */
     public function is_initialised() {
-        return ($this->database instanceof MongoDB);
+        return ($this->database instanceof MongoDB\Database);
     }
 
     /**
@@ -319,24 +309,20 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
         }
         $record['data'] = serialize($data);
         $options = array('upsert' => true);
-        if ($this->legacymongo) {
-            $options['safe'] = $this->usesafe;
-        } else {
-            $options['w'] = $this->usesafe ? 1 : 0;
-        }
+
+        $w = $this->usesafe ? 1 : 0;
+        $wc = new MongoDB\Driver\WriteConcern($w);
+
+        $options['writeConcern'] = $wc;
+
         $this->delete($key);
-        $result = $this->collection->insert($record, $options);
-        if ($result === true) {
-            // Safe mode is off.
-            return true;
-        } else if (is_array($result)) {
-            if (empty($result['ok']) || isset($result['err'])) {
-                return false;
-            }
-            return true;
+        try {
+            $this->collection->insertOne($record, $options);
+        } catch (MongoDB\Exception\Exception $e) {
+            return false;
         }
-        // Who knows?
-        return false;
+
+        return true;
     }
 
     /**
@@ -373,27 +359,23 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
             $criteria = $key;
         }
         $options = array('justOne' => false);
-        if ($this->legacymongo) {
-            $options['safe'] = $this->usesafe;
-        } else {
-            $options['w'] = $this->usesafe ? 1 : 0;
-        }
-        $result = $this->collection->remove($criteria, $options);
-
-        if ($result === true) {
-            // Safe mode.
-            return true;
-        } else if (is_array($result)) {
-            if (empty($result['ok']) || isset($result['err'])) {
-                return false;
-            } else if (empty($result['n'])) {
-                // Nothing was removed.
-                return false;
-            }
-            return true;
+
+        $w = $this->usesafe ? 1 : 0;
+        $wc = new MongoDB\Driver\WriteConcern($w);
+
+        $options['writeConcern'] = $wc;
+
+        try {
+            $result = $this->collection->deleteOne($criteria, $options);
+        } catch (\MongoDB\Exception $e) {
+            return false;
+        }
+
+        if (empty($result->getDeletedCount())) {
+            return false;
         }
-        // Who knows?
-        return false;
+
+        return true;
     }
 
     /**
@@ -502,16 +484,14 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
             $connection = $this->connection;
         } else {
             try {
-                // MongoClient from Mongo 1.3 onwards. Mongo for earlier versions.
-                $class = ($this->legacymongo) ? 'Mongo' : 'MongoClient';
-                $connection = new $class($this->server, $this->options);
-            } catch (MongoConnectionException $e) {
-                // We only want to catch MongoConnectionExceptions here.
+                $connection = new MongoDB\Client($this->server, $this->options);
+            } catch (MongoDB\Driver\Exception\RuntimeException $e) {
+                // We only want to catch RuntimeException here.
                 // If the server cannot be connected to we cannot clean it.
                 return;
             }
         }
-        $database = $connection->selectDB($this->databasename);
+        $database = $connection->selectDatabase($this->databasename);
         $database->drop();
         $connection = null;
         $database = null;
@@ -564,7 +544,6 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
         return $store;
     }
 
-
     /**
      * Generates an instance of the cache store that can be used for testing.
      *
@@ -577,7 +556,7 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
 
         // If the configuration is not defined correctly, return only the configuration know about.
         if (defined('TEST_CACHESTORE_MONGODB_TESTSERVER')) {
-            $configuration['servers'] = explode("\n", TEST_CACHESTORE_MONGODB_TESTSERVER);
+            $configuration['server'] = TEST_CACHESTORE_MONGODB_TESTSERVER;
         }
 
         return $configuration;
diff --git a/cache/stores/mongodb/thirdpartylibs.xml b/cache/stores/mongodb/thirdpartylibs.xml
new file mode 100644 (file)
index 0000000..bd22d79
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<libraries>
+  <library>
+    <location>MongoDB</location>
+    <name>MongoDB PHP Library</name>
+    <license>Apache</license>
+    <version>1.4</version>
+    <licenseversion>2.0</licenseversion>
+  </library>
+</libraries>
\ No newline at end of file
index f6c02bd..4a801da 100644 (file)
@@ -1,6 +1,11 @@
 This files describes API changes in /cache/stores/* - cache store plugins.
 Information provided here is intended especially for developers.
 
+=== 3.7 ===
+* Upgraded MongoDB cache store to use the new lower level PHP-driver and MongoDB PHP Library.
+* The mongodb extension has replaced the old mongo extension. The mongodb pecl extension >= 1.5 must be installed to use MongoDB
+cache store.
+
 === 3.6 ===
 * The `cache::now()` function now takes an optional boolean parameter to indicate that the cache should return a more
   accurate time, generated by the PHP `microtime` function.
index af9449e..8cd7889 100644 (file)
@@ -86,6 +86,7 @@ class core_component {
         'Phpml' => 'lib/mlbackend/php/phpml/src/Phpml',
         'PHPMailer\\PHPMailer' => 'lib/phpmailer/src',
         'RedeyeVentures\\GeoPattern' => 'lib/geopattern-php/GeoPattern',
+        'MongoDB' => 'cache/stores/mongodb/MongoDB',
     );
 
     /**