Permalink
Browse files

Merge pull request #87 from doctrine/readprefs

Support 1.2.12 and 1.3.x drivers (slaveOkay and read pref compatibility)
  • Loading branch information...
2 parents 2b4e5c5 + f3449d2 commit 4813728372c02cc8f8bacfa18faef7134d0a5797 @jwage jwage committed Dec 18, 2012
View
@@ -5,6 +5,7 @@ php:
- 5.4
env:
+ - MONGO_VERSION=1.2.12
- MONGO_VERSION=1.3.1
services: mongodb
View
@@ -12,7 +12,7 @@
],
"require": {
"php": ">=5.3.2",
- "ext-mongo": ">=1.3.1,<1.4-dev",
+ "ext-mongo": ">=1.2.12,<1.4-dev",
"symfony/yaml": ">=2.0,<2.3-dev",
"symfony/console": ">=2.0,<2.3-dev",
"doctrine/common": ">=2.1.0,<2.5-dev"
@@ -19,13 +19,14 @@
namespace Doctrine\MongoDB;
-use Doctrine\Common\EventManager,
- Doctrine\MongoDB\Event\EventArgs,
- Doctrine\MongoDB\Event\DistinctEventArgs,
- Doctrine\MongoDB\Event\GroupEventArgs,
- Doctrine\MongoDB\Event\NearEventArgs,
- Doctrine\MongoDB\Event\MapReduceEventArgs,
- Doctrine\MongoDB\Event\UpdateEventArgs;
+use Doctrine\Common\EventManager;
+use Doctrine\MongoDB\Event\DistinctEventArgs;
+use Doctrine\MongoDB\Event\EventArgs;
+use Doctrine\MongoDB\Event\GroupEventArgs;
+use Doctrine\MongoDB\Event\MapReduceEventArgs;
+use Doctrine\MongoDB\Event\NearEventArgs;
+use Doctrine\MongoDB\Event\UpdateEventArgs;
+use Doctrine\MongoDB\Util\ReadPreference;
/**
* Wrapper for the PHP MongoCollection class.
@@ -616,6 +617,51 @@ protected function doSave(array &$a, array $options)
return $this->getMongoCollection()->save($a, $options);
}
+ /**
+ * Set whether secondary read queries are allowed for this collection.
+ *
+ * This method wraps setSlaveOkay() for driver versions before 1.3.0. For
+ * newer drivers, this method wraps setReadPreference() and specifies
+ * SECONDARY_PREFERRED.
+ */
+ public function setSlaveOkay($ok = true)
+ {
+ if (version_compare(phpversion('mongo'), '1.3.0', '<')) {
+ return $this->getMongoCollection()->setSlaveOkay($ok);
+ }
+
+ $prevSlaveOkay = $this->getSlaveOkay();
+
+ if ($ok) {
+ // Preserve existing tags for non-primary read preferences
+ $readPref = $this->getMongoCollection()->getReadPreference();
+ $tags = isset($readPref['tagsets']) ? ReadPreference::convertTagSets($readPref['tagsets']) : array();
+ $this->getMongoCollection()->setReadPreference(\MongoClient::RP_SECONDARY_PREFERRED, $tags);
+ } else {
+ $this->getMongoCollection()->setReadPreference(\MongoClient::RP_PRIMARY);
+ }
+
+ return $prevSlaveOkay;
+ }
+
+ /**
+ * Get whether secondary read queries are allowed for this collection.
+ *
+ * This method wraps getSlaveOkay() for driver versions before 1.3.0. For
+ * newer drivers, this method considers any read preference other than
+ * PRIMARY as a true "slaveOkay" value.
+ */
+ public function getSlaveOkay()
+ {
+ if (version_compare(phpversion('mongo'), '1.3.0', '<')) {
+ return $this->getMongoCollection()->getSlaveOkay();
+ }
+
+ $readPref = $this->getMongoCollection()->getReadPreference();
+
+ return \MongoClient::RP_PRIMARY !== ReadPreference::convertNumericType($readPref['type']);
+ }
+
public function validate($scanData = false)
{
return $this->getMongoCollection()->validate($scanData);
@@ -69,12 +69,12 @@ class Connection
/**
* Create a new MongoClient wrapper instance.
*
- * @param mixed $server A string server name, an existing Mongo instance or can be omitted.
+ * @param mixed $server A string server name, an existing MongoClient or Mongo instance, or null
* @param array $options
*/
public function __construct($server = null, array $options = array(), Configuration $config = null, EventManager $evm = null)
{
- if ($server instanceof \MongoClient) {
+ if ($server instanceof \MongoClient || $server instanceof \Mongo) {
$this->mongo = $server;
} elseif ($server !== null) {
$this->server = $server;
@@ -95,6 +95,10 @@ public function initialize($reinitialize = false)
$server = $this->server;
$options = $this->options;
$this->mongo = $this->retry(function() use($server, $options) {
+ if (version_compare(phpversion('mongo'), '1.3.0', '<')) {
+ return new \Mongo($server ?: 'mongodb://localhost:27017', $options);
+ }
+
return new \MongoClient($server ?: 'mongodb://localhost:27017', $options);
});
@@ -147,10 +151,14 @@ public function log(array $log)
/**
* Set the PHP MongoClient instance to wrap.
*
- * @param MongoCient $mongo The PHP Mongo instance
+ * @param MongoClient $mongo The PHP Mongo instance
*/
- public function setMongo(\MongoClient $mongo)
+ public function setMongo($mongo)
{
+ if ( ! ($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
+ throw new \InvalidArgumentException('MongoClient or Mongo instance required');
+ }
+
$this->mongo = $mongo;
}
@@ -43,15 +43,15 @@ class Cursor implements Iterator
protected $query = array();
protected $fields = array();
protected $hints = array();
- protected $immortal = false;
+ protected $immortal;
protected $options = array();
protected $batchSize;
protected $limit;
protected $skip;
- protected $slaveOkay = false;
+ protected $slaveOkay;
protected $snapshot;
protected $sorts = array();
- protected $tailable = false;
+ protected $tailable;
protected $timeout;
/**
@@ -100,7 +100,9 @@ public function recreate()
foreach ($this->hints as $hint) {
$this->mongoCursor->hint($hint);
}
- $this->mongoCursor->immortal($this->immortal);
+ if ($this->immortal !== null) {
+ $this->mongoCursor->immortal($this->immortal);
+ }
foreach ($this->options as $key => $value) {
$this->mongoCursor->addOption($key, $value);
}
@@ -113,14 +115,18 @@ public function recreate()
if ($this->skip !== null) {
$this->mongoCursor->skip($this->skip);
}
- $this->mongoCursor->slaveOkay($this->slaveOkay);
+ if ($this->slaveOkay !== null) {
+ $this->setMongoCursorSlaveOkay($this->slaveOkay);
+ }
if ($this->snapshot) {
$this->mongoCursor->snapshot();
}
foreach ($this->sorts as $sort) {
$this->mongoCursor->sort($sort);
}
- $this->mongoCursor->tailable($this->tailable);
+ if ($this->tailable !== null) {
+ $this->mongoCursor->tailable($this->tailable);
+ }
if ($this->timeout !== null) {
$this->mongoCursor->timeout($this->timeout);
}
@@ -203,6 +209,7 @@ public function hint(array $keyPattern)
public function immortal($liveForever = true)
{
+ $liveForever = (boolean) $liveForever;
$this->immortal = $liveForever;
$this->mongoCursor->immortal($liveForever);
return $this;
@@ -251,32 +258,70 @@ public function addOption($key, $value)
public function batchSize($num)
{
+ $limit = (integer) $num;
$this->batchSize = $num;
$this->mongoCursor->batchSize($num);
return $this;
}
public function limit($num)
{
+ $limit = (integer) $num;
$this->limit = $num;
$this->mongoCursor->limit($num);
return $this;
}
public function skip($num)
{
+ $num = (integer) $num;
$this->skip = $num;
$this->mongoCursor->skip($num);
return $this;
}
- public function slaveOkay($okay = true)
+ public function slaveOkay($ok = true)
{
- $this->slaveOkay = $okay;
- $this->mongoCursor->slaveOkay($okay);
+ $ok = (boolean) $ok;
+ $this->slaveOkay = $ok;
+ $this->setMongoCursorSlaveOkay($ok);
return $this;
}
+ /**
+ * Set whether secondary read queries are allowed for this cursor.
+ *
+ * This method wraps setSlaveOkay() for driver versions before 1.3.0. For
+ * newer drivers, this method either wraps setReadPreference() method and
+ * specifies SECONDARY_PREFERRED or does nothing, depending on whether
+ * setReadPreference() exists.
+ *
+ * @param boolean $ok
+ */
+ public function setMongoCursorSlaveOkay($ok)
+ {
+ if (version_compare(phpversion('mongo'), '1.3.0', '<')) {
+ $this->mongoCursor->slaveOkay($ok);
+ return;
+ }
+
+ /* MongoCursor::setReadPreference() may not exist until 1.4.0. Although
+ * we could throw an exception here, it's more user-friendly to NOP.
+ */
+ if (!method_exists($this->mongoCursor, 'setReadPreference')) {
+ return;
+ }
+
+ if ($ok) {
+ // Preserve existing tags for non-primary read preferences
+ $readPref = $this->mongoCursor->getReadPreference();
+ $tags = isset($readPref['tagsets']) ? ReadPreference::convertTagSets($readPref['tagsets']) : array();
+ $this->mongoCursor->setReadPreference(\MongoClient::RP_SECONDARY_PREFERRED, $tags);
+ } else {
+ $this->mongoCursor->setReadPreference(\MongoClient::RP_PRIMARY);
+ }
+ }
+
public function snapshot()
{
$this->snapshot = true;
@@ -290,8 +335,7 @@ public function sort($fields)
if (is_string($order)) {
$order = strtolower($order) === 'asc' ? 1 : -1;
}
- $order = (int) $order;
- $fields[$fieldName] = $order;
+ $fields[$fieldName] = (integer) $order;
}
$this->sorts[] = $fields;
$this->mongoCursor->sort($fields);
@@ -300,14 +344,15 @@ public function sort($fields)
public function tailable($tail = true)
{
+ $tail = (boolean) $tail;
$this->tailable = $tail;
$this->mongoCursor->tailable($tail);
return $this;
}
public function timeout($ms)
{
- $this->timeout = $ms;
+ $this->timeout = (integer) $ms;
$this->mongoCursor->timeout($ms);
return $this;
}
@@ -372,4 +417,4 @@ protected function retry(\Closure $retry, $recreate = false)
return $retry();
}
}
-}
+}
@@ -19,8 +19,9 @@
namespace Doctrine\MongoDB;
-use Doctrine\Common\EventManager,
- Doctrine\MongoDB\Event\EventArgs;
+use Doctrine\Common\EventManager;
+use Doctrine\MongoDB\Event\EventArgs;
+use Doctrine\MongoDB\Util\ReadPreference;
/**
* Wrapper for the PHP MongoDB class.
@@ -200,6 +201,51 @@ protected function doGetGridFs($name)
);
}
+ /**
+ * Set whether secondary read queries are allowed for this database.
+ *
+ * This method wraps setSlaveOkay() for driver versions before 1.3.0. For
+ * newer drivers, this method wraps setReadPreference() and specifies
+ * SECONDARY_PREFERRED.
+ */
+ public function setSlaveOkay($ok = true)
+ {
+ if (version_compare(phpversion('mongo'), '1.3.0', '<')) {
+ return $this->getMongoDB()->setSlaveOkay($ok);
+ }
+
+ $prevSlaveOkay = $this->getSlaveOkay();
+
+ if ($ok) {
+ // Preserve existing tags for non-primary read preferences
+ $readPref = $this->getMongoDB()->getReadPreference();
+ $tags = isset($readPref['tagsets']) ? ReadPreference::convertTagSets($readPref['tagsets']) : array();
+ $this->getMongoDB()->setReadPreference(\MongoClient::RP_SECONDARY_PREFERRED, $tags);
+ } else {
+ $this->getMongoDB()->setReadPreference(\MongoClient::RP_PRIMARY);
+ }
+
+ return $prevSlaveOkay;
+ }
+
+ /**
+ * Get whether secondary read queries are allowed for this database.
+ *
+ * This method wraps getSlaveOkay() for driver versions before 1.3.0. For
+ * newer drivers, this method considers any read preference other than
+ * PRIMARY as a true "slaveOkay" value.
+ */
+ public function getSlaveOkay()
+ {
+ if (version_compare(phpversion('mongo'), '1.3.0', '<')) {
+ return $this->getMongoDB()->getSlaveOkay();
+ }
+
+ $readPref = $this->getMongoDB()->getReadPreference();
+
+ return \MongoClient::RP_PRIMARY !== ReadPreference::convertNumericType($readPref['type']);
+ }
+
public function getProfilingLevel()
{
return $this->getMongoDB()->getProfilingLevel();
@@ -74,7 +74,7 @@ class Builder
'hints' => array(),
'immortal' => false,
'snapshot' => false,
- 'slaveOkay' => false,
+ 'slaveOkay' => null,
'eagerCursor' => false,
'mapReduce' => array(
'map' => null,
@@ -129,7 +129,7 @@ public function getType()
}
/**
- * Set slave okaye.
+ * Set slave okay.
*
* @param bool $bool
* @return Builder
Oops, something went wrong.

0 comments on commit 4813728

Please sign in to comment.