Commit 71464555 authored by Jeremy Mikola's avatar Jeremy Mikola

Merge pull request #6

parents 86dab095 192d950b
...@@ -7,11 +7,12 @@ php: ...@@ -7,11 +7,12 @@ php:
- 5.6 - 5.6
env: env:
- MONGODB_VERSION=0.2.0 - MONGODB_VERSION=alpha
services: mongodb services: mongodb
before_script: 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 - php --ri mongodb
- composer install --dev --no-interaction --prefer-source - composer install --dev --no-interaction --prefer-source
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
{ "name": "Derick Rethans", "email": "github@derickrethans.nl" } { "name": "Derick Rethans", "email": "github@derickrethans.nl" }
], ],
"require": { "require": {
"ext-mongodb": "^0.2" "ext-mongodb": "*"
}, },
"require-dev": { "require-dev": {
"fzaninotto/faker": "~1.0" "fzaninotto/faker": "~1.0"
......
...@@ -11,11 +11,13 @@ ...@@ -11,11 +11,13 @@
convertWarningsToExceptions="true" convertWarningsToExceptions="true"
stopOnFailure="false" stopOnFailure="false"
syntaxCheck="false" syntaxCheck="false"
bootstrap="vendor/autoload.php" bootstrap="tests/bootstrap.php"
> >
<php> <php>
<ini name="error_reporting" value="-1"/> <ini name="error_reporting" value="-1"/>
<env name="MONGODB_URI" value="mongodb://127.0.0.1:27017"/>
<env name="MONGODB_DATABASE" value="phplib_test"/>
</php> </php>
<testsuites> <testsuites>
......
...@@ -2,30 +2,34 @@ ...@@ -2,30 +2,34 @@
namespace MongoDB; namespace MongoDB;
use MongoDB\Collection; use MongoDB\Driver\Command;
use MongoDB\Database; use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager; use MongoDB\Driver\Manager;
use MongoDB\Driver\Result; use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\WriteConcern;
use ArrayIterator;
use stdClass;
use UnexpectedValueException;
class Client class Client
{ {
private $manager; private $manager;
private $wc; private $readPreference;
private $rp; private $writeConcern;
/** /**
* Constructs new Client instance * Constructs a new Client instance.
* *
* This is the suggested main entry point using phongo. * This is the preferred class for connecting to a MongoDB server or
* It acts as a bridge to access individual databases and collection tools * cluster of servers. It serves as a gateway for accessing individual
* which are provided in this namespace. * databases and collections.
* *
* @param Manager $uri The MongoDB URI to connect to * @see http://docs.mongodb.org/manual/reference/connection-string/
* @param WriteConcern $options URI Options * @param string $uri MongoDB connection string
* @param ReadPreference $driverOptions Driver specific options * @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); $this->manager = new Manager($uri, $options, $driverOptions);
} }
...@@ -33,42 +37,90 @@ class Client ...@@ -33,42 +37,90 @@ class Client
/** /**
* Drop a database. * Drop a database.
* *
* @see http://docs.mongodb.org/manual/reference/command/dropDatabase/
* @param string $databaseName * @param string $databaseName
* @return Result * @return Cursor
*/ */
public function dropDatabase($databaseName) 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 * @see http://docs.mongodb.org/manual/reference/command/listDatabases/
* * @return Traversable
* @param string $databaseName The database to select * @throws UnexpectedValueException if the command result is malformed
* @param WriteConcern $writeConcern Default Write Concern to apply
* @param ReadPreference $readPreferences Default Read Preferences to apply
*/ */
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 $databaseName Name of the database to select
* @param string $collectionName The collection to select * @param WriteConcern $writeConcern Default write concern to apply
* @param WriteConcern $writeConcern Default Write Concern to apply * @param ReadPreference $readPreference Default read preference to apply
* @param ReadPreference $readPreferences Default Read Preferences 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);
}
}
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
namespace MongoDB; namespace MongoDB;
use MongoDB\Driver\Command; use MongoDB\Driver\Command;
use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager; use MongoDB\Driver\Manager;
use MongoDB\Driver\Query; use MongoDB\Driver\Query;
use MongoDB\Driver\ReadPreference; use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\Result;
use MongoDB\Driver\BulkWrite; use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\WriteConcern; use MongoDB\Driver\WriteConcern;
...@@ -43,25 +43,24 @@ class Collection ...@@ -43,25 +43,24 @@ class Collection
/** /**
* Constructs new Collection instance * Constructs new Collection instance.
* *
* This is the suggested CRUD interface when using phongo. * This class provides methods for collection-specific operations, such as
* It implements the MongoDB CRUD specification which is an interface all MongoDB * CRUD (i.e. create, read, update, and delete) and index management.
* supported drivers follow.
* *
* @param Manager $manager The phongo Manager instance * @param Manager $manager Manager instance from the driver
* @param string $ns Fully Qualified Namespace (dbname.collname) * @param string $namespace Collection namespace (e.g. "db.collection")
* @param WriteConcern $wc The WriteConcern to apply to writes * @param WriteConcern $writeConcern Default write concern to apply
* @param ReadPreference $rp The ReadPreferences to apply to reads * @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->manager = $manager;
$this->ns = $ns; $this->ns = (string) $namespace;
$this->wc = $wc; $this->wc = $writeConcern;
$this->rp = $rp; $this->rp = $readPreference;
list($this->dbname, $this->collname) = explode(".", $ns, 2); list($this->dbname, $this->collname) = explode(".", $namespace, 2);
} }
/** /**
...@@ -87,14 +86,16 @@ class Collection ...@@ -87,14 +86,16 @@ class Collection
"pipeline" => $pipeline, "pipeline" => $pipeline,
) + $options; ) + $options;
$result = $this->_runCommand($this->dbname, $cmd); $cursor = $this->_runCommand($this->dbname, $cmd);
$doc = $result->toArray();
if (isset($cmd["cursor"]) && $cmd["cursor"]) { if (isset($cmd["cursor"]) && $cmd["cursor"]) {
return $result; return $cursor;
} else { }
if ($doc["ok"]) {
return new \ArrayIterator($doc["result"]); $doc = current($cursor->toArray());
}
if ($doc["ok"]) {
return new \ArrayIterator($doc["result"]);
} }
throw $this->_generateCommandException($doc); throw $this->_generateCommandException($doc);
...@@ -235,7 +236,7 @@ class Collection ...@@ -235,7 +236,7 @@ class Collection
"query" => $filter, "query" => $filter,
) + $options; ) + $options;
$doc = $this->_runCommand($this->dbname, $cmd)->toArray(); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return $doc["n"]; return $doc["n"];
} }
...@@ -325,7 +326,7 @@ class Collection ...@@ -325,7 +326,7 @@ class Collection
"query" => $filter, "query" => $filter,
) + $options; ) + $options;
$doc = $this->_runCommand($this->dbname, $cmd)->toArray(); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return $doc["values"]; return $doc["values"];
} }
...@@ -335,11 +336,15 @@ class Collection ...@@ -335,11 +336,15 @@ class Collection
/** /**
* Drop this collection. * Drop this collection.
* *
* @return Result * @see http://docs.mongodb.org/manual/reference/command/drop/
* @return Cursor
*/ */
public function drop() 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 @@ class Collection ...@@ -348,7 +353,7 @@ class Collection
* @see http://docs.mongodb.org/manual/reference/command/dropIndexes/ * @see http://docs.mongodb.org/manual/reference/command/dropIndexes/
* @see http://docs.mongodb.org/manual/reference/method/db.collection.dropIndex/ * @see http://docs.mongodb.org/manual/reference/method/db.collection.dropIndex/
* @param string $indexName * @param string $indexName
* @return Result * @return Cursor
* @throws InvalidArgumentException if "*" is specified * @throws InvalidArgumentException if "*" is specified
*/ */
public function dropIndex($indexName) public function dropIndex($indexName)
...@@ -361,7 +366,7 @@ class Collection ...@@ -361,7 +366,7 @@ class Collection
* *
* @see http://docs.mongodb.org/manual/reference/command/dropIndexes/ * @see http://docs.mongodb.org/manual/reference/command/dropIndexes/
* @see http://docs.mongodb.org/manual/reference/method/db.collection.dropIndexes/ * @see http://docs.mongodb.org/manual/reference/method/db.collection.dropIndexes/
* @return Result * @return Cursor
*/ */
public function dropIndexes() public function dropIndexes()
{ {
...@@ -376,7 +381,7 @@ class Collection ...@@ -376,7 +381,7 @@ class Collection
* *
* @param array $filter The find query to execute * @param array $filter The find query to execute
* @param array $options Additional options * @param array $options Additional options
* @return Result * @return Cursor
*/ */
public function find(array $filter = array(), array $options = array()) public function find(array $filter = array(), array $options = array())
{ {
...@@ -434,7 +439,7 @@ class Collection ...@@ -434,7 +439,7 @@ class Collection
"query" => $filter, "query" => $filter,
) + $options; ) + $options;
$doc = $this->_runCommand($this->dbname, $cmd)->toArray(); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return $doc["value"]; return $doc["value"];
} }
...@@ -471,7 +476,7 @@ class Collection ...@@ -471,7 +476,7 @@ class Collection
"query" => $filter, "query" => $filter,
) + $options; ) + $options;
$doc = $this->_runCommand($this->dbname, $cmd)->toArray(); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return $doc["value"]; return $doc["value"];
} }
...@@ -509,7 +514,7 @@ class Collection ...@@ -509,7 +514,7 @@ class Collection
"query" => $filter, "query" => $filter,
) + $options; ) + $options;
$doc = $this->_runCommand($this->dbname, $cmd)->toArray(); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return $doc["value"]; return $doc["value"];
} }
...@@ -948,7 +953,7 @@ class Collection ...@@ -948,7 +953,7 @@ class Collection
* *
* @see http://docs.mongodb.org/manual/reference/command/listIndexes/ * @see http://docs.mongodb.org/manual/reference/command/listIndexes/
* @see http://docs.mongodb.org/manual/reference/method/db.collection.getIndexes/ * @see http://docs.mongodb.org/manual/reference/method/db.collection.getIndexes/
* @return Result * @return Cursor
*/ */
public function listIndexes() public function listIndexes()
{ {
......
...@@ -3,34 +3,42 @@ ...@@ -3,34 +3,42 @@
namespace MongoDB; namespace MongoDB;
use MongoDB\Collection; use MongoDB\Collection;
use MongoDB\Driver\Command;
use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager; 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 class Database
{ {
private $databaseName;
private $manager; private $manager;
private $ns; private $readPreference;
private $wc; private $writeConcern;
private $rp;
private $dbname;
/** /**
* 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 Manager $manager Manager instance from the driver
* @param string $dbname Fully Qualified database name * @param string $databaseName Database name
* @param WriteConcern $wc The WriteConcern to apply to writes * @param WriteConcern $writeConcern Default write concern to apply
* @param ReadPreference $rp The ReadPreferences to apply to reads * @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->manager = $manager;
$this->dbname = $dbname; $this->databaseName = (string) $databaseName;
$this->wc = $wc; $this->writeConcern = $writeConcern;
$this->rp = $rp; $this->readPreference = $readPreference;
} }
/** /**
...@@ -40,32 +48,45 @@ class Database ...@@ -40,32 +48,45 @@ class Database
* @see http://docs.mongodb.org/manual/reference/method/db.createCollection/ * @see http://docs.mongodb.org/manual/reference/method/db.createCollection/
* @param string $collectionName * @param string $collectionName
* @param array $options * @param array $options
* @return Result * @return Cursor
*/ */
public function createCollection($collectionName, array $options = array()) 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. * Drop this database.
* *
* @return Result * @see http://docs.mongodb.org/manual/reference/command/dropDatabase/
* @return Cursor
*/ */
public function drop() 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. * Drop a collection within this database.
* *
* @see http://docs.mongodb.org/manual/reference/command/drop/
* @param string $collectionName * @param string $collectionName
* @return Result * @return Cursor
*/ */
public function dropCollection($collectionName) 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 @@ class Database ...@@ -73,27 +94,90 @@ class Database
* *
* @see http://docs.mongodb.org/manual/reference/command/listCollections/ * @see http://docs.mongodb.org/manual/reference/command/listCollections/
* @param array $options * @param array $options
* @return Result * @return CollectionInfoIterator
*/ */
public function listCollections(array $options = array()) 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 string $collectionName Name of the collection to select
* @param WriteConcern $writeConcern Default Write Concern to apply * @param WriteConcern $writeConcern Default write concern to apply
* @param ReadPreference $readPreferences Default Read Preferences 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);
}
}
<?php
namespace MongoDB\Model;
class CollectionInfo
{
private $name;
private $options;
/**
* Constructor.
*
* @param array $info Collection info
*/
public function __construct(array $info)
{
$this->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;
}
}
<?php
namespace MongoDB\Model;
use IteratorIterator;
class CollectionInfoCommandIterator extends IteratorIterator implements CollectionInfoIterator
{
/**
* Return the current element as a CollectionInfo instance.
*
* @return CollectionInfo
*/
public function current()
{
return new CollectionInfo(parent::current());
}
}
<?php
namespace MongoDB\Model;
use Iterator;
interface CollectionInfoIterator extends Iterator
{
/**
* Return the current element as a CollectionInfo instance.
*
* @return CollectionInfo
*/
public function current();
}
<?php
namespace MongoDB\Model;
use FilterIterator;
use Iterator;
use IteratorIterator;
use Traversable;
class CollectionInfoLegacyIterator extends FilterIterator implements CollectionInfoIterator
{
/**
* Constructor.
*
* @param Traversable $iterator
*/
public function __construct(Traversable $iterator)
{
/* FilterIterator requires an Iterator, so wrap all other Traversables
* with an IteratorIterator as a convenience.
*/
if ( ! $iterator instanceof Iterator) {
$iterator = new IteratorIterator($iterator);
}
parent::__construct($iterator);
}
/**
* Return the current element as a CollectionInfo instance.
*
* @return CollectionInfo
*/
public function current()
{
$info = parent::current();
// Trim the database prefix up to and including the first dot
$firstDot = strpos($info['name'], '.');
if ($firstDot !== false) {
$info['name'] = (string) substr($info['name'], $firstDot + 1);
}
return new CollectionInfo($info);
}
/**
* Filter out internal or invalid collections.
*
* @see http://php.net/manual/en/filteriterator.accept.php
* @return boolean
*/
public function accept()
{
$info = parent::current();
if ( ! isset($info['name']) || ! is_string($info['name'])) {
return false;
}
// Reject names with "$" characters (e.g. indexes, oplog)
if (strpos($info['name'], '$') !== false) {
return false;
}
$firstDot = strpos($info['name'], '.');
/* Legacy collection names are a namespace and should be prefixed with
* the database name and a dot. Reject values that omit this prefix or
* are empty beyond it.
*/
if ($firstDot === false || $firstDot + 1 == strlen($info['name'])) {
return false;
}
return true;
}
}
<?php
namespace MongoDB\Tests;
use MongoDB\Client;
/**
* Functional tests for the Client class.
*/
class ClientFunctionalTest extends FunctionalTestCase
{
public function testDropDatabase()
{
$writeResult = $this->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');
}
}
<?php
namespace MongoDB\Tests;
use MongoDB\Collection;
use MongoDB\Driver\Manager;
class CollectionFunctionalTest extends FunctionalTestCase
{
private $collection;
public function setUp()
{
parent::setUp();
$this->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);
}
}
<?php <?php
use MongoDB\Collection; namespace MongoDB\Tests;
use MongoDB\Driver\Manager;
class CollectionTest extends PHPUnit_Framework_TestCase { use ReflectionClass;
use ReflectionMethod;
function setUp() {
require_once __DIR__ . "/" . "utils.inc";
$this->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);
}
class CollectionTest extends TestCase
{
public function testMethodOrder() public function testMethodOrder()
{ {
$class = new ReflectionClass('MongoDB\Collection'); $class = new ReflectionClass('MongoDB\Collection');
...@@ -68,4 +30,3 @@ class CollectionTest extends PHPUnit_Framework_TestCase { ...@@ -68,4 +30,3 @@ class CollectionTest extends PHPUnit_Framework_TestCase {
} }
} }
} }
<?php
namespace MongoDB\Tests;
use MongoDB\Client;
use MongoDB\Database;
use MongoDB\Model\CollectionInfo;
use InvalidArgumentException;
/**
* Functional tests for the Database class.
*/
class DatabaseFunctionalTest extends FunctionalTestCase
{
private $database;
public function setUp()
{
parent::setUp();
$this->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);
}
}
}
<?php
namespace MongoDB\Tests;
use Faker\Factory;
class FixtureGenerator
{
private $faker;
public function __construct()
{
$this->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
),
);
}
}
<?php
namespace MongoDB\Tests;
use MongoDB\Driver\Command;
use MongoDB\Driver\Manager;
use MongoDB\Driver\Cursor;
abstract class FunctionalTestCase extends TestCase
{
protected $manager;
public function setUp()
{
$this->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']);
}
}
<?php
namespace MongoDB\Tests;
use ReflectionClass;
abstract class TestCase extends \PHPUnit_Framework_TestCase
{
/**
* Return the test collection name.
*
* @return string
*/
public function getCollectionName()
{
$class = new ReflectionClass($this);
return sprintf('%s.%s', $class->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';
}
}
<?php
if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
// Dependencies were installed with Composer and this is the main project
$loader = require_once __DIR__ . '/../vendor/autoload.php';
} elseif (file_exists(__DIR__ . '/../../../../autoload.php')) {
// We're installed as a dependency in another project's `vendor` directory
$loader = require_once __DIR__ . '/../../../../autoload.php';
} else {
throw new Exception('Can\'t find autoload.php. Did you install dependencies with Composer?');
}
$loader->addPsr4('MongoDB\\Tests\\', __DIR__);
<?php
require_once __DIR__ . "/" . "../vendor/autoload.php";
function createUser($faker)
{
return array(
"username" => $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),
);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment