diff --git a/.travis.yml b/.travis.yml
index b6e6361f7..59b908f5e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,11 +7,12 @@ php:
- 5.6
env:
- - MONGODB_VERSION=0.2.0
+ - MONGODB_VERSION=alpha
services: mongodb
before_script:
- - pecl -q install -f mongodb-${MONGODB_VERSION}
+ - mongo --eval 'tojson(db.runCommand({buildInfo:1}))'
+ - pecl install -f mongodb-${MONGODB_VERSION}
- php --ri mongodb
- composer install --dev --no-interaction --prefer-source
diff --git a/composer.json b/composer.json
index fb95e2cb1..2ca78742e 100644
--- a/composer.json
+++ b/composer.json
@@ -10,7 +10,7 @@
{ "name": "Derick Rethans", "email": "github@derickrethans.nl" }
],
"require": {
- "ext-mongodb": "^0.2"
+ "ext-mongodb": "*"
},
"require-dev": {
"fzaninotto/faker": "~1.0"
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 4df13239c..4f324887a 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -11,11 +11,13 @@
convertWarningsToExceptions="true"
stopOnFailure="false"
syntaxCheck="false"
- bootstrap="vendor/autoload.php"
+ bootstrap="tests/bootstrap.php"
>
+
+
diff --git a/src/Client.php b/src/Client.php
index 4c926a2ca..f83f0b87f 100644
--- a/src/Client.php
+++ b/src/Client.php
@@ -2,30 +2,34 @@
namespace MongoDB;
-use MongoDB\Collection;
-use MongoDB\Database;
+use MongoDB\Driver\Command;
+use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager;
-use MongoDB\Driver\Result;
+use MongoDB\Driver\ReadPreference;
+use MongoDB\Driver\WriteConcern;
+use ArrayIterator;
+use stdClass;
+use UnexpectedValueException;
class Client
{
private $manager;
- private $wc;
- private $rp;
-
+ private $readPreference;
+ private $writeConcern;
/**
- * Constructs new Client instance
+ * Constructs a new Client instance.
*
- * This is the suggested main entry point using phongo.
- * It acts as a bridge to access individual databases and collection tools
- * which are provided in this namespace.
+ * This is the preferred class for connecting to a MongoDB server or
+ * cluster of servers. It serves as a gateway for accessing individual
+ * databases and collections.
*
- * @param Manager $uri The MongoDB URI to connect to
- * @param WriteConcern $options URI Options
- * @param ReadPreference $driverOptions Driver specific options
+ * @see http://docs.mongodb.org/manual/reference/connection-string/
+ * @param string $uri MongoDB connection string
+ * @param array $options Additional connection string options
+ * @param array $driverOptions Driver-specific options
*/
- public function __construct($uri, $options, $driverOptions)
+ public function __construct($uri, array $options = array(), array $driverOptions = array())
{
$this->manager = new Manager($uri, $options, $driverOptions);
}
@@ -33,42 +37,90 @@ public function __construct($uri, $options, $driverOptions)
/**
* Drop a database.
*
+ * @see http://docs.mongodb.org/manual/reference/command/dropDatabase/
* @param string $databaseName
- * @return Result
+ * @return Cursor
*/
public function dropDatabase($databaseName)
{
- // TODO
+ $databaseName = (string) $databaseName;
+ $command = new Command(array('dropDatabase' => 1));
+ $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
+
+ return $this->manager->executeCommand($databaseName, $command, $readPreference);
}
/**
- * Select a database
+ * List databases.
*
- * It acts as a bridge to access specific database commands
- *
- * @param string $databaseName The database to select
- * @param WriteConcern $writeConcern Default Write Concern to apply
- * @param ReadPreference $readPreferences Default Read Preferences to apply
+ * @see http://docs.mongodb.org/manual/reference/command/listDatabases/
+ * @return Traversable
+ * @throws UnexpectedValueException if the command result is malformed
*/
- public function selectDatabase($databaseName, WriteConcern $writeConcern = null, ReadPreference $readPreferences = null)
+ public function listDatabases()
{
- return new Database($this->manager, $databaseName, $writeConcern, $readPreferences);
+ $command = new Command(array('listDatabases' => 1));
+
+ $cursor = $this->manager->executeCommand('admin', $command);
+ $result = current($cursor->toArray());
+
+ if ( ! isset($result['databases']) || ! is_array($result['databases'])) {
+ throw new UnexpectedValueException('listDatabases command did not return a "databases" array');
+ }
+
+ $databases = array_map(
+ function(stdClass $database) { return (array) $database; },
+ $result['databases']
+ );
+
+ /* Return a Traversable instead of an array in case listDatabases is
+ * eventually changed to return a command cursor, like the collection
+ * and index enumeration commands. This makes the "totalSize" command
+ * field inaccessible, but users can manually invoke the command if they
+ * need that value.
+ */
+ return new ArrayIterator($databases);
}
/**
- * Select a specific collection in a database
+ * Select a database.
*
- * It acts as a bridge to access specific collection commands
+ * If a write concern or read preference is not specified, the write concern
+ * or read preference of the Client will be applied, respectively.
*
- * @param string $databaseName The database where the $collectionName exists
- * @param string $collectionName The collection to select
- * @param WriteConcern $writeConcern Default Write Concern to apply
- * @param ReadPreference $readPreferences Default Read Preferences to apply
+ * @param string $databaseName Name of the database to select
+ * @param WriteConcern $writeConcern Default write concern to apply
+ * @param ReadPreference $readPreference Default read preference to apply
+ * @return Database
*/
- public function selectCollection($databaseName, $collectionName, WriteConcern $writeConcern = null, ReadPreference $readPreferences = null)
+ public function selectDatabase($databaseName, WriteConcern $writeConcern = null, ReadPreference $readPreference = null)
{
- return new Collection($this->manager, "{$databaseName}.{$collectionName}", $writeConcern, $readPreferences);
+ // TODO: inherit from Manager options once PHPC-196 is implemented
+ $writeConcern = $writeConcern ?: $this->writeConcern;
+ $readPreference = $readPreference ?: $this->readPreference;
+
+ return new Database($this->manager, $databaseName, $writeConcern, $readPreference);
}
-}
+ /**
+ * Select a collection.
+ *
+ * If a write concern or read preference is not specified, the write concern
+ * or read preference of the Client will be applied, respectively.
+ *
+ * @param string $databaseName Name of the database containing the collection
+ * @param string $collectionName Name of the collection to select
+ * @param WriteConcern $writeConcern Default write concern to apply
+ * @param ReadPreference $readPreference Default read preference to apply
+ * @return Collection
+ */
+ public function selectCollection($databaseName, $collectionName, WriteConcern $writeConcern = null, ReadPreference $readPreference = null)
+ {
+ $namespace = $databaseName . '.' . $collectionName;
+ // TODO: inherit from Manager options once PHPC-196 is implemented
+ $writeConcern = $writeConcern ?: $this->writeConcern;
+ $readPreference = $readPreference ?: $this->readPreference;
+ return new Collection($this->manager, $namespace, $writeConcern, $readPreference);
+ }
+}
diff --git a/src/Collection.php b/src/Collection.php
index c4bcbc7fe..82bc054fa 100644
--- a/src/Collection.php
+++ b/src/Collection.php
@@ -3,10 +3,10 @@
namespace MongoDB;
use MongoDB\Driver\Command;
+use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager;
use MongoDB\Driver\Query;
use MongoDB\Driver\ReadPreference;
-use MongoDB\Driver\Result;
use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\WriteConcern;
@@ -43,25 +43,24 @@ class Collection
/**
- * Constructs new Collection instance
+ * Constructs new Collection instance.
*
- * This is the suggested CRUD interface when using phongo.
- * It implements the MongoDB CRUD specification which is an interface all MongoDB
- * supported drivers follow.
+ * This class provides methods for collection-specific operations, such as
+ * CRUD (i.e. create, read, update, and delete) and index management.
*
- * @param Manager $manager The phongo Manager instance
- * @param string $ns Fully Qualified Namespace (dbname.collname)
- * @param WriteConcern $wc The WriteConcern to apply to writes
- * @param ReadPreference $rp The ReadPreferences to apply to reads
+ * @param Manager $manager Manager instance from the driver
+ * @param string $namespace Collection namespace (e.g. "db.collection")
+ * @param WriteConcern $writeConcern Default write concern to apply
+ * @param ReadPreference $readPreference Default read preference to apply
*/
- public function __construct(Manager $manager, $ns, WriteConcern $wc = null, ReadPreference $rp = null)
+ public function __construct(Manager $manager, $namespace, WriteConcern $writeConcern = null, ReadPreference $readPreference = null)
{
$this->manager = $manager;
- $this->ns = $ns;
- $this->wc = $wc;
- $this->rp = $rp;
+ $this->ns = (string) $namespace;
+ $this->wc = $writeConcern;
+ $this->rp = $readPreference;
- list($this->dbname, $this->collname) = explode(".", $ns, 2);
+ list($this->dbname, $this->collname) = explode(".", $namespace, 2);
}
/**
@@ -87,14 +86,16 @@ public function aggregate(array $pipeline, array $options = array())
"pipeline" => $pipeline,
) + $options;
- $result = $this->_runCommand($this->dbname, $cmd);
- $doc = $result->toArray();
+ $cursor = $this->_runCommand($this->dbname, $cmd);
+
if (isset($cmd["cursor"]) && $cmd["cursor"]) {
- return $result;
- } else {
- if ($doc["ok"]) {
- return new \ArrayIterator($doc["result"]);
- }
+ return $cursor;
+ }
+
+ $doc = current($cursor->toArray());
+
+ if ($doc["ok"]) {
+ return new \ArrayIterator($doc["result"]);
}
throw $this->_generateCommandException($doc);
@@ -235,7 +236,7 @@ public function count(array $filter = array(), array $options = array())
"query" => $filter,
) + $options;
- $doc = $this->_runCommand($this->dbname, $cmd)->toArray();
+ $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) {
return $doc["n"];
}
@@ -325,7 +326,7 @@ public function distinct($fieldName, array $filter = array(), array $options = a
"query" => $filter,
) + $options;
- $doc = $this->_runCommand($this->dbname, $cmd)->toArray();
+ $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) {
return $doc["values"];
}
@@ -335,11 +336,15 @@ public function distinct($fieldName, array $filter = array(), array $options = a
/**
* Drop this collection.
*
- * @return Result
+ * @see http://docs.mongodb.org/manual/reference/command/drop/
+ * @return Cursor
*/
public function drop()
{
- // TODO
+ $command = new Command(array('drop' => $this->collname));
+ $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
+
+ return $this->manager->executeCommand($this->dbname, $command, $readPreference);
}
/**
@@ -348,7 +353,7 @@ public function drop()
* @see http://docs.mongodb.org/manual/reference/command/dropIndexes/
* @see http://docs.mongodb.org/manual/reference/method/db.collection.dropIndex/
* @param string $indexName
- * @return Result
+ * @return Cursor
* @throws InvalidArgumentException if "*" is specified
*/
public function dropIndex($indexName)
@@ -361,7 +366,7 @@ public function dropIndex($indexName)
*
* @see http://docs.mongodb.org/manual/reference/command/dropIndexes/
* @see http://docs.mongodb.org/manual/reference/method/db.collection.dropIndexes/
- * @return Result
+ * @return Cursor
*/
public function dropIndexes()
{
@@ -376,7 +381,7 @@ public function dropIndexes()
*
* @param array $filter The find query to execute
* @param array $options Additional options
- * @return Result
+ * @return Cursor
*/
public function find(array $filter = array(), array $options = array())
{
@@ -434,7 +439,7 @@ public function findOneAndDelete(array $filter, array $options = array())
"query" => $filter,
) + $options;
- $doc = $this->_runCommand($this->dbname, $cmd)->toArray();
+ $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) {
return $doc["value"];
}
@@ -471,7 +476,7 @@ public function findOneAndReplace(array $filter, array $replacement, array $opti
"query" => $filter,
) + $options;
- $doc = $this->_runCommand($this->dbname, $cmd)->toArray();
+ $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) {
return $doc["value"];
}
@@ -509,7 +514,7 @@ public function findOneAndUpdate(array $filter, array $update, array $options =
"query" => $filter,
) + $options;
- $doc = $this->_runCommand($this->dbname, $cmd)->toArray();
+ $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) {
return $doc["value"];
}
@@ -948,7 +953,7 @@ public function insertOne(array $document)
*
* @see http://docs.mongodb.org/manual/reference/command/listIndexes/
* @see http://docs.mongodb.org/manual/reference/method/db.collection.getIndexes/
- * @return Result
+ * @return Cursor
*/
public function listIndexes()
{
diff --git a/src/Database.php b/src/Database.php
index cb772b3a6..1da5d90db 100644
--- a/src/Database.php
+++ b/src/Database.php
@@ -3,34 +3,42 @@
namespace MongoDB;
use MongoDB\Collection;
+use MongoDB\Driver\Command;
+use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager;
-use MongoDB\Driver\Result;
+use MongoDB\Driver\Query;
+use MongoDB\Driver\ReadPreference;
+use MongoDB\Driver\Server;
+use MongoDB\Driver\WriteConcern;
+use MongoDB\Model\CollectionInfoIterator;
+use MongoDB\Model\CollectionInfoCommandIterator;
+use MongoDB\Model\CollectionInfoLegacyIterator;
+use InvalidArgumentException;
class Database
{
+ private $databaseName;
private $manager;
- private $ns;
- private $wc;
- private $rp;
-
- private $dbname;
+ private $readPreference;
+ private $writeConcern;
/**
- * Constructs new Database instance
+ * Constructs new Database instance.
*
- * It acts as a bridge for database specific operations.
+ * This class provides methods for database-specific operations and serves
+ * as a gateway for accessing collections.
*
- * @param Manager $manager The phongo Manager instance
- * @param string $dbname Fully Qualified database name
- * @param WriteConcern $wc The WriteConcern to apply to writes
- * @param ReadPreference $rp The ReadPreferences to apply to reads
+ * @param Manager $manager Manager instance from the driver
+ * @param string $databaseName Database name
+ * @param WriteConcern $writeConcern Default write concern to apply
+ * @param ReadPreference $readPreference Default read preference to apply
*/
- public function __construct(Manager $manager, $databaseName, WriteConcern $wc = null, ReadPreference $rp = null)
+ public function __construct(Manager $manager, $databaseName, WriteConcern $writeConcern = null, ReadPreference $readPreference = null)
{
$this->manager = $manager;
- $this->dbname = $dbname;
- $this->wc = $wc;
- $this->rp = $rp;
+ $this->databaseName = (string) $databaseName;
+ $this->writeConcern = $writeConcern;
+ $this->readPreference = $readPreference;
}
/**
@@ -40,32 +48,45 @@ public function __construct(Manager $manager, $databaseName, WriteConcern $wc =
* @see http://docs.mongodb.org/manual/reference/method/db.createCollection/
* @param string $collectionName
* @param array $options
- * @return Result
+ * @return Cursor
*/
public function createCollection($collectionName, array $options = array())
{
- // TODO
+ $collectionName = (string) $collectionName;
+ $command = new Command(array('create' => $collectionName) + $options);
+ $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
+
+ return $this->manager->executeCommand($this->databaseName, $command, $readPreference);
}
/**
* Drop this database.
*
- * @return Result
+ * @see http://docs.mongodb.org/manual/reference/command/dropDatabase/
+ * @return Cursor
*/
public function drop()
{
- // TODO
+ $command = new Command(array('dropDatabase' => 1));
+ $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
+
+ return $this->manager->executeCommand($this->databaseName, $command, $readPreference);
}
/**
* Drop a collection within this database.
*
+ * @see http://docs.mongodb.org/manual/reference/command/drop/
* @param string $collectionName
- * @return Result
+ * @return Cursor
*/
public function dropCollection($collectionName)
{
- // TODO
+ $collectionName = (string) $collectionName;
+ $command = new Command(array('drop' => $collectionName));
+ $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
+
+ return $this->manager->executeCommand($this->databaseName, $command, $readPreference);
}
/**
@@ -73,27 +94,90 @@ public function dropCollection($collectionName)
*
* @see http://docs.mongodb.org/manual/reference/command/listCollections/
* @param array $options
- * @return Result
+ * @return CollectionInfoIterator
*/
public function listCollections(array $options = array())
{
- // TODO
+ $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
+ $server = $this->manager->selectServer($readPreference);
+
+ $serverInfo = $server->getInfo();
+ $maxWireVersion = isset($serverInfo['maxWireVersion']) ? $serverInfo['maxWireVersion'] : 0;
+
+ return ($maxWireVersion >= 3)
+ ? $this->listCollectionsCommand($server, $options)
+ : $this->listCollectionsLegacy($server, $options);
}
/**
- * Select a specific collection in this database
+ * Select a collection within this database.
*
- * It acts as a bridge to access specific collection commands
+ * If a write concern or read preference is not specified, the write concern
+ * or read preference of the Database will be applied, respectively.
*
- * @param string $collectionName The collection to select
- * @param WriteConcern $writeConcern Default Write Concern to apply
- * @param ReadPreference $readPreferences Default Read Preferences to apply
+ * @param string $collectionName Name of the collection to select
+ * @param WriteConcern $writeConcern Default write concern to apply
+ * @param ReadPreference $readPreference Default read preference to apply
+ * @return Collection
*/
- public function selectCollection($collectionName, WriteConcern $writeConcern = null, ReadPreference $readPreferences = null)
+ public function selectCollection($collectionName, WriteConcern $writeConcern = null, ReadPreference $readPreference = null)
{
- return new Collection($this->manager, "{$this->dbname}.{$collectionName}", $writeConcern, $readPreferences);
+ $namespace = $this->databaseName . '.' . $collectionName;
+ $writeConcern = $writeConcern ?: $this->writeConcern;
+ $readPreference = $readPreference ?: $this->readPreference;
+
+ return new Collection($this->manager, $namespace, $writeConcern, $readPreference);
}
-}
+ /**
+ * Returns information for all collections in this database using the
+ * listCollections command.
+ *
+ * @param Server $server
+ * @param array $options
+ * @return CollectionInfoCommandIterator
+ */
+ private function listCollectionsCommand(Server $server, array $options = array())
+ {
+ $command = new Command(array('listCollections' => 1) + $options);
+ $cursor = $server->executeCommand($this->databaseName, $command);
+ return new CollectionInfoCommandIterator($cursor);
+ }
+ /**
+ * Returns information for all collections in this database by querying
+ * the "system.namespaces" collection (MongoDB <2.8).
+ *
+ * @param Server $server
+ * @param array $options
+ * @return CollectionInfoLegacyIterator
+ * @throws InvalidArgumentException if the filter option is neither an array
+ * nor object, or if filter.name is not a
+ * string.
+ */
+ private function listCollectionsLegacy(Server $server, array $options = array())
+ {
+ $filter = array_key_exists('filter', $options) ? $options['filter'] : array();
+
+ if ( ! is_array($filter) && ! is_object($filter)) {
+ throw new InvalidArgumentException(sprintf('Expected filter to be array or object, %s given', gettype($filter)));
+ }
+
+ if (array_key_exists('name', (array) $filter)) {
+ $filter = (array) $filter;
+
+ if ( ! is_string($filter['name'])) {
+ throw new InvalidArgumentException(sprintf('Filter "name" must be a string for MongoDB <2.8, %s given', gettype($filter['name'])));
+ }
+
+ $filter['name'] = $this->databaseName . '.' . $filter['name'];
+ }
+
+ $namespace = $this->databaseName . '.system.namespaces';
+ $query = new Query($filter);
+ $cursor = $server->executeQuery($namespace, $query);
+
+ return new CollectionInfoLegacyIterator($cursor);
+ }
+}
diff --git a/src/Model/CollectionInfo.php b/src/Model/CollectionInfo.php
new file mode 100644
index 000000000..9617250ad
--- /dev/null
+++ b/src/Model/CollectionInfo.php
@@ -0,0 +1,70 @@
+name = (string) $info['name'];
+ $this->options = isset($info['options']) ? (array) $info['options'] : array();
+ }
+
+ /**
+ * Return the collection name.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Return the collection options.
+ *
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * Return whether the collection is a capped collection.
+ *
+ * @return boolean
+ */
+ public function isCapped()
+ {
+ return isset($this->options['capped']) ? (boolean) $this->options['capped'] : false;
+ }
+
+ /**
+ * Return the maximum number of documents to keep in the capped collection.
+ *
+ * @return integer|null
+ */
+ public function getCappedMax()
+ {
+ return isset($this->options['max']) ? (integer) $this->options['max'] : null;
+ }
+
+ /**
+ * Return the maximum size (in bytes) of the capped collection.
+ *
+ * @return integer|null
+ */
+ public function getCappedSize()
+ {
+ return isset($this->options['size']) ? (integer) $this->options['size'] : null;
+ }
+}
diff --git a/src/Model/CollectionInfoCommandIterator.php b/src/Model/CollectionInfoCommandIterator.php
new file mode 100644
index 000000000..ce0c28737
--- /dev/null
+++ b/src/Model/CollectionInfoCommandIterator.php
@@ -0,0 +1,18 @@
+manager->executeInsert($this->getNamespace(), array('x' => 1));
+ $this->assertEquals(1, $writeResult->getInsertedCount());
+
+ $client = new Client($this->getUri());
+ $commandResult = $client->dropDatabase($this->getDatabaseName());
+ $this->assertCommandSucceeded($commandResult);
+ $this->assertCollectionCount($this->getNamespace(), 0);
+ }
+
+ public function testListDatabases()
+ {
+ $writeResult = $this->manager->executeInsert($this->getNamespace(), array('x' => 1));
+ $this->assertEquals(1, $writeResult->getInsertedCount());
+
+ $client = new Client($this->getUri());
+ $databases = $client->listDatabases();
+
+ $this->assertInstanceOf('Traversable', $databases);
+
+ $foundDatabase = null;
+
+ foreach ($databases as $database) {
+ if ($database['name'] === $this->getDatabaseName()) {
+ $foundDatabase = $database;
+ break;
+ }
+ }
+
+ $this->assertNotNull($foundDatabase, 'Found test database in list of databases');
+ $this->assertFalse($foundDatabase['empty'], 'Test database is not empty');
+ $this->assertGreaterThan(0, $foundDatabase['sizeOnDisk'], 'Test database takes up disk space');
+ }
+}
diff --git a/tests/CollectionFunctionalTest.php b/tests/CollectionFunctionalTest.php
new file mode 100644
index 000000000..4d3bc5d20
--- /dev/null
+++ b/tests/CollectionFunctionalTest.php
@@ -0,0 +1,59 @@
+collection = new Collection($this->manager, $this->getNamespace());
+ $this->collection->deleteMany(array());
+ }
+
+ public function testDrop()
+ {
+ $writeResult = $this->collection->insertOne(array('x' => 1));
+ $this->assertEquals(1, $writeResult->getInsertedCount());
+
+ $commandResult = $this->collection->drop();
+ $this->assertCommandSucceeded($commandResult);
+ $this->assertCollectionCount($this->getNamespace(), 0);
+ }
+
+ function testInsertAndRetrieve()
+ {
+ $generator = new FixtureGenerator();
+
+ for ($i = 0; $i < 10; $i++) {
+ $user = $generator->createUser();
+ $result = $this->collection->insertOne($user);
+ $this->assertInstanceOf('MongoDB\InsertOneResult', $result);
+ $this->assertInstanceOf('BSON\ObjectId', $result->getInsertedId());
+ $this->assertEquals(24, strlen($result->getInsertedId()));
+
+ $user["_id"] = $result->getInsertedId();
+ $document = $this->collection->findOne(array("_id" => $result->getInsertedId()));
+ $this->assertEquals($document, $user, "The inserted and returned objects are the same");
+ }
+
+ $this->assertEquals(10, $i);
+
+ $query = array("firstName" => "Ransom");
+ $count = $this->collection->count($query);
+ $this->assertEquals(1, $count);
+ $cursor = $this->collection->find($query);
+ $this->assertInstanceOf('MongoDB\Driver\Cursor', $cursor);
+
+ foreach($cursor as $n => $person) {
+ $this->assertInternalType("array", $person);
+ }
+ $this->assertEquals(0, $n);
+ }
+}
diff --git a/tests/CollectionTest.php b/tests/CollectionTest.php
index e54ee92bb..5d9964407 100644
--- a/tests/CollectionTest.php
+++ b/tests/CollectionTest.php
@@ -1,50 +1,12 @@
faker = Faker\Factory::create();
- $this->faker->seed(1234);
-
- $this->manager = new Manager("mongodb://localhost");
- $this->collection = new Collection($this->manager, "test.case");
- $this->collection->deleteMany(array());
- }
-
- function testInsertAndRetrieve() {
- $collection = $this->collection;
-
- for($i=0; $i<10;$i++) {
- $user = createUser($this->faker);
- $result = $collection->insertOne($user);
- $this->assertInstanceOf('MongoDB\InsertOneResult', $result);
- $this->assertInstanceOf('BSON\ObjectId', $result->getInsertedId());
- $this->assertEquals(24, strlen($result->getInsertedId()));
-
- $user["_id"] = $result->getInsertedId();
- $document = $collection->findOne(array("_id" => $result->getInsertedId()));
- $this->assertEquals($document, $user, "The inserted and returned objects are the same");
- }
-
- $this->assertEquals(10, $i);
-
-
- $query = array("firstName" => "Ransom");
- $count = $collection->count($query);
- $this->assertEquals(1, $count);
- $cursor = $collection->find($query);
- $this->assertInstanceOf('MongoDB\Driver\Result', $cursor);
-
- foreach($cursor as $n => $person) {
- $this->assertInternalType("array", $person);
- }
- $this->assertEquals(0, $n);
- }
+use ReflectionClass;
+use ReflectionMethod;
+class CollectionTest extends TestCase
+{
public function testMethodOrder()
{
$class = new ReflectionClass('MongoDB\Collection');
@@ -68,4 +30,3 @@ function(ReflectionMethod $method) { return $method->getName(); },
}
}
}
-
diff --git a/tests/DatabaseFunctionalTest.php b/tests/DatabaseFunctionalTest.php
new file mode 100644
index 000000000..b49ccf6dc
--- /dev/null
+++ b/tests/DatabaseFunctionalTest.php
@@ -0,0 +1,136 @@
+database = new Database($this->manager, $this->getDatabaseName());
+ $this->database->drop();
+ }
+
+ public function testCreateCollection()
+ {
+ $that = $this;
+ $basicCollectionName = $this->getCollectionName() . '.basic';
+
+ $commandResult = $this->database->createCollection($basicCollectionName);
+ $this->assertCommandSucceeded($commandResult);
+ $this->assertCollectionExists($basicCollectionName, function(CollectionInfo $info) use ($that) {
+ $that->assertFalse($info->isCapped());
+ });
+
+ $cappedCollectionName = $this->getCollectionName() . '.capped';
+ $cappedCollectionOptions = array(
+ 'capped' => true,
+ 'max' => 100,
+ 'size' => 1048576,
+ );
+
+ $commandResult = $this->database->createCollection($cappedCollectionName, $cappedCollectionOptions);
+ $this->assertCommandSucceeded($commandResult);
+ $this->assertCollectionExists($cappedCollectionName, function(CollectionInfo $info) use ($that) {
+ $that->assertTrue($info->isCapped());
+ $that->assertEquals(100, $info->getCappedMax());
+ $that->assertEquals(1048576, $info->getCappedSize());
+ });
+ }
+
+ public function testDrop()
+ {
+ $writeResult = $this->manager->executeInsert($this->getNamespace(), array('x' => 1));
+ $this->assertEquals(1, $writeResult->getInsertedCount());
+
+ $commandResult = $this->database->drop();
+ $this->assertCommandSucceeded($commandResult);
+ $this->assertCollectionCount($this->getNamespace(), 0);
+ }
+
+ public function testDropCollection()
+ {
+ $writeResult = $this->manager->executeInsert($this->getNamespace(), array('x' => 1));
+ $this->assertEquals(1, $writeResult->getInsertedCount());
+
+ $commandResult = $this->database->dropCollection($this->getCollectionName());
+ $this->assertCommandSucceeded($commandResult);
+ $this->assertCollectionCount($this->getNamespace(), 0);
+ }
+
+ public function testListCollections()
+ {
+ $commandResult = $this->database->createCollection($this->getCollectionName());
+ $this->assertCommandSucceeded($commandResult);
+
+ $collections = $this->database->listCollections();
+ $this->assertInstanceOf('MongoDB\Model\CollectionInfoIterator', $collections);
+
+ foreach ($collections as $collection) {
+ $this->assertInstanceOf('MongoDB\Model\CollectionInfo', $collection);
+ }
+ }
+
+ public function testListCollectionsWithFilter()
+ {
+ $commandResult = $this->database->createCollection($this->getCollectionName());
+ $this->assertCommandSucceeded($commandResult);
+
+ $collectionName = $this->getCollectionName();
+ $options = array('filter' => array('name' => $collectionName));
+
+ $collections = $this->database->listCollections($options);
+ $this->assertInstanceOf('MongoDB\Model\CollectionInfoIterator', $collections);
+ $this->assertCount(1, $collections);
+
+ foreach ($collections as $collection) {
+ $this->assertInstanceOf('MongoDB\Model\CollectionInfo', $collection);
+ $this->assertEquals($collectionName, $collection->getName());
+ }
+ }
+
+ /**
+ * Asserts that a collection with the given name exists in the database.
+ *
+ * An optional $callback may be provided, which should take a CollectionInfo
+ * argument as its first and only parameter. If a CollectionInfo matching
+ * the given name is found, it will be passed to the callback, which may
+ * perform additional assertions.
+ *
+ * @param callable $callback
+ */
+ private function assertCollectionExists($collectionName, $callback = null)
+ {
+ if ($callback !== null && ! is_callable($callback)) {
+ throw new InvalidArgumentException('$callback is not a callable');
+ }
+
+ $collections = $this->database->listCollections();
+
+ $foundCollection = null;
+
+ foreach ($collections as $collection) {
+ if ($collection->getName() === $collectionName) {
+ $foundCollection = $collection;
+ break;
+ }
+ }
+
+ $this->assertNotNull($foundCollection, sprintf('Found %s collection in the database', $collectionName));
+
+ if ($callback !== null) {
+ call_user_func($callback, $foundCollection);
+ }
+ }
+}
diff --git a/tests/FixtureGenerator.php b/tests/FixtureGenerator.php
new file mode 100644
index 000000000..986dffaa5
--- /dev/null
+++ b/tests/FixtureGenerator.php
@@ -0,0 +1,59 @@
+faker = Factory::create();
+ $this->faker->seed(1234);
+ }
+
+ public function createUser()
+ {
+ return array(
+ "username" => $this->faker->unique()->userName,
+ "password" => $this->faker->sha256,
+ "email" => $this->faker->unique()->safeEmail,
+ "firstName" => $this->faker->firstName,
+ "lastName" => $this->faker->lastName,
+ "phoneNumber" => $this->faker->phoneNumber,
+ "altPhoneNumber" => $this->faker->optional(0.1)->phoneNumber,
+ "company" => $this->faker->company,
+ "bio" => $this->faker->paragraph,
+ "createdAt" => $this->faker->dateTimeBetween("2008-01-01T00:00:00+0000", "2014-08-01T00:00:00+0000")->getTimestamp(),
+ "addresses" => array(
+ $this->createAddress(),
+ $this->createAddress(),
+ $this->createAddress(),
+ ),
+ );
+ }
+
+ public function createAddress()
+ {
+ return (object) array(
+ "streetAddress" => $this->faker->streetAddress,
+ "city" => $this->faker->city,
+ "state" => $this->faker->state,
+ "postalCode" => $this->faker->postcode,
+ "loc" => $this->createGeoJsonPoint(),
+ );
+ }
+
+ public function createGeoJsonPoint()
+ {
+ return (object) array(
+ "type" => "Point",
+ "coordinates" => (object) array(
+ $this->faker->longitude,
+ $this->faker->latitude
+ ),
+ );
+ }
+}
diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php
new file mode 100644
index 000000000..e64090f65
--- /dev/null
+++ b/tests/FunctionalTestCase.php
@@ -0,0 +1,35 @@
+manager = new Manager($this->getUri());
+ }
+
+ public function assertCollectionCount($namespace, $count)
+ {
+ list($databaseName, $collectionName) = explode('.', $namespace, 2);
+
+ $cursor = $this->manager->executeCommand($databaseName, new Command(array('count' => $collectionName)));
+
+ $document = current($cursor->toArray());
+ $this->assertArrayHasKey('n', $document);
+ $this->assertEquals($count, $document['n']);
+ }
+
+ public function assertCommandSucceeded(Cursor $cursor)
+ {
+ $document = current($cursor->toArray());
+ $this->assertArrayHasKey('ok', $document);
+ $this->assertEquals(1, $document['ok']);
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 000000000..365405d17
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,50 @@
+getShortName(), $this->getName(false));
+ }
+
+ /**
+ * Return the test database name.
+ *
+ * @return string
+ */
+ public function getDatabaseName()
+ {
+ return getenv('MONGODB_DATABASE') ?: 'phplib_test';
+ }
+
+ /**
+ * Return the test namespace.
+ *
+ * @return string
+ */
+ public function getNamespace()
+ {
+ return sprintf('%s.%s', $this->getDatabaseName(), $this->getCollectionName());
+ }
+
+ /**
+ * Return the connection URI.
+ *
+ * @return string
+ */
+ public function getUri()
+ {
+ return getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1:27017';
+ }
+}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 000000000..464fc5839
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,13 @@
+addPsr4('MongoDB\\Tests\\', __DIR__);
diff --git a/tests/utils.inc b/tests/utils.inc
deleted file mode 100644
index b07b872b4..000000000
--- a/tests/utils.inc
+++ /dev/null
@@ -1,44 +0,0 @@
- $faker->unique()->userName,
- "password" => $faker->sha256,
- "email" => $faker->unique()->safeEmail,
- "firstName" => $faker->firstName,
- "lastName" => $faker->lastName,
- "phoneNumber" => $faker->phoneNumber,
- "altPhoneNumber" => $faker->optional(0.1)->phoneNumber,
- "company" => $faker->company,
- "bio" => $faker->paragraph,
- "createdAt" => $faker->dateTimeBetween("2008-01-01T00:00:00+0000", "2014-08-01T00:00:00+0000")->getTimestamp(),
- "addresses" => (object)array(
- createAddress($faker),
- createAddress($faker),
- createAddress($faker),
- ),
- );
-}
-
-function createAddress($faker)
-{
- return (object)array(
- "streetAddress" => $faker->streetAddress,
- "city" => $faker->city,
- "state" => $faker->state,
- "postalCode" => $faker->postcode,
- "loc" => createGeoJsonPoint($faker),
- );
-}
-
-function createGeoJsonPoint($faker)
-{
- return (object)array(
- "type" => "Point",
- "coordinates" => (object)array($faker->longitude, $faker->latitude),
- );
-}
-
-